我似乎无法使用PHP安全地绑定到Active Directory.未加密的连接工作正常.使用其他客户端能够牢固地绑定,例如通过SSL连接使用LDAPAdmin.这里有什么问题?有没有我缺少的LDAP SSL模块?如何使用
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
尝试使用Ubuntu 10.04 repo中的PHP 5.3.2-1ubuntu4.7绑定到Active Directory服务器
$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,3); ldap_set_option($con,0); $encrypted = (ldap_start_tls($con)); if ($encrypted) ldap_bind($con,$password); // Unecrypted works,but don't want logins sent in cleartext ldap_close($con); ##################### # SASL bind attempt # ##################### $con = ldap_connect($hostnameTLS,0); ldap_sasl_bind($con,NULL,$password,'DIGEST-MD5',$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)
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,status In"...,41 * msgid 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从不’ – 即使这个修复是针对不同的错误,这给出了一个相当明确的错误消息.
这是我如何做到的:
<?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> * z.B. 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,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],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; } }
你启用了证书吗?我知道有一个问题,当证书被拒绝.编辑“/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问题.尝试更新到更新版本:)