Проблемы с безопасным связыванием с Active Directory с помощью PHP

Кажется, я не могу использовать php для надежного привязки к Active Directory. Незашифрованные соединения работают нормально. Использование других клиентов может безопасно связываться, например, с помощью LDAPAdmin через SSL. В чем проблема? Есть ли какой-то модуль SSL LDAP, который мне не хватает? Как безопасно привязываться к серверу с помощью php?

Я заметил из phpinfo() что cURL поддерживает ldap / ldaps – что является хорошим примером использования этого для выполнения безопасного связывания в php? Является ли это жизнеспособным решением?

phpinfo ();

 ldap LDAP Support enabled RCS Version $Id: ldap.c 293036 2010-01-03 09:23:27Z sebastian $ Total Links 0/unlimited API Version 3001 Vendor Name OpenLDAP Vendor Version 20421 SASL Support Enabled 

Попытка привязки к серверу Active Directory с использованием PHP версии 5.3.2-1ubuntu4.7 из Ubuntu 10.04 repo

 $username = 'user'; $password = 'passwd'; $account_suffix = '@example.com'; $hostnameSSL = 'ldaps://ldap.example.com:636'; $hostnameTLS = 'ldap.example.com'; $portTLS = 389; ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7); // Attempting fix from http://www.php.net/manual/en/ref.ldap.php#77553 putenv('LDAPTLS_REQCERT=never'); #################### # SSL bind attempt # #################### // Attempting syntax from http://www.php.net/manual/en/function.ldap-bind.php#101445 $con = ldap_connect($hostnameSSL); if (!is_resource($con)) trigger_error("Unable to connect to $hostnameSSL",E_USER_WARNING); // Options from http://www.php.net/manual/en/ref.ldap.php#73191 if (!ldap_set_option($con, LDAP_OPT_PROTOCOL_VERSION, 3)) { trigger_error("Failed to set LDAP Protocol version to 3, TLS not supported",E_USER_WARNING); } ldap_set_option($con, LDAP_OPT_REFERRALS, 0); if (ldap_bind($con,$username . $account_suffix, $password)) die('All went well using SSL'); ldap_close($con); #################### # TLS bind attempt # #################### $con = ldap_connect($hostnameTLS,$portTLS); ldap_set_option($con, LDAP_OPT_PROTOCOL_VERSION, 3); ldap_set_option($con, LDAP_OPT_REFERRALS, 0); $encrypted = (ldap_start_tls($con)); if ($encrypted) ldap_bind($con,$username . $account_suffix, $password); // Unecrypted works, but don't want logins sent in cleartext ldap_close($con); ##################### # SASL bind attempt # ##################### $con = ldap_connect($hostnameTLS,$portTLS); ldap_set_option($con, LDAP_OPT_PROTOCOL_VERSION, 3); ldap_set_option($con, LDAP_OPT_REFERRALS, 0); ldap_sasl_bind($con, NULL, $password, 'DIGEST-MD5', NULL, $username. $account_suffix); ldap_close($con); 

Все вышесказанное терпит неудачу. Ошибки из журнала:

 ldap_create ldap_url_parse_ext(ldaps://ldap.example.com:636) ldap_bind_s ldap_simple_bind_s ldap_sasl_bind_s ldap_sasl_bind ldap_send_initial_request ldap_new_connection 1 1 0 ldap_int_open_connection ldap_connect_to_host: TCP ldap.example.com:636 ldap_new_socket: 27 ldap_prepare_socket: 27 ldap_connect_to_host: Trying 1.1.1.1:636 ldap_pvt_connect: fd: 27 tm: -1 async: 0 ldap_open_defconn: successful ldap_send_server_request ldap_result ld 0x215380c0 msgid 1 wait4msg ld 0x215380c0 msgid 1 (infinite timeout) wait4msg continue ld 0x215380c0 msgid 1 all 1 ** ld 0x215380c0 Connections: * host: ldap.example.com port: 636 (default) refcnt: 2 status: Connected last used: Thu Mar 10 11:15:53 2011 ** ld 0x215380c0 Outstanding Requests: * msgid 1, origid 1, status InProgress outstanding referrals 0, parent count 0 ld 0x215380c0 request count 1 (abandoned 0) ** ld 0x215380c0 Response Queue: Empty ld 0x215380c0 response count 0 ldap_chkResponseList ld 0x215380c0 msgid 1 all 1 ldap_chkResponseList returns ld 0x215380c0 NULL ldap_int_select read1msg: ld 0x215380c0 msgid 1 all 1 ldap_err2string [Thu Mar 10 11:15:53 2011] [error] [client ::1] PHP Warning: ldap_bind() [<a href='function.ldap-bind'>function.ldap-bind</a>]: Unable to bind to server: Can't contact LDAP server in /..test.php on line 28 [Thu Mar 10 11:15:53 2011] [error] [client ::1] PHP Stack trace: [Thu Mar 10 11:15:53 2011] [error] [client ::1] PHP 1. {main}() /..test.php:0 [Thu Mar 10 11:15:53 2011] [error] [client ::1] PHP 2. ldap_bind() /..test.php:28 ldap_free_request (origid 1, msgid 1) ldap_free_connection 1 1 ldap_free_connection: actually freed ldap_create ldap_err2string [Thu Mar 10 11:15:53 2011] [error] [client ::1] PHP Warning: ldap_start_tls() [<a href='function.ldap-start-tls'>function.ldap-start-tls</a>]: Unable to start TLS: Not Supported in /..test.php on line 37 [Thu Mar 10 11:15:53 2011] [error] [client ::1] PHP Stack trace: [Thu Mar 10 11:15:53 2011] [error] [client ::1] PHP 1. {main}() /..test.php:0 [Thu Mar 10 11:15:53 2011] [error] [client ::1] PHP 2. ldap_start_tls() /..test.php:37 ldap_create ldap_sasl_interactive_bind_s: user selected: DIGEST-MD5 ldap_err2string [Thu Mar 10 11:15:53 2011] [error] [client ::1] PHP Warning: ldap_sasl_bind() [<a href='function.ldap-sasl-bind'>function.ldap-sasl-bind</a>]: Unable to bind to server: Not Supported in /..test.php on line 47 [Thu Mar 10 11:15:53 2011] [error] [client ::1] PHP Stack trace: [Thu Mar 10 11:15:53 2011] [error] [client ::1] PHP 1. {main}() /..test.php:0 [Thu Mar 10 11:15:53 2011] [error] [client ::1] PHP 2. ldap_sasl_bind() /..test.php:47 

Глядя на ответ ssl:

 >> openssl s_client -connect my.example.com:636 -prexit (...) SSL handshake has read 5732 bytes and written 443 bytes --- New, TLSv1/SSLv3, Cipher is RC4-MD5 Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE SSL-Session: Protocol : TLSv1 Cipher : RC4-MD5 Session-ID: 111111111111111111111111 Session-ID-ctx: Master-Key: AAAAAAAAAAAAAAAAAAAAA Key-Arg : None Start Time: 1299071105 Timeout : 300 (sec) Verify return code: 20 (unable to get local issuer certificate) 

Результаты из 'strace php test.php':

  write(2, " refcnt: 2 status: Connected\n", 31 refcnt: 2 status: Connected ) = 31 write(2, " last used: Tue Mar 15 10:59:19"..., 39 last used: Tue Mar 15 10:59:19 2011 ) = 39 write(2, "\n", 1 ) = 1 write(2, "** ld 0x954e0b8 Outstanding Requ"..., 38** ld 0x954e0b8 Outstanding Requests: ) = 38 write(2, " * msgid 1, origid 1, status In"..., 41 * msgid 1, origid 1, status InProgress ) = 41 write(2, " outstanding referrals 0, pare"..., 43 outstanding referrals 0, parent count 0 ) = 43 write(2, " ld 0x954e0b8 request count 1 ("..., 45 ld 0x954e0b8 request count 1 (abandoned 0) ) = 45 write(2, "** ld 0x954e0b8 Response Queue:\n", 32** ld 0x954e0b8 Response Queue: ) = 32 write(2, " Empty\n", 9 Empty ) = 9 write(2, " ld 0x954e0b8 response count 0\n", 32 ld 0x954e0b8 response count 0 ) = 32 write(2, "ldap_chkResponseList ld 0x954e0b"..., 48ldap_chkResponseList ld 0x954e0b8 msgid 1 all 1 ) = 48 write(2, "ldap_chkResponseList returns ld "..., 47ldap_chkResponseList returns ld 0x954e0b8 NULL ) = 47 write(2, "ldap_int_select\n", 16ldap_int_select ) = 16 poll([{fd=3, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, -1) = 1 ([{fd=3, revents=POLLIN}]) write(2, "read1msg: ld 0x954e0b8 msgid 1 a"..., 37read1msg: ld 0x954e0b8 msgid 1 all 1 ) = 37 read(3, "", 8) = 0 write(2, "ldap_err2string\n", 16ldap_err2string ) = 16 write(2, "PHP Warning: ldap_bind(): Unabl"..., 158PHP Warning: ldap_bind(): Unable to bind to server: Can't contact LDAP server in 

И у меня есть исправление /etc/ldap.conf с 'TLS_REQCERT never' – хотя это исправление для другой ошибки, что дает довольно ясное сообщение об ошибке.

Вы видели комментарий на странице PHP.net о недостатках разрешений в каком-либо хранилище сертификатов, который делает это:

http://de3.php.net/manual/en/function.ldap-connect.php

bleathem 27-Feb-2008 10:30 Все публикуют о получении ldaps: // работая в стеке WAMP / AD, мне было трудно найти, как это сделать в RHEL 5.1 (со всеми rpms). Хорошая старая strace сделала трюк и помогла мне найти проблему … Оказывается, php искал файл CA в / etc / pki / CA, и у меня не было прав на эту папку. chmod'ing до 755 решил мое сообщение «Не могу связаться с LDAP-сервером».

Так что, возможно, это и ваша проблема. Если нет, вы должны дать либо strace, либо wirehark попытку поймать системные вызовы и сетевые передачи и выяснить, что пошло не так. Один из них ясно покажет это.

вот как я это делаю:

 <?php $username = ''; // username to check $password = ''; // password to check /** * Is it an Active Directory? * * <pre> * true = yes * set the following values: * SDB_AUTH_LDAP_HOST * SDB_AUTH_LDAP_SSL * SDB_AUTH_LDAP_BASE * SDB_AUTH_LDAP_SEARCH * SDB_AUTH_LDAP_USERDOMAIN * false = no, you have to supply an hostname * and configure the following values: * SDB_AUTH_LDAP_HOST * SDB_AUTH_LDAP_PORT * SDB_AUTH_LDAP_SSL * SDB_AUTH_LDAP_BASE * SDB_AUTH_LDAP_SEARCH * SDB_AUTH_LDAP_USERDOMAIN * </pre> * @see SDB_AUTH_LDAP_HOST */ define('SDB_AUTH_IS_AD', true); /** * Domain name of the LDAP Host or of the AD-Domain */ define('SDB_AUTH_LDAP_HOST', 'your-domain.tld'); /** * LDAP Port? * * if {@link SDB_AUTH_IS_AD} = true, then the port will be read form DNS. */ define('SDB_AUTH_LDAP_PORT', '389'); /** * Use LDAPS (true) oder LDAP (false) connection? */ define('SDB_AUTH_LDAP_SSL', false); /** * LDAP Base */ define('SDB_AUTH_LDAP_BASE', 'CN=Users,DC=your-domain.tld,DC=de'); /** * LDAP Search, to find a user * * %s will be replaced by the username.<br> * zB CN=%s */ define('SDB_AUTH_LDAP_SEARCH', '(&(sAMAccountName=%s)(objectclass=user)(objectcategory=person))'); /** * Die LDAP Domain des Benutzers * * if the username doesnt contain a domain append this domain to it.<br> * in case this is empty, nothing will be appended. */ define('SDB_AUTH_LDAP_USERDOMAIN', 'your-domain.tld'); /** * Path to LDAP Search * * Will give back better error messages * ( leave empty in case you don't want to have it. ) */ define('SDB_AUTH_LDAP_SEARCHBIN', '/usr/bin/ldapsearch'); $ldap_error_codes=array( '525' => 'Username doesnt exist.', '52e' => 'Wrong password.', '530' => 'You cannot login at this time.', '531' => 'You cannot login from this host.', '532' => 'Your password was expired.', '533' => 'Your account has been deactivated.', '701' => 'Your account was expired.', '773' => 'Please set another password (at your workstation) before you login.', '775' => 'Your account has been locked.', ); if(SDB_AUTH_LDAP_SSL) $dcs=dns_get_record("_ldaps._tcp.".SDB_AUTH_LDAP_HOST, DNS_SRV); else $dcs=dns_get_record("_ldap._tcp.".SDB_AUTH_LDAP_HOST, DNS_SRV); shuffle($dcs); $_LDAP_ATTRS=array('cn', 'sn', 'description', 'givenName', 'distinguishedName', 'displayName', 'memberOf', 'name', 'sAMAccountName', 'sAMAccountType', 'objectClass', 'objectCategory'); if(SDB_AUTH_LDAP_USERDOMAIN!='' && strstr($username, '@')===false) { $username=$username.'@'.SDB_AUTH_LDAP_USERDOMAIN; } $status=array(); $status['CN']=''; $status['displayName']=''; $status['description']=''; $status['distinguishedName']=''; $status['groups']=array(); $status['RC']=array(); $status['connected']=false; $status['user_exists']=false; $status['is_in_team']=false; foreach($dcs as $_LDAP_HOST) { $_LDAP_PORT=$_LDAP_HOST['port']; $_LDAP_HOST=$_LDAP_HOST['target']; // check connection first ( http://bugs.php.net/bug.php?id=15637 ) $sock=@fsockopen($_LDAP_HOST, $_LDAP_PORT, $errno, $errstr, 1); @fclose($sock); if($errno!=0) continue; // then do a "connect"... ( the real connect happens with bind ) $ds=@ldap_connect(( SDB_AUTH_LDAP_SSL ? "ldaps://" : "ldap://" ).$_LDAP_HOST.":".$_LDAP_PORT."/"); ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3); // are we connected? actually, this will always return true if(is_resource($ds)) { $status['connected']=true; // login sucessful? actually also connection test if(@ldap_bind($ds, $username, $password)) { // search $sr=ldap_search($ds, SDB_AUTH_LDAP_BASE, sprintf(SDB_AUTH_LDAP_SEARCH, $usernode), $_LDAP_ATTRS); // suche successful? if(is_resource($sr)) { // fetch entries $info = ldap_get_entries($ds, $sr); if(isset($info['count']) && $info['count']>0) { $status['user_exists']=true; } // close search result ldap_free_result($sr); $status['CN']=$info[0]['cn'][0]; $status['description']=$info[0]['description'][0]; $status['displayName']=$info[0]['displayname'][0]; $status['distinguishedName']=$info[0]['distinguishedname'][0]; // is the user in the dexteam? for($i=0; $i<$info[0]['memberof']['count']; $i++) { $status['groups'][]=$info[0]['memberof'][$i]; // IS IN TEAM CHECK if(substr($info[0]['memberof'][$i], 0, strlen('CN=DexTeam,'))=='CN=DexTeam,') $status['is_in_team']=true; } $status['RC']['code']=ldap_errno($ds); $status['RC']['string']=ldap_error($ds); ldap_close($ds); break; } else { $status['RC']['code']=ldap_errno($ds); $status['RC']['string']=ldap_error($ds); ldap_close($ds); break; } } else { $status['RC']['code']=ldap_errno($ds); $status['RC']['string']=ldap_error($ds); // do we want better error messages? if(SDB_AUTH_LDAP_SEARCHBIN!='' && is_executable(SDB_AUTH_LDAP_SEARCHBIN)) { $status['RC']['ldapsearchrc']=''; $status['RC']['ldapsearchtxt']=array(); exec(SDB_AUTH_LDAP_SEARCHBIN.' -x -H '.escapeshellarg(( SDB_AUTH_LDAP_SSL ? "ldaps://" : "ldap://" ).$_LDAP_HOST.":".$_LDAP_PORT."/").' -D '.escapeshellarg($username).' -w '.escapeshellarg($password).' 2>&1', $status['RC']['ldapsearchtxt'], $status['RC']['ldapsearchrc']); if($status['RC']['ldapsearchrc']!=0) { if(preg_match("/data ([^, ]+),/", $status['RC']['ldapsearchtxt'][1], $matches)) { if(isset($ldap_error_codes[$matches[1]])) { $status['RC']['code']=$matches[1]; $status['RC']['string']=$ldap_error_codes[$matches[1]]; } } unset($status['RC']['ldapsearchrc']); unset($status['RC']['ldapsearchtxt']); } } ldap_close($ds); break; } } else { continue; } } с <?php $username = ''; // username to check $password = ''; // password to check /** * Is it an Active Directory? * * <pre> * true = yes * set the following values: * SDB_AUTH_LDAP_HOST * SDB_AUTH_LDAP_SSL * SDB_AUTH_LDAP_BASE * SDB_AUTH_LDAP_SEARCH * SDB_AUTH_LDAP_USERDOMAIN * false = no, you have to supply an hostname * and configure the following values: * SDB_AUTH_LDAP_HOST * SDB_AUTH_LDAP_PORT * SDB_AUTH_LDAP_SSL * SDB_AUTH_LDAP_BASE * SDB_AUTH_LDAP_SEARCH * SDB_AUTH_LDAP_USERDOMAIN * </pre> * @see SDB_AUTH_LDAP_HOST */ define('SDB_AUTH_IS_AD', true); /** * Domain name of the LDAP Host or of the AD-Domain */ define('SDB_AUTH_LDAP_HOST', 'your-domain.tld'); /** * LDAP Port? * * if {@link SDB_AUTH_IS_AD} = true, then the port will be read form DNS. */ define('SDB_AUTH_LDAP_PORT', '389'); /** * Use LDAPS (true) oder LDAP (false) connection? */ define('SDB_AUTH_LDAP_SSL', false); /** * LDAP Base */ define('SDB_AUTH_LDAP_BASE', 'CN=Users,DC=your-domain.tld,DC=de'); /** * LDAP Search, to find a user * * %s will be replaced by the username.<br> * zB CN=%s */ define('SDB_AUTH_LDAP_SEARCH', '(&(sAMAccountName=%s)(objectclass=user)(objectcategory=person))'); /** * Die LDAP Domain des Benutzers * * if the username doesnt contain a domain append this domain to it.<br> * in case this is empty, nothing will be appended. */ define('SDB_AUTH_LDAP_USERDOMAIN', 'your-domain.tld'); /** * Path to LDAP Search * * Will give back better error messages * ( leave empty in case you don't want to have it. ) */ define('SDB_AUTH_LDAP_SEARCHBIN', '/usr/bin/ldapsearch'); $ldap_error_codes=array( '525' => 'Username doesnt exist.', '52e' => 'Wrong password.', '530' => 'You cannot login at this time.', '531' => 'You cannot login from this host.', '532' => 'Your password was expired.', '533' => 'Your account has been deactivated.', '701' => 'Your account was expired.', '773' => 'Please set another password (at your workstation) before you login.', '775' => 'Your account has been locked.', ); if(SDB_AUTH_LDAP_SSL) $dcs=dns_get_record("_ldaps._tcp.".SDB_AUTH_LDAP_HOST, DNS_SRV); else $dcs=dns_get_record("_ldap._tcp.".SDB_AUTH_LDAP_HOST, DNS_SRV); shuffle($dcs); $_LDAP_ATTRS=array('cn', 'sn', 'description', 'givenName', 'distinguishedName', 'displayName', 'memberOf', 'name', 'sAMAccountName', 'sAMAccountType', 'objectClass', 'objectCategory'); if(SDB_AUTH_LDAP_USERDOMAIN!='' && strstr($username, '@')===false) { $username=$username.'@'.SDB_AUTH_LDAP_USERDOMAIN; } $status=array(); $status['CN']=''; $status['displayName']=''; $status['description']=''; $status['distinguishedName']=''; $status['groups']=array(); $status['RC']=array(); $status['connected']=false; $status['user_exists']=false; $status['is_in_team']=false; foreach($dcs as $_LDAP_HOST) { $_LDAP_PORT=$_LDAP_HOST['port']; $_LDAP_HOST=$_LDAP_HOST['target']; // check connection first ( http://bugs.php.net/bug.php?id=15637 ) $sock=@fsockopen($_LDAP_HOST, $_LDAP_PORT, $errno, $errstr, 1); @fclose($sock); if($errno!=0) continue; // then do a "connect"... ( the real connect happens with bind ) $ds=@ldap_connect(( SDB_AUTH_LDAP_SSL ? "ldaps://" : "ldap://" ).$_LDAP_HOST.":".$_LDAP_PORT."/"); ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3); // are we connected? actually, this will always return true if(is_resource($ds)) { $status['connected']=true; // login sucessful? actually also connection test if(@ldap_bind($ds, $username, $password)) { // search $sr=ldap_search($ds, SDB_AUTH_LDAP_BASE, sprintf(SDB_AUTH_LDAP_SEARCH, $usernode), $_LDAP_ATTRS); // suche successful? if(is_resource($sr)) { // fetch entries $info = ldap_get_entries($ds, $sr); if(isset($info['count']) && $info['count']>0) { $status['user_exists']=true; } // close search result ldap_free_result($sr); $status['CN']=$info[0]['cn'][0]; $status['description']=$info[0]['description'][0]; $status['displayName']=$info[0]['displayname'][0]; $status['distinguishedName']=$info[0]['distinguishedname'][0]; // is the user in the dexteam? for($i=0; $i<$info[0]['memberof']['count']; $i++) { $status['groups'][]=$info[0]['memberof'][$i]; // IS IN TEAM CHECK if(substr($info[0]['memberof'][$i], 0, strlen('CN=DexTeam,'))=='CN=DexTeam,') $status['is_in_team']=true; } $status['RC']['code']=ldap_errno($ds); $status['RC']['string']=ldap_error($ds); ldap_close($ds); break; } else { $status['RC']['code']=ldap_errno($ds); $status['RC']['string']=ldap_error($ds); ldap_close($ds); break; } } else { $status['RC']['code']=ldap_errno($ds); $status['RC']['string']=ldap_error($ds); // do we want better error messages? if(SDB_AUTH_LDAP_SEARCHBIN!='' && is_executable(SDB_AUTH_LDAP_SEARCHBIN)) { $status['RC']['ldapsearchrc']=''; $status['RC']['ldapsearchtxt']=array(); exec(SDB_AUTH_LDAP_SEARCHBIN.' -x -H '.escapeshellarg(( SDB_AUTH_LDAP_SSL ? "ldaps://" : "ldap://" ).$_LDAP_HOST.":".$_LDAP_PORT."/").' -D '.escapeshellarg($username).' -w '.escapeshellarg($password).' 2>&1', $status['RC']['ldapsearchtxt'], $status['RC']['ldapsearchrc']); if($status['RC']['ldapsearchrc']!=0) { if(preg_match("/data ([^, ]+),/", $status['RC']['ldapsearchtxt'][1], $matches)) { if(isset($ldap_error_codes[$matches[1]])) { $status['RC']['code']=$matches[1]; $status['RC']['string']=$ldap_error_codes[$matches[1]]; } } unset($status['RC']['ldapsearchrc']); unset($status['RC']['ldapsearchtxt']); } } ldap_close($ds); break; } } else { continue; } } с <?php $username = ''; // username to check $password = ''; // password to check /** * Is it an Active Directory? * * <pre> * true = yes * set the following values: * SDB_AUTH_LDAP_HOST * SDB_AUTH_LDAP_SSL * SDB_AUTH_LDAP_BASE * SDB_AUTH_LDAP_SEARCH * SDB_AUTH_LDAP_USERDOMAIN * false = no, you have to supply an hostname * and configure the following values: * SDB_AUTH_LDAP_HOST * SDB_AUTH_LDAP_PORT * SDB_AUTH_LDAP_SSL * SDB_AUTH_LDAP_BASE * SDB_AUTH_LDAP_SEARCH * SDB_AUTH_LDAP_USERDOMAIN * </pre> * @see SDB_AUTH_LDAP_HOST */ define('SDB_AUTH_IS_AD', true); /** * Domain name of the LDAP Host or of the AD-Domain */ define('SDB_AUTH_LDAP_HOST', 'your-domain.tld'); /** * LDAP Port? * * if {@link SDB_AUTH_IS_AD} = true, then the port will be read form DNS. */ define('SDB_AUTH_LDAP_PORT', '389'); /** * Use LDAPS (true) oder LDAP (false) connection? */ define('SDB_AUTH_LDAP_SSL', false); /** * LDAP Base */ define('SDB_AUTH_LDAP_BASE', 'CN=Users,DC=your-domain.tld,DC=de'); /** * LDAP Search, to find a user * * %s will be replaced by the username.<br> * zB CN=%s */ define('SDB_AUTH_LDAP_SEARCH', '(&(sAMAccountName=%s)(objectclass=user)(objectcategory=person))'); /** * Die LDAP Domain des Benutzers * * if the username doesnt contain a domain append this domain to it.<br> * in case this is empty, nothing will be appended. */ define('SDB_AUTH_LDAP_USERDOMAIN', 'your-domain.tld'); /** * Path to LDAP Search * * Will give back better error messages * ( leave empty in case you don't want to have it. ) */ define('SDB_AUTH_LDAP_SEARCHBIN', '/usr/bin/ldapsearch'); $ldap_error_codes=array( '525' => 'Username doesnt exist.', '52e' => 'Wrong password.', '530' => 'You cannot login at this time.', '531' => 'You cannot login from this host.', '532' => 'Your password was expired.', '533' => 'Your account has been deactivated.', '701' => 'Your account was expired.', '773' => 'Please set another password (at your workstation) before you login.', '775' => 'Your account has been locked.', ); if(SDB_AUTH_LDAP_SSL) $dcs=dns_get_record("_ldaps._tcp.".SDB_AUTH_LDAP_HOST, DNS_SRV); else $dcs=dns_get_record("_ldap._tcp.".SDB_AUTH_LDAP_HOST, DNS_SRV); shuffle($dcs); $_LDAP_ATTRS=array('cn', 'sn', 'description', 'givenName', 'distinguishedName', 'displayName', 'memberOf', 'name', 'sAMAccountName', 'sAMAccountType', 'objectClass', 'objectCategory'); if(SDB_AUTH_LDAP_USERDOMAIN!='' && strstr($username, '@')===false) { $username=$username.'@'.SDB_AUTH_LDAP_USERDOMAIN; } $status=array(); $status['CN']=''; $status['displayName']=''; $status['description']=''; $status['distinguishedName']=''; $status['groups']=array(); $status['RC']=array(); $status['connected']=false; $status['user_exists']=false; $status['is_in_team']=false; foreach($dcs as $_LDAP_HOST) { $_LDAP_PORT=$_LDAP_HOST['port']; $_LDAP_HOST=$_LDAP_HOST['target']; // check connection first ( http://bugs.php.net/bug.php?id=15637 ) $sock=@fsockopen($_LDAP_HOST, $_LDAP_PORT, $errno, $errstr, 1); @fclose($sock); if($errno!=0) continue; // then do a "connect"... ( the real connect happens with bind ) $ds=@ldap_connect(( SDB_AUTH_LDAP_SSL ? "ldaps://" : "ldap://" ).$_LDAP_HOST.":".$_LDAP_PORT."/"); ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3); // are we connected? actually, this will always return true if(is_resource($ds)) { $status['connected']=true; // login sucessful? actually also connection test if(@ldap_bind($ds, $username, $password)) { // search $sr=ldap_search($ds, SDB_AUTH_LDAP_BASE, sprintf(SDB_AUTH_LDAP_SEARCH, $usernode), $_LDAP_ATTRS); // suche successful? if(is_resource($sr)) { // fetch entries $info = ldap_get_entries($ds, $sr); if(isset($info['count']) && $info['count']>0) { $status['user_exists']=true; } // close search result ldap_free_result($sr); $status['CN']=$info[0]['cn'][0]; $status['description']=$info[0]['description'][0]; $status['displayName']=$info[0]['displayname'][0]; $status['distinguishedName']=$info[0]['distinguishedname'][0]; // is the user in the dexteam? for($i=0; $i<$info[0]['memberof']['count']; $i++) { $status['groups'][]=$info[0]['memberof'][$i]; // IS IN TEAM CHECK if(substr($info[0]['memberof'][$i], 0, strlen('CN=DexTeam,'))=='CN=DexTeam,') $status['is_in_team']=true; } $status['RC']['code']=ldap_errno($ds); $status['RC']['string']=ldap_error($ds); ldap_close($ds); break; } else { $status['RC']['code']=ldap_errno($ds); $status['RC']['string']=ldap_error($ds); ldap_close($ds); break; } } else { $status['RC']['code']=ldap_errno($ds); $status['RC']['string']=ldap_error($ds); // do we want better error messages? if(SDB_AUTH_LDAP_SEARCHBIN!='' && is_executable(SDB_AUTH_LDAP_SEARCHBIN)) { $status['RC']['ldapsearchrc']=''; $status['RC']['ldapsearchtxt']=array(); exec(SDB_AUTH_LDAP_SEARCHBIN.' -x -H '.escapeshellarg(( SDB_AUTH_LDAP_SSL ? "ldaps://" : "ldap://" ).$_LDAP_HOST.":".$_LDAP_PORT."/").' -D '.escapeshellarg($username).' -w '.escapeshellarg($password).' 2>&1', $status['RC']['ldapsearchtxt'], $status['RC']['ldapsearchrc']); if($status['RC']['ldapsearchrc']!=0) { if(preg_match("/data ([^, ]+),/", $status['RC']['ldapsearchtxt'][1], $matches)) { if(isset($ldap_error_codes[$matches[1]])) { $status['RC']['code']=$matches[1]; $status['RC']['string']=$ldap_error_codes[$matches[1]]; } } unset($status['RC']['ldapsearchrc']); unset($status['RC']['ldapsearchtxt']); } } ldap_close($ds); break; } } else { continue; } } 

вы включили сертификат? Я знаю, что была проблема, когда certifiacte получает отказ. отредактируйте «/etc/ldap/ldap.conf» и добавьте «TLS_REQCERT never»

 # # LDAP Defaults # # See ldap.conf(5) for details # This file should be world readable but not world writable. #BASE dc=example,dc=com #URI ldap://ldap.example.com ldap://ldap-master.example.com:666 #SIZELIMIT 12 #TIMELIMIT 15 #DEREF never TLS_REQCERT never 

однако для меня это работает с ldap и ldaps:

  • это может быть проблема конфигурации с конфигурацией объявления. возможно, некоторые ограничения безопасности …
  • Или это может быть проблема с php / ldap lib. Попробуйте обновить до более новых версий 🙂

Наконец, я смог заставить все работать на моей машине Windows, прочитав следующий поток ошибок PHP: http://bugs.php.net/bug.php?id=48866

К сожалению, это зависит от Windows, но в моем тестировании мне по крайней мере нужно идти в правильном направлении (я знаю, что он должен работать с PHP сейчас на моем веб-сервере … пока у меня ldap.conf настроен правильно). В Windows с PHP 5.3 мне нужно было добавить файл ldap.conf в корень моего диска C: (другие примеры, которые я видел в Интернете, помещали его в C: \ openldap \ sysconf, который не работал).

TLS все еще не работает точно (это дает мне сообщение «не удалось запустить tls: не могу связаться с сервером LDAP»), но SSL, похоже, работает, и я смог обновить пароль для учетной записи в своем тестовом скрипте ,

Я предполагаю, что файл ldap.conf просто нужно настроить аналогично на моем веб-сервере, и я, надеюсь, буду в бизнесе (я просто не уверен, что тот, который уже существует, тот, который мне нужно изменить или мне нужно для создания дополнительного). Я посмотрю, смогу ли я сообщить об этом фронте.

Поскольку мой код отлично работает с CentOS, я пришел к выводу, что проблема не в программировании. Мне пока не удалось запустить его в моей среде Ubuntu, но я предполагаю, что это ошибка в моем серверном программном обеспечении.

Включен ли LDAPS в Active Directory? Если это так, получите доверенный корень ключа ЦС в доверенное корневое хранилище ключей.