За последние 24 часа нас посетили 34370 программистов и 1695 роботов. Сейчас ищут 727 программистов ...

Класс для работы с ldap

Тема в разделе "Прочие вопросы по PHP", создана пользователем alexey_baranov, 11 фев 2009.

  1. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    Не встечал ли кто хороший ldap-класс, а лучше всего, который не использует php_ldap. это было бы просто замечательно. Собираюсь делать аутентификацию через AD. В данный момент в поисках. посоветуйте, если кто сталкивался.
     
  2. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    Аутентификация все ближе, а идей никаких. Кто делал, посоветуйте с чего начать, а с чего не надо?
     
  3. neyr00n

    neyr00n Активный пользователь

    С нами с:
    29 ноя 2007
    Сообщения:
    106
    Симпатии:
    0
    я делал на друпале + AD (модуль). вот основная функция аутентификации
    PHP:
    1.  
    2. <?php
    3. function ldap_checkuser($username, $pwd)
    4. {
    5.     if ( $username == '' || $pwd == '' ) return false;
    6.  
    7.     $g_res = ldap_connect('<адрес сервера>');
    8.  
    9.     if ( $g_res == FALSE ) return false;
    10.  
    11.     ldap_set_option($g_res, LDAP_OPT_PROTOCOL_VERSION, 3);
    12.     ldap_set_option($g_res, LDAP_OPT_REFERRALS, 0);
    13.  
    14.     if ( @ldap_bind($g_res, "$username@domainname.ru", $pwd) == FALSE )
    15.     {
    16.         return false;
    17.     }
    18.  
    19.     // ищем этого юзверя в AD и забираем всю инфу о нем.
    20.     $sr=ldap_search($g_res,"ou=Office,dc=domainname,dc=ru", "(samaccountname=$username)", array("*") );
    21.     $info = ldap_get_entries($g_res, $sr);
    22.  
    23.     $ar_res = array();
    24.  
    25.     $ar_res['login'] = $username;
    26.     $ar_res['pwd'] = $pwd;
    27.  
    28.  
    29.     for ($i=0; $i<$info["count"]; $i++)
    30.     {
    31.          // тут в цикле обрабатывается инфа о юзвере
    32.     }
    33.  
    34.     ldap_unbind($g_res);
    35.  
    36.     $g_res = 0;
    37.  
    38.     return true;
    39. }?>
    40.  
    все остальное было на друпале ) не забываем, что у AD своя родная виндовая кодировка.
     
  4. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    neyr00n
    все понятно. спасибо. а класс какой-нибудь найти не пытался или тут кроме этой одной процедурки больше ничего и не понадобится?
     
  5. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    хороший класс?
     
  6. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    кстати насчет пхп и лдап. правильно я понимаю, что один раз в начале вся нужная инфа по пользователю скачивается из АД и сохраняется в сессию. А потом уже достается оттуда? как быть, если пользак уже зарегился и просит "открой мне то то и то то". Сначала его админы в АД добавят в нужную группу, а потом он должен будет перелогинится на сайте, чтобы информация из АД повторно считалась в сессию. Так что ли?
     
  7. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    Можно ли сделать обращение к лдапу каждый раз при загрузке страницы? Насколько это долго. Если это соизмеримо с обращением к БД, тогда конечно нет проблем.
     
  8. neyr00n

    neyr00n Активный пользователь

    С нами с:
    29 ноя 2007
    Сообщения:
    106
    Симпатии:
    0
    есть еще одна функция, которая ищет всех активных пользователей. вобщем мне только две функции понадобилось.

    если AD и сайт находятся на одной тачке по одному айпи, то по идее должно проходить быстро. а так по разному. лично у меня сайь т AD находятся на разных тачках, иногда коннект быстро проходит, иногда не очень ) зависимость не уловил.
     
  9. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    neyr00n
    у меня тоже на разных. хотя бы потому что апач и посгрес на фрях крутится, а АД где- то, еще не знаю где, но точно на винде. Ты значит в в сессии хранишь всю инфу по пользователю?
     
  10. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    тоже с АД какая- то лажу недавно была. очень медленно аутентификация проходила. похоже придется в сессию
     
  11. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    neyr00n
    ldap_search($сid, "DC=corp,DC=te,DC=ru", "(objectclass=person)") не работает, хотя через виндовую лдап-бродилку этот запрос выдает все что положено. в чем тут может быть дело? что там про кодировки в AD, может в этом дело?
     
  12. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    вот полный код
    сначала все проходит как положено

    PHP:
    1. $cid=ldap_connect($hostname);  //resource id='3' type='ldap link'
    2. ldap_bind($cid, "CN=root,OU=Users,OU=Технокомэнерго,DC=corp,DC=te,DC=ru", $bindpw); //true
    3.  
    потом уже идет
    PHP:
    1. ldap_search($сid, "DC=corp,DC=te,DC=ru", "(objectclass=person)")// тут false
     
  13. neyr00n

    neyr00n Активный пользователь

    С нами с:
    29 ноя 2007
    Сообщения:
    106
    Симпатии:
    0
    я так думаю, тебе надо указать где именно искать, например : ou=Users, по умолчанию там находятся все пользователи AD. плюс, вместо objectClass вставь например 'samaccountname=*' (для пробы). и добавь array("*") (фильтр полей, которые будут взяты из AD):

    PHP:
    1.  
    2. <?php
    3. // ищем все записи, которые находятся в "директории" Users.
    4. ldap_search($сid, "ou=Users,DC=corp,DC=te,DC=ru", "(samaccountname=*)", array("*"));
    5. ?>
    6.  
    upd. в твоем случае в baseDN еще можно добавить "OU=Технокомэнерго".

    я строчку для себя подбирал методом тыка %) ибо вводную документашку по AD я чет непонял вообще. слишком много умных слов ))

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

    про кодировку я тебя обманул. в utf AD хранит.
     
  14. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    вот спасибо, удружил. потерял на этом часик. вообще вывод такой: все запутано и сложно. целый день убил. Хотя бы потому что никто не придупредил, что там все в утф-8, но почему- то бинарные данные переводить в вин-1251 нельзя. чтобы их привести к человеческому виду надо делать бин2хекс() от утф-ного вида. Очень плохо, что через ldap нельзя получить косвенное вхождение пользователя в группу. Например (A>B, B>C => A>C). Приходится делать несколько рекурсивных запросов к АD для того чтобы рекурсивно подниматься до самых общих групп. Вот код, может кому пригодится. И на эти десять строчек потратил целый день. Все потому что нет нормальных классов для ЛДАП. Я использовал класс LDAP который нарыл в гугле http://www.ypass.net/software/php_ldap/ класс отстойный, потому что нет исключений. везде приходится писать кучи ифов и вообще кривой. достаточно заглянуть в конструктор, так что я его немного обернул.

    PHP:
    1. class ADUser extends User{
    2.     /**
    3.      *
    4.      * @var LDAPEx
    5.      */
    6.     public $ldap;
    7.     function login($name, $password) {
    8.         $userDomane= LDAP_USER_DOMAIN;
    9.         $this->ldap= new LDAPEx(iconv("Windows-1251", "UTF-8", "{$name}@{$userDomane}"), iconv("Windows-1251", "UTF-8", $password));
    10.         $this->ldap->search($this->ldap->win2utf("(&(objectclass=person)(sAMAccountName={$name}))"));
    11.         $attrs= $this->ldap->fetch();
    12.         //id
    13.         $this->id= bin2hex(($attrs['objectSid'][0]));
    14.         //роли
    15.         $this->property['roleeuserr']= array();
    16.         if (isset($attrs['memberOf']))
    17.             for($i=0; $i< $attrs['memberOf']['count']; $i++){
    18.                 $this->memberOf($this->ldap->utf2win($attrs['memberOf'][$i]));
    19.             }
    20.         //дисконект
    21.         $this->ldap->disconnect();
    22.     }
    23.     /**
    24.      * рекурсивно устанавливает роль и все роли в которые она входит
    25.      *
    26.      * @param $path путь до роли в формате ldap
    27.      */
    28.     function memberOf($path) {
    29.         $this->ldap->search($this->ldap->win2utf("(&(distinguishedName={$path}))"));
    30.         $attrs= $this->ldap->fetch();
    31.         //id
    32. //        echo $this->ldap->utf2win($attrs['name'][0]).': '.bin2hex($attrs['objectGUID'][0]).'<br>';
    33.         $this->property['roleeuserr'][]= bin2hex($attrs['objectGUID'][0]);
    34.         //найти родительские роли
    35.         if (isset($attrs['memberOf']))
    36.             for($i=0; $i< $attrs['memberOf']['count']; $i++)
    37.                 $this->memberOf($this->ldap->utf2win($attrs['memberOf'][$i]));
    38.     }
    39. }
    40.  
    а использовать его теперь так
    PHP:
    1. //LDAP
    2. /*
    3. *       The hostname of the LDAP server.  It may also be a space separated
    4. *       list of LDAP servers
    5. */
    6. define("LDAP_HOSTNAME", "9.0.11.177");
    7.  
    8. /*
    9. *    The BASE DN of your ldap server. (if you don't know what it is,
    10. *    you should check your slapd.conf file)
    11. */
    12. define("LDAP_BASEDN", "DC=corp,DC=te,DC=ru");
    13.  
    14. /*
    15. *    The BIND DN for your ldap server. (if you don't know what it is,
    16. *    you should check your slapd.conf file)
    17. */
    18. define("LDAP_BINDDN", iconv("Windows-1251", "UTF-8", "torsuperuser@corp.te.ru"));
    19.  
    20. /*
    21. *    The BIND PW for your ldap server. (if you don't know what it is,
    22. *    you should check your slapd.conf file)
    23. */
    24. define("LDAP_BINDPW", iconv("Windows-1251", "UTF-8", "qwerty"));
    25.  
    26. /*
    27. *    The FULL path to the configuration file with your objectClass
    28. *    definitions.  This file must be readable by the process using
    29. *    this class (probably your web server).  Do _NOT_ make your
    30. *    slapd.conf file world readable.  If you have objectClass definitions
    31. *    in your slapd.conf file, you should separate them into a slapd.oc.conf
    32. *    file.
    33. */
    34. define("LDAP_SLAPD_OC_CONF_PATH", "/usr/local/etc/openldap/slapd.oc.conf");
    35.  
    36. define("LDAP_USER_DOMAIN", "corp.te.ru");
    37.  
    38.  
    39. $user= new ADUser();
    40. $user->login('torsuperuser', 'qwerty');
    41. print_r($user);
    Код (Text):
    1. ADUser Object
    2. (
    3.     [ldap] => LDAPEx Object
    4.         (
    5.             [hostname] => 9.0.11.177
    6.             [basedn] => DC=corp,DC=te,DC=ru
    7.             [binddn] => torsuperuser@corp.te.ru
    8.             [bindpw] => qwerty
    9.             [OCconfigFilePath] => /usr/local/etc/openldap/slapd.oc.conf
    10.             [cid] => Resource id #46
    11.             [bid] => 1
    12.             [sr] => Resource id #53
    13.             [re] => Resource id #54
    14.             [error] => Success
    15.             [start] => 1
    16.             [objectClasses] => Array
    17.                 (
    18.                 )
    19.  
    20.         )
    21.  
    22.     [id] => 010500000000000515000000c94d7d363d787b17e77b8010a0060000
    23.     [time] =>
    24.     [born] =>
    25.     [master] =>
    26.     [CONT] =>
    27.     [VIEW] =>
    28.     [property] => Array
    29.         (
    30.             [roleeuserr] => Array
    31.                 (
    32.                     [0] => 710234bbc2abc148ade8c1f9b4567b24
    33.                     [1] => b730b0175c9c594180e02998baa5734e
    34.                     [2] => 8ca0b07f4b4d4f4ba730bf05312dd597
    35.                 )
    36.  
    37.         )
    38.  
    39. )
     
  15. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    салют всем! опять откопал эту тему, потому что возник новый вопрос.

    почему не получается прибиндиться к АД под некоторым пользователем и от его имени сменить себе же пароль? Переробовал разных userAccountControl, ничего не помогает. я пробовал делать и через ldap_modify и через ldap_mod_replace. Все время пишет одну и ту же лажу "Insufficient access". Что не так?

    userAccountControl: 512
    userAccountControl: 513
    userAccountControl: 66048
     
  16. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    не поверишь, пришел к тому же. один в один :) в основном из- за того, что в АД пользака никто не запрещает удалить, а в базе с пользаком может быть связана тонна логов и еще потому что в АД негде хранить списфические данные. Сначала использовал для этого ненужные поля AD вроде "Pager", но потом решил, что это еще большее извращение. Щас при первом входе пользака создаю его локальную копию, при последующих входах, обновляю ее. И в сессии храню локальную копию.