Using LDAP functions to get Active Directory tokenGroups attribute in PHP

11,065

Solved my own problem and thought I'd put the answer here so that others might find it. The issue was using the ldap_search() function. The answer was to use the ldap_read() function instead of ldap_search(). The difference is the scope of the request. The search function uses a scope of "sub" (i.e., subtree) while the read function uses "base." The tokenGroups information can only be found when using a scope of "base" so using the correct PHP function was the key.

As I mentioned above, I was working from someone else code in perl to create my solution and the perl script used a function named "search" to do it's LDAP requests which lead me down wrong path.

Thanks to those who took a peek at the question!

--

As per the requests in the comments, here's the basics of the solution in code. I'm extracting from an object that I use so this might not be 100% but it'll be close. Also, variables not declared in this snipped (e.g. $server, $user, $password) are for you to figure out; I won't know your AD credentials anyway!

$ldap = ldap_connect($server);
ldap_bind($ldap, $user, $password);
$tokengroups = ldap_read($ldap, $dn, "CN=*", array("tokengroups")));
$tokengroups = ldap_get_entries($ldap, $tokengroups);

At this point, $tokengroups is our results as an array. it should have count index as well as some other information. To extract the actual groups, you'll need to do something like this:

$groups = array();
if($tokengroups["count"] > 0) {
    $groups = $tokengroups[0]["tokengroups"];
    unset($groups["count"]);

    // if you want the SID's for your groups, you can stop here.
    // if you want to decode the SID's then you can do something like this.
    // the sid_decode() here: http://www.php.net/manual/en/function.unpack.php#72591

    foreach($groups as $i => &$sid) {
        $sid = sid_decode($sid);

        $sid_dn = ldap_read($ldap, "<SID=$sid>", "CN=*", array("dn"));
        if($sid_dn !== false) {
            $group = ldap_get_entries($ldap, $sid_dn);
            $group = $group["count"] == 1 ? $group[0]["dn"] : NULL;
            $groups[$i] = $group;
        }
    }
}

That's the basics. There's one caveat: you'll probably need to work with the individual or individuals who manage AD accounts at your organization. The first time I tried to get this running (a few years ago, so my memory is somewhat fuzzy) the account that I was given did not have the appropriate authorization to access the token groups information. I'm sure there are other ways to do this, but because I was porting someone else's code for this specific solution, this was how I did it.

Share:
11,065
Dash
Author by

Dash

I'm a professional web application developer working for a major US public university.

Updated on July 22, 2022

Comments

  • Dash
    Dash almost 2 years

    Greetings,

    I already have a working connection to the AD and can search and retrieve information from it. I've even developed a recursive method by which one can retrieve all groups for a given user. However, I'd like to avoid the recursion if possible. One way to do this is to get the tokenGroups attribute from the AD for the user, which should be a list of the SIDs for the groups that the specified user has membership, whether that membership be direct or indirect.

    When I run a search for a user's AD information, though, the tokenGroups attribute isn't even in it. I tried specifically requesting that information (i.e., specifying it using the fourth parameter to ldap_search) but that didn't work, either.

    Thanks, David Kees