Progress is going very well with the ldap plugin. But we found that when we start bringing in other ldap serves to test, some of the shortcuts that worked for M$ did not work so well with other ldap servers. To that end, I wrote another proof of concept code using the long way to get a user’s ldap attributes. In this method I have to use an authorized read only user to query the ldap server to locate the user’s ldap account, then I use that ldap account to relogin to the ldap server to pick up the user’s group associations.
<?php
// the user we are going to authenticate
$user = 'user1234';
$pass = 'Password';
// IP address or fqdn of ldap server
$server = '192.168.1.5';
// credentials that have read access to the LDAP server
$bindDN = 'cn=Bob Jones,ou=Users,ou=nyc,dc=domain,dc=com';
$bindPass = 'Password.2';
// How deep in ldap from search base are we going to look for the user
$searchScope = 2;
// clean up user name we only want the user's short name without any domain component
// note I did not try to understand the regex expression but I expect there to be
// issues with non-us english characters, just saying.
$user = trim(preg_replace('/[^a-zA-Z0-9\-\_@\.]/', '', $user));
// open connection to the server
$ldapconn = ldap_connect($server,389);
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0);
$accessLevel = 0;
$userSearchDN = 'ou=nyc,dc=domain,dc=com';
$adminGroup = 'FoG_Admins';
$userGroup = 'FOG_Users';
$grpMemberAttr = strtolower('memberOf');
if ( ldap_bind($ldapconn, $bindDN, $bindPass) ) {
// for the filter we are searching for a person with an NT style account like the contents of $user
$filter = sprintf('(&(objectCategory=inetOrgPerson)(%s=%s))', 'sAMAccountName', $user);
// we want to return the user's DN so that we can bind as the user
// we will get his DN based on his samaccountname for AD
$attr = array( 'dn' );
switch ($searchScope) {
case 1:
// LDAP_SCOPE_ONELEVEL search one level down but not base
$result = ldap_list($ldapconn, $userSearchDN, $filter, $attr);
break;
case 2:
// LDAP_SCOPE_SUBTREE search base + all subtree (OUs) below
$result = ldap_search($ldapconn, $userSearchDN, $filter, $attr);
break;
default:
// LDAP_SCOPE_BASE search base only and don't look any deeper
$result = ldap_read($ldapconn, $userSearchDN, $filter, $attr);
}
// count the number of entries returned
$retcount = ldap_count_entries($ldapconn, $result);
if ($retcount == 1) {
// great we only returned one entry
$entries = ldap_get_entries($ldapconn, $result);
// pull out the user dn from the entries
$userDN = $entries[0]['dn'];
} else {
$userDN = '';
}
}
// if user dn is populated then attempt to connect (bind) to ldap as user
if (!$userDN =='') {
// Now rebind as the user we just found
if ( ldap_bind($ldapconn, $userDN, $pass) ) {
// If we get to here the user is authorized, now lets get the group membership
// This time since we know the user DN (fully qualified ldap path) we can look up the user based on that
// this filter just matches all objects (cheat)
$filter = '(objectclass=*)';
// get what groups this user is a member of
$attr = array( $grpMemberAttr );
// read in the attributes of this user
$result = ldap_read($ldapconn, $userDN, $filter, $attr);
// count the number of entries returned
$retcount = ldap_count_entries($ldapconn, $result);
if ($retcount > 0) {
$entries = ldap_get_entries($ldapconn, $result);
// check groups for membership
foreach($entries[0][$grpMemberAttr] as $grps) {
// is admin user, set level and break loop
if(strpos( $grps, $adminGroup )) { $accessLevel = 2; break; }
// is user, set level and keep looking just incase user is in both groups
if(strpos( $grps, $userGroup )) $accessLevel = 1;
}
}
// close our connection as bindDN
ldap_unbind( $ldapconn );
echo $accessLevel;
} else {
print 'unable to bind using user info, user is not authorized in ldap';
}
} else {
echo 'User not found in LDAP';
}
?>