PHPのお勉強!

PHP TOP

LDAP 関数

目次

add a note

User Contributed Notes 34 notes

up
24
idbobby at rambler dot ru
14 years ago
First of all, sorry for my English.
Here are two functions to check group membership and some others which can be useful for work with LDAP (Active Directory in this example).

index.php
---------

<?php

$user
= 'bob';
$password = 'zhlob';
$host = 'myldap';
$domain = 'mydomain.ex';
$basedn = 'dc=mydomain,dc=ex';
$group = 'SomeGroup';

$ad = ldap_connect("ldap://{$host}.{$domain}") or die('Could not connect to LDAP server.');
ldap_set_option($ad, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ad, LDAP_OPT_REFERRALS, 0);
@
ldap_bind($ad, "{$user}@{$domain}", $password) or die('Could not bind to AD.');
$userdn = getDN($ad, $user, $basedn);
if (
checkGroupEx($ad, $userdn, getDN($ad, $group, $basedn))) {
//if (checkGroup($ad, $userdn, getDN($ad, $group, $basedn))) {
echo "You're authorized as ".getCN($userdn);
} else {
echo
'Authorization failed';
}
ldap_unbind($ad);

/*
* This function searchs in LDAP tree ($ad -LDAP link identifier)
* entry specified by samaccountname and returns its DN or epmty
* string on failure.
*/
function getDN($ad, $samaccountname, $basedn) {
$attributes = array('dn');
$result = ldap_search($ad, $basedn,
"(samaccountname={$samaccountname})", $attributes);
if (
$result === FALSE) { return ''; }
$entries = ldap_get_entries($ad, $result);
if (
$entries['count']>0) { return $entries[0]['dn']; }
else { return
''; };
}

/*
* This function retrieves and returns CN from given DN
*/
function getCN($dn) {
preg_match('/[^,]*/', $dn, $matchs, PREG_OFFSET_CAPTURE, 3);
return
$matchs[0][0];
}

/*
* This function checks group membership of the user, searching only
* in specified group (not recursively).
*/
function checkGroup($ad, $userdn, $groupdn) {
$attributes = array('members');
$result = ldap_read($ad, $userdn, "(memberof={$groupdn})", $attributes);
if (
$result === FALSE) { return FALSE; };
$entries = ldap_get_entries($ad, $result);
return (
$entries['count'] > 0);
}

/*
* This function checks group membership of the user, searching
* in specified group and groups which is its members (recursively).
*/
function checkGroupEx($ad, $userdn, $groupdn) {
$attributes = array('memberof');
$result = ldap_read($ad, $userdn, '(objectclass=*)', $attributes);
if (
$result === FALSE) { return FALSE; };
$entries = ldap_get_entries($ad, $result);
if (
$entries['count'] <= 0) { return FALSE; };
if (empty(
$entries[0]['memberof'])) { return FALSE; } else {
for (
$i = 0; $i < $entries[0]['memberof']['count']; $i++) {
if (
$entries[0]['memberof'][$i] == $groupdn) { return TRUE; }
elseif (
checkGroupEx($ad, $entries[0]['memberof'][$i], $groupdn)) { return TRUE; };
};
};
return
FALSE;
}

?>
up
10
oscar dot php at linaresdigital dot com
9 years ago
There is a lot of confusion about accountExpires, pwdLastSet, lastLogon and badPasswordTime active directory fields.

All of them are using "Interval" date/time format with a value that represents the number of 100-nanosecond intervals since January 1, 1601 (UTC, and a value of 0 or 0x7FFFFFFFFFFFFFFF, 9223372036854775807, indicates that the account never expires): https://msdn.microsoft.com/en-us/library/ms675098(v=vs.85).aspx

So if you need to translate it from/to UNIX timestamp you can easily calculate the difference with:

<?php
$datetime1
= new DateTime('1601-01-01');
$datetime2 = new DateTime('1970-01-01');
$interval = $datetime1->diff($datetime2);
echo (
$interval->days * 24 * 60 * 60) . " seconds\n";
?>

The difference between both dates is 11644473600 seconds. Don't rely on floating point calculations nor other numbers that probably were calculated badly (including time zone or something similar).

Now you can convert from LDAP field:

<?php
$lastlogon
= $info[$i]['lastlogon'][0];
// divide by 10.000.000 to get seconds from 100-nanosecond intervals
$winInterval = round($lastlogon / 10000000);
// substract seconds from 1601-01-01 -> 1970-01-01
$unixTimestamp = ($winInterval - 11644473600);
// show date/time in local time zone
echo date("Y-m-d H:i:s", $unixTimestamp) ."\n";
?>

Hope it helps.
up
3
maykelsb at yahoo dot com dot br
17 years ago
Problems with ldap_search in W2k3, can be solved adding

// -- $conn is a valid ldap connection.

ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION,3);
ldap_set_option($conn, LDAP_OPT_REFERRALS,0);

before ldap_bind, as sad in http://bugs.php.net/bug.php?id=30670.
up
3
gcathell at thetdgroup dot com
18 years ago
I recently had to access a Microsoft Active Directory server as an LDAP service over SSL using PHP. It took me a long time to get all the information I needed to get it to work.

I attempted to post a note here with the details but it ended it being too long. I've placed the details at the following URL in hopes that someone else will benefit and will be able to solve the problem much more quickly than I did.

http://greg.cathell.net/php_ldap_ssl.html

Good luck!
up
4
spam2004 at turniton dot dk
19 years ago
Here are two small functions that enables you to convert a binary objectSID from Microsoft AD into a more usefull text version (formatted (S-1-5.....)).

// Converts a little-endian hex-number to one, that 'hexdec' can convert
function littleEndian($hex) {
for ($x=strlen($hex)-2; $x >= 0; $x=$x-2) {
$result .= substr($hex,$x,2);
}
return $result;
}

// Returns the textual SID
function binSIDtoText($binsid) {
$hex_sid=bin2hex($binsid);
$rev = hexdec(substr($hex_sid,0,2)); // Get revision-part of SID
$subcount = hexdec(substr($hex_sid,2,2)); // Get count of sub-auth entries
$auth = hexdec(substr($hex_sid,4,12)); // SECURITY_NT_AUTHORITY
$result = "$rev-$auth";
for ($x=0;$x < $subcount; $x++) {
$subauth[$x] = hexdec(littleEndian(substr($hex_sid,16+($x*8),8))); // get all SECURITY_NT_AUTHORITY
$result .= "-".$subauth[$x];
}
return $result;
}

echo binSIDtoText($bin_sid);
up
1
hijinio at comcast dot net
19 years ago
In case anybody has trouble configuring PHP with LDAP support on a Solaris 10 box, here is the configure line I used:

./configure --with-nsapi=/opt/SUNWwbsvr --enable-libgcc --disable-libxml --with-ldap=/usr/local --prefix=/opt/php/php-5.0.4

The important part to note is the location used for --with-ldap= ; which for most S10 people, will be "--with-ldap=/usr/local".
up
1
Richie Bartlett(at)ITsystems-Online com
19 years ago
This is an update to <i>wtfo at technocraft dot com</i> (23-May-2002 03:40)... This function allows additional (optional) parameters. The prev function listed, failed to close the ldap connection after successful authenication.

<?php
function checkNTuser($username,$password,$DomainName="myDomain",
$ldap_server="ldap://PDC.example.net"){//v0.9
// returns true when user/pass enable bind to LDAP (Windows 2k).
$auth_user=$username."@".$DomainName;
#echo $auth_user."->";
if($connect=@ldap_connect($ldap_server)){
#echo "connection ($ldap_server): ";
if($bind=@ldap_bind($connect, $auth_user, $password)){
#echo "true <BR>";
@ldap_close($connect);
return(
true);
}
//if bound to ldap
}//if connected to ldap
#echo "failed <BR>";
@ldap_close($connect);
return(
false);
}
//end function checkNTuser
?>
up
1
ant at solace dot mh dot se
20 years ago
When working with LDAP, its worth remembering that the majority
of LDAP servers encode their strings as UTF-8. What this means
for non ascii strings is that you will need to use the utf8_encode and
utf8_decode functions when creating filters for the LDAP server.

Of course, if you can its simpler to just avoid using non-ascii characters
but for most sites the users like to see their strange native character
sets including umlauts etc..

If you just get ? characters where you are expecting non-ascii, then
you might just need to upgrade your PHP version.
up
2
christopherbyrne at hotmail dot com
19 years ago
For anyone who's been having trouble working with the "accountexpires" attribute in Active Directory after having read the following article

www.microsoft.com/technet/scriptcenter/
resources/qanda/sept05/hey0902.mspx

or something similar, this may save you some frustration. In the article is is mentioned that this attribute is an integer representing the number of nanoseconds since 01-Jan-1601 00:00:00.

However the "accountexpires" attribute actually seems to be the number of 100 nanosecond increments since 31-Dec-1600 14:00:00. As a result if you divide the integer by 10,000,000 and subtract 11644560000 you will get a Unix timestamp that will match the dates in AD.

To set the "accountexpires" date just reverse the procedure, that is, get the timestamp for the new date you want, add 11644560000 and multiply by 10,000,000. You will also need to format the resultant number to make sure it is not outputted in scientific notation for AD to be happy with it.

Hope this helps!
up
2
llurovi at gmail dot com
8 years ago
For those of you that are having trouble when user's password has special characters, make sure you decode the string to an appropiate codification. For instance, I had an issue where some users could not logging properly into our web app.

Example of a simple connection:

<?php

$ldap_ip
= 'LDAP-SERVER-IP';
$ldap = ldap_connect($ldap_ip);

$user = 'Test';
$password = 'otoño'; //This password is correct but binding it with this format will give us an error

$password = utf8_decode($password); //$password = otoxF1o

$ldap_bind = ldap_bind($ldap, $user, $password); //Now the binding is successfull and $ldap_bind = true

?>
up
2
unroar at gmail dot com
17 years ago
In Solaris 9 the libnet library is a prerequisite for building PHP with LDAP, SASL and SSL (libnet is available on Sunfreeware).

I didn't see this mentioned anywhere and I'm not sure if it is required by ldap or sasl or ssl. I just spent an hour on Google with no luck before I figured it out, maybe this comment will help the next googler.

The error is,
ld: fatal: library -lnet: not found
ld: fatal: File processing errors. No output written to sapi/cli/php
collect2: ld returned 1 exit status
make: *** [sapi/cli/php] Error 1