Reputation: 85
I have an LDAP authentication system that can find and retrieve the memberOf attribute from AD but I'm not sure how to go about getting nested group memberships. I'm aware of the memberOf:1.2.840.113556.1.4.1941: extension but unsure how to adapt it to my code. My code that is working is below (it just doesn't do nested groups). Can someone with more experience help?
IN CONFIG.PHP
$adbase = "some.domain.com";
$adtree = "OU=All Departments,DC=some,DC=domain,DC=com";
$group_admins = "Test App Admins";
$group_staff = "Test App Staff";
IN RUN.PHP
function extract_unit($string, $start, $end) {
$pos = stripos($string, $start);
$str = substr($string, $pos);
$str_two = substr($str, strlen($start));
$second_pos = stripos($str_two, $end);
$str_three = substr($str_two, 0, $second_pos);
$unit = trim($str_three); // remove whitespaces
return $unit;
}
extract($_POST);
if($action == "logon") {
$ldap = ldap_connect($adbase);
$userID = "$user@$adbase";
$bind = @ldap_bind($ldap, $userID, $pass);
if($bind == true) {
// assign session variables
$_SESSION['username'] = $user;
// get group memberships
$results = ldap_search($ldap, $adtree, "(samaccountname=$user)",array("memberof", "mail"));
$entries = ldap_get_entries($ldap, $results);
// get group count (first entry) and group listings
$beat = 0; $str = ""; foreach($entries[0]['memberof'] as $temp) {
if($beat == 0) {
$count = $temp;
}
else {
$temp = extract_unit($temp, "CN=", ",OU=");
$str .= "$temp, ";
$groups[] = $temp;
}
$beat++;
}
// return the mail address, stackoverflow.com/questions/16224720/searching-for-email-address-ldap-active-directory
$mail = $entries[0]["mail"][0];
// assign session variables
$_SESSION['mail'] = $mail;
// groups defined in config.php
$client = "You are logged in as a client.";
if(in_array($group_admins, $groups)) {
$_SESSION['admin'] = true;
$client = "You are logged in as an administrator.";
}
else {
$_SESSION['admin'] = false;
}
// groups defined in config.php
if(in_array($group_staff, $groups)) {
$_SESSION['staff'] = true;
$client = "You are logged in as staff.";
}
else {
$_SESSION['staff'] = false;
}
// if it returns true user was found
print "<h2>Signed in as $user</h2>\n";
print "$client<br>\n";
print "<img src=\"./images/next.png\"> <a href=\"./?d=welcome\">Continue ...</a>\n";
print "<!-- count is $count -->";
print "<!-- groups are $str -->";
print "<!-- mail is $mail -->";
}
else {
print "<h2>Login attempt failed</h2>\n";
print "<img src=\"./images/logon.png\"> <a href=\"./?d=user/logon\">You may try again ...</a>\n";
}
}
Upvotes: 1
Views: 3616
Reputation: 85
I ended up getting to work but I had to take a different path.
This is the code that I finally got PHP LDAP authentication working, with nested groups. This assumes the username is being checked to see if it exists in a group or nested group. If you take out (samaccountname=$user) then it will return a list of all the users in that group but it will take considerably longer (less than a second to like 30+ seconds).
/*
$adBase like "some.domain.com"
$ldBase like "OU=Users,DC=some,DC=domain,DC=com"
$admins like "CN=Test Admins,OU=Groups"
$staff like "CN=Test Staff,OU=Groups"
$ldaplink like "ldap://ldap.domain.com/o=domain.com??sub?"
*/
$ldap = ldap_connect($adBase);
$bind = @ldap_bind($ldap, "$user@$adBase", $pass);
$admins = $ldAdmin.",".$ldBase;
$staffs = $ldStaff.",".$ldBase;
$filtrA = "(&(objectClass=user)(samaccountname=$user)(memberof:1.2.840.113556.1.4.1941:=$admins))";
$filtrS = "(&(objectClass=user)(samaccountname=$user)(memberof:1.2.840.113556.1.4.1941:=$staffs))";
if($bind) {
// default message if not found in either group
$client = "You are logged in as a client.";
// get basic info first; stackoverflow.com/questions/1622472...
$result = ldap_search($ldap, $ldBase, "(samaccountname=$user)", array("mail"));
$entries = ldap_get_entries($ldap, $result);
$mail = $entries[0]["mail"][0];
$_SESSION['username'] = $user;
$_SESSION['mail'] = $mail;
#region check admin/nested group
$link1A = ldap_search($ldap, $ldBase, $filtrA, array("name"));
$link2A = ldap_get_entries($ldap, $link1A);
@$nameA = $link2A[0]["name"][0]; // throws error if not defined but that's what we're testing thus the @
if($nameA == true) {
// user was found in administrators or in nested group
$_SESSION['admin'] = true;
$client = "You are logged in as an administrator.";
}
else {
$_SESSION['admin'] = false;
}
#endregion
#region check staff/nested group
$link1S = ldap_search($ldap, $ldBase, $filtrS, array("name"));
$link2S = ldap_get_entries($ldap, $link1S);
@$nameS = $link2S[0]["name"][0]; // throws error if not defined but that's what we're testing thus the @
if($nameS == true) {
// user was found in staff or in nested group
$_SESSION['staff'] = true;
$client = "You are logged in as staff.";
}
else {
$_SESSION['staff'] = false;
}
#endregion
// if it returns true user was found
print "<h2>Signed in as $user</h2>\n";
print "$client<br>\n";
print "<img src=\"./images/next.png\"> <a href=\"./?d=tem/welcome\">Continue ...</a>\n";
print "<!-- mail is $mail -->";
}
else {
print "<h2>Login attempt failed</h2>\n";
print "<img src=\"./images/logon.png\"> <a href=\"./?d=user/logon\">You may try again ...</a>\n";
}
Upvotes: 1
Reputation: 11026
You need to construct a query using the EXTENSIBLE MATCH filter syntax similar to:
(memberOf:1.2.840.113556.1.4.1941:=CN=GroupOne,OU=Security Groups,OU=Groups,DC=YOURDOMAIN,DC=NET)
Which RESOLVES ALL MEMBERS (INCLUDING NESTED) SECURITY GROUPS (REQUIRES AT LEAST WINDOWS 2003 SP2)
Upvotes: 0