LINUX.ORG.RU

взаимодействие с ldap-сервером

 , , ,


0

1

здравствуйте, получаю в http-ответе kerberos-зашифрованный токен... нужно по этому токену получить определенную информацию для веб-сервера от ldap-сервера(в моем случае active directory). далее чтобы, например, ldap-сервер прислал полномочия клиента приславшего этот токен, что нужно делать? не шарю в этом, подскажите хотя бы с чего начать... я так понимаю надо юзать GSSAPI, расшифровать токен хотя бы. Используемый язык c++ или си, платформа linux x86_64

★★

Последнее исправление: xperious (всего исправлений: 2)

чтобы, например, ldap-сервер прислал полномочия клиента приславшего этот токен

кстати, это авторизацией кличут.

я формально не профи этого дела, но что-то не очень понятно, что куда у тебя ходит.

в общем, если тебе нужно чтобы ДЕМОН аутентифицировался по керберосу, и керберос-билетом авторизовался в каталоге, то для этого придуманы service tickets, они без пароля само собой, обычно лежат (лучше в отдельном кейтабе, специально для каждого демона. например apache.keytab, postfix.keytab и т.д.) где-то в доступном для демона месте и читаемы только юзером под которым демон робит. Он этим билетом и пользуется.

если надо чтобы какая-то пользовательская программа брала что-то из лдапа, то юзер при логине в ОС получает TGT (ticket granting ticket) а прога с ним уже аутентифицируется в керберосе и получает билет для той услуги, для которой надо (и которая сконфигурирована в керберосе).
прога соотв. должна уметь говорить с керберосом (и с лдапом). есть вроде sasld или напрямую по GSSAPI.

И в тэгах openldap а в сетапе его что-то не видно.

disclaimer: я 100% что-то коряво (читай не верно) описал, всё по памяти. но тебя должно толкнуть в нужном направлении. и еще всё это про *nix. С АД наверняка будут свои заморочки, но в целом схема работы аналогичная.

mos ★★☆☆☆
()

получаю в http-ответе kerberos-зашифрованный токен... нужно по этому токену получить определенную информацию для веб-сервера от ldap-сервера

Ты втираешь нам какую-то дичь.

Ты получаешь в http-запросе к веб-серверу на крестах мандат(сеансовый билет) кербероса для этого сервиса? После этого ты хочешь подключиться к AD (ldap'у) от имени пользователя, который прислал мандат?

Если всё так, то это возможно. Для этого в браузере должно быть разрешено делегирование к этому сервису.

Хром-винда:

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\SOFTWARE\Policies\Google\Chrome]
"AuthNegotiateDelegateWhitelist"="https://websrv.domain.local"

Хромиум-линукс:

cat << EOF > /etc/chromium/policies/recommended/negotiate.json
{
        "AuthServerWhitelist":                          "websrv.domain.local",
        "AuthNegotiateDelegateWhitelist":       "websrv.domain.local"
}
EOF

Firefox: about:config -> filter negotiate -> Добавить имя сервера в поля network.negotiate-auth.trusted-uris и network.negotiate-auth.delegation-uris

После этого браузер будет отсылать мандаты с делегацией. И твой веб-сервер сможет подключаться под ним к AD.

Как это делать на крестах, не знаю. Делал на питоне с использованием gssapi примерно так:

        header = request.headers.get("Authorization", "")
        if header.startswith('Negotiate '):
            global _srvCred, _log
            token = b64decode(header[10:])

            # Init server.
            srvCtx  = gssapi.SecurityContext(creds = _srvCred, usage = 'accept')
            try:
                srvToken = srvCtx.step(token)
            except Exception as ex:
                return _forbidden()

            if srvCtx.complete:
                clientCredsToken = None
                if srvCtx.delegated_creds:
                    clientCredsToken = srvCtx.delegated_creds.export()
                response = function(srvCtx.initiator_name, clientCredsToken, *args, **kwargs)
                response = make_response(response)
            else:
                response = _unauthorised()
            if srvToken:
                response.headers['WWW-Authenticate'] = 'Negotiate ' + b64encode(srvToken).decode("utf-8")
            return response

Соответственно в function подключаешься к ldap'у с использованием kerberos'а и clientCredsToken.

gssapi - это всего-лишь обёртка над gssapi c bindings, так что можешь изучать их. Ну и как это прикрутить к ldap c sdk.

Ivan_qrt ★★★★★
()
Ответ на: комментарий от Ivan_qrt

да я все с тем же... https://www.linux.org.ru/forum/admin/13597093 наконец-то стал приходить ответ с Autorization: Negotiate с токеном начинающимся на YII...

Ты втираешь нам какую-то дичь.

да вроде ж все правильно описал: приходит зашифрованный этот самый сеансовый билет, далее мы идем в ldap с этим билетом и по нему определяем, например, имя пользователя... это реально? просто наткнулся на чудовищно маленькое количество инфы в гуглах по этому вопросу

xperious ★★
() автор топика
Последнее исправление: xperious (всего исправлений: 1)
Ответ на: комментарий от mos

лучше в отдельном кейтабе, специально для каждого демона. например apache.keytab

хм, т.е. для апача в каком-то особенном каталоге нужно делать файл .keytab или пофиг? вот, может поможете по теме еще:https://www.linux.org.ru/forum/general/13616436 я может диковато описал, но вроде понятно

xperious ★★
() автор топика
Ответ на: комментарий от xperious

далее мы идем в ldap с этим билетом и по нему определяем, например, имя пользователя... это реально?

По билету реально определить userPrincipalName. Он указан в самом билете и станет известен при проверке этого самого билета. Ты же ведь проверяешь пришедший тебе билет? Или твоему сервису можно любую фигню прислать, лишь бы была?

Имея userPrincipalName можно подключаться к AD под любым, заранее известным, пользователем. Для выяснения имени ему достаточно прав только на чтение и поиск. Наверняка у вас есть какой-либо ldapuser специально для этого.

Вот под этим пользователем устанавливаешь соединение и ищешь по userPrincipalName.

Подключаться к AD по gssapi с использованием полученного билета тебе нафиг не надо. Это имеет смысл только если тебе нужны привилегии подключающегося пользователя. Например, если ты хочешь заманить на свой сайт domain admin'а и удалить всех пользователей, а тебе права domain admin'а не дают.

Ivan_qrt ★★★★★
()
Последнее исправление: Ivan_qrt (всего исправлений: 1)
Ответ на: комментарий от Ivan_qrt

Он указан в самом билете и станет известен при проверке этого самого билета. Ты же ведь проверяешь пришедший тебе билет? Или твоему сервису можно любую фигню прислать, лишь бы была?

да я честно говоря пока ничего еще не проверяю... я думал проверка как раз и состоит каким-то образом при посылки этого ключа на ldap-сервер... для проверки то пишется код? или как то автоматом

xperious ★★
() автор топика
Ответ на: комментарий от xperious

Код на питоне, который проверяет корректность пришедшего билета приведён выше.

За основу взят flask_kerberos и переведён на gssapi, чтобы умел работать с делегатами. Полный код: http://pastecode.ru/7eb5dc/

Как это сделать на php или крестах не приведу пример. Но думаю в гугле этого всего много. Если используется фреймворк, то скорее всего для него есть соответствующий плагин. Если нет, то тебе нужна обёртка для php на gssapi и делать при запросе примерно тоже.

Так же можно поручить это дело веб-серверу. Я так не пробовал, но гугл говорит про mod_auth_kerb для апача: http://va0816.blogspot.ru/2014/11/ldap-kerberos-apache-php.html

Короче вариантов море, в гугле всё рассказано.

Ivan_qrt ★★★★★
()
Ответ на: комментарий от Ivan_qrt

хм, а если мне апач вернул уже upn-имя( в виде логин@домен), то как тут дело меняется? мы можем больше инфы узнать при запросе в active directory?

и, если не затруднит, скиньте пожалуйста ссылки по которым вы разбирались, а то вообще тухляндия

xperious ★★
() автор топика
Ответ на: комментарий от xperious

хм, а если мне апач вернул уже upn-имя( в виде логин@домен), то как тут дело меняется? мы можем больше инфы узнать при запросе в active directory?

Имея userPrincipalName можно подключаться к AD под любым, заранее известным, пользователем. Для выяснения имени ему достаточно прав только на чтение и поиск. Наверняка у вас есть какой-либо ldapuser специально для этого.

Вот под этим пользователем устанавливаешь соединение и ищешь по userPrincipalName.

Подключаться к AD по gssapi с использованием полученного билета тебе нафиг не надо. Это имеет смысл только если тебе нужны привилегии подключающегося пользователя. Например, если ты хочешь заманить на свой сайт domain admin'а и удалить всех пользователей, а тебе права domain admin'а не дают.

Подключаешься к AD под любой известной учёткой, и делаешь ldpasearch по userPrincipalName=upn. Что тут может быть непонятного-то?

и, если не затруднит, скиньте пожалуйста ссылки по которым вы разбирались, а то вообще тухляндия

Да нет у меня каких-то осбых ссылок. Да и шибко качественного материала по теме я не встречал. Нашлось только это:

http://www.itadmintools.com/2011/07/creating-kerberos-keytab-files.html https://dimanb.wordpress.com/2012/10/20/kerberos-02/

Ivan_qrt ★★★★★
()
Ответ на: комментарий от Ivan_qrt

Подключаешься к AD под любой известной учёткой, и делаешь ldpasearch по userPrincipalName=upn. Что тут может быть непонятного-то?

Да нет у меня каких-то осбых ссылок. Да и шибко качественного материала по теме я не встречал. Нашлось только это:

спасибо, но я имел ввиду программно чтоб запросы делать, в настройках то я разобрался, все пашет

xperious ★★
() автор топика
Ответ на: комментарий от xperious

Проверять сессионный ключ надо на KDC, а не в LDAP-каталоге. Да, в AD на одном сервере и KDC, и каталог. Но протоколы они используют разные.

Короче, аутентификация идет на KDC по протоколу Kerberos. После успешной аутентификации можно поискать параметры авторизации в LDAP-каталоге.

iliyap ★★★★★
()
Ответ на: комментарий от xperious

спасибо, но я имел ввиду программно чтоб запросы делать

А как ещё можно запросы к лдапу делать? Руками asn.1 записывать?

Ты сформулируй внятно, чего именно ты хочешь. Лучше конкретику, и употребляя названия вещей правильно.

Ivan_qrt ★★★★★
()
Ответ на: комментарий от Ivan_qrt

да как-то инфы маловато на плюсах, думаю на php сделаю ибо время очень поджимает, там вон навалом примеров

xperious ★★
() автор топика
Ответ на: комментарий от xperious

да как-то инфы маловато на плюсах

Для плюсов, из адекватного, я видел только это https://github.com/openldap/openldap/tree/master/contrib/ldapc++

Всё остальное только на С. Для mozilla ldap c sdk документация вполне нормальная.

думаю на php сделаю

Если у тебя есть php и нет жёстких требований к производительности, то, разумеется надо делать на php. Оно и проще, и надёжнее, и безопаснее.

хм, а в принципе реально осуществить поиск инфы о пользователе в AD по его UPN(не по SPN)?

Я тебе уже который раз говорю: ищешь по фильтру «userprincipalname=<сюда подставить полученный upn>», получаешь учётку со всей информацией.

Ivan_qrt ★★★★★
()
Ответ на: комментарий от Ivan_qrt

спасибо за ссылки, странно что сам не нашел...

такой вопрос: допустим, есть пользователь дядя вова с учетной записью vova@test.local, так вот нужно осуществить поиск по vova@test.local... я правильно понимаю, что vova@test.local это upn-имя пользователя?

допустим, по CN=дядя вова,DC=test,DC=local находит, но нужно чтоб по vova@test.local, вот это реально?

xperious ★★
() автор топика
Ответ на: комментарий от xperious

Ищешь по «userPrincipalName=vova@test.local». Как и написано выше.

Можешь поставить себе на сервак openldap-clients и по пользоваться ldapsearch для общего понимания, что из себя представляет ldap.

Разумеется, почитать про ldap-сервера будет не лишним.

Ivan_qrt ★★★★★
()
Ответ на: комментарий от Ivan_qrt

последний час бьюсь над этим: так работает:

ldap_search($connect,"CN=дядя вова,DC=test,DC=local", "(objectClass=*)", array("*") ) 
    or die("!!");
а так нет, перепробовал все:
ldap_search($connect, "DC=XXXX,DC=XXXX", "(UserPrincipalName=vova@TEST.LOCAL)", array("*") )
    or die("!!");

xperious ★★
() автор топика
Ответ на: комментарий от xperious

Телепаты в отпуске. Без них в чём твоя ошибка без какой-либо о ней информации сказать крайне трудно. УМВР вот так:

<?php
    $con = ldap_connect("ldaps://ad.domain.local:636");
    ldap_set_option($con, LDAP_OPT_PROTOCOL_VERSION, 3);
    if(!$con)
        echo "!con";
    $res = ldap_bind($con, "cn=ldapuser,cn=users,dc=domain,dc=local", "secret");
    echo "bind: $res"."\n";
    $sr = ldap_search($con, "dc=domain,dc=local", "userprincipalname=username@domain.local");
    echo ldap_count_entries($con, $sr)."\n";

    $info = ldap_get_entries($con, $sr);
    echo "count: ".$info['count']."\n";
    for($i = 0; $i < $info['count']; ++$i) {
        $user = $info[$i];
        echo "dn: " . $user['dn']."\n";
        echo "cn: " . $user['cn'][0]."\n";
        echo "sam: " . $user['samaccountname'][0]."\n";
        echo "upn: " . $user['userprincipalname'][0]."\n";
    }
?>

Ivan_qrt ★★★★★
()
Ответ на: комментарий от Ivan_qrt

вот так не прокатывает, вообще не может найти юзера(падает на die)

<?php
    /* коннектимся и биндимся */
    $sr = ldap_search($con, "dc=test,dc=local", "userprincipalname=vova@test.local")
    or die("не могу найти юзера");
    echo ldap_count_entries($con, $sr)."\n";
?>

вот так не падает, но возвращает нулевой результат:

<?php
    /* коннектимся и биндимся */
    $sr = ldap_search($con, "dc=xxxx,dc=xxxx", "userprincipalname=vova@test.local")
    or die("не могу найти юзера");
    echo ldap_count_entries($con, $sr)."\n";
?>

вот так находит, но это не то что нужно:

<?php
    /* коннектимся и биндимся */
    $sr = ldap_search($con, "cn=дядя вова,dc=test,dc=local", "(objectClass=*)")
    or die("не могу найти юзера");
    echo ldap_count_entries($con, $sr)."\n";
?>
и везде в логах присутствует client didn't delegate us their credentials

xperious ★★
() автор топика
Последнее исправление: xperious (всего исправлений: 1)
Ответ на: комментарий от xperious

мде... кажись нашел ответ: если пользователь не расположен ни в какой папке, то его найти не удается, но стоило создать пользователя в users, как сразу все нашлось

xperious ★★
() автор топика
Ответ на: комментарий от xperious

если пользователь не расположен ни в какой папке, то его найти не удается, но стоило создать пользователя в users, как сразу все нашлось

С правами проблемы?

Ivan_qrt ★★★★★
()
Ответ на: комментарий от Ivan_qrt

честно говоря не знаю...

setspn -L vova возвращал CN=дядя вова,DC=test,DC=local... вот этого не мог найти

сделал другого: setspn -L vanya возвращает CN=дядя ваня,CN=users,DC=test,DC=local - этого находит без проблем

client didn't delegate us their credentials все равно есть... это походу вообще с ldap-запросами не связано

xperious ★★
() автор топика
Последнее исправление: xperious (всего исправлений: 2)
Ответ на: комментарий от xperious

сделал другого: setspn -L vanya

Как ты думаешь, в чём разница между spn и upn? И почему ты проверяешь userprincipalname по serviceprincipalname?

client didn't delegate us their credentials все равно есть... это походу вообще с ldap-запросами не связано

/* коннектимся и биндимся */

Очевидно, нужно коннектиться и биндиться лучше.

Ivan_qrt ★★★★★
()
Ответ на: комментарий от Ivan_qrt

Как ты думаешь, в чём разница между spn и upn? И почему ты проверяешь userprincipalname по serviceprincipalname?

да честно говоря, не сильно разбираюсь

xperious ★★
() автор топика
Ответ на: комментарий от xperious

Ну если ты сам проблему решать не хочешь, информацию для её решения не предоставляешь, то зачем тогда вообще было тред заводить?

Ivan_qrt ★★★★★
()
Ответ на: комментарий от Ivan_qrt

та вроде решилось, получил от ad то что нужно было... вы очень помогли(а если учесть все темы, то вообще), спасибо за все. правда все равно на c++ придется делать... есть необходимость в общем

xperious ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.