Our Active Directory is structured like so:

-DC=tld
--DC=internal
---OU=Security Groups
---OU=Service Accounts
---OU=Users
---OU=Computers
---OU=RemoteOffice1
---OU=RemoteOffice2
----OU=Users
-----CN=userName1
-----CN=userName2
-----etc
----OU=Security Groups
-----CN=IT
-----CN=Users
-----etc
----OU=Distribution Lists
-----CN=Managers
-----CN=Employee
-----etc
---OU=RemoteOffice3
---OU=RemoteOffice4
---etc

So for LDAP Integration module admin page I enter the following:
Base DN: DC=tld,DC=internal
For LDAP Groups configuration in the "Groups are specified by LDAP attributes" section I place a check mark and enter memberOf. I also check the "Groups exist as LDAP entries where a multivalued attribute contains the members' CNs" and I enter DC=tld,DC=interna. For the "Attribute holding group members:" section I enter member. This all works, for the most part...
When I use the ldapgroups.conf.php to filter and map AD groups to user roles, most map, but some are not.
I thought that was due to my not using the "Group is specified in user's DN" check mark and adding OU to the "Attribute of the DN which contains the group name" section. I tried this because we seem to have all of the situations listed on the LDAP Integration LDAP groups admin page. All of our users are listed in various OUs are listed within sub directories in the remote office OUs. For example, a user's CN could look like so: CN=Jane Doe,OU=Users,OU=RemoteOffice2,DC=tld,DC=internal. This varies from the example on the LDAP Groups admin page which states "Check this option if your users' DNs look like cn=jdoe,ou=Group1,cn=example,cn=com and Group1 turns out to be the group you want." in that our users are down two OUs rather than one. Does the example mean to check this option if there is only one OU within the user's CN, or just if there is a group listed within the user's CN? I tried adding to the ldapgroups.conf.php filter this line'OU=Users,OU,remoteOffice2,OU=tld,DC=internal' => 'RemoteOffice2 Users' but no mappings occurred. Can these be mixed or do I need to stick with getting CNs of Security Groups and Distribution Lists (like this CN=RemoteOffice2,OU=Distribution Lists,OU=RemoteOffice2,DC=tld,DC=internal' => 'RemoteOffice2 Users ) that do work fine?
Thanks

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

kotoponus’s picture

I have bumped into the same problem too... Did anyone find a way to deal with this? I would be grateful if anyone can point me to good posts!

kotoponus’s picture

I ended up writing my own code to deal with this. We use Active Directory with groups associated with a group.

By any means it is not the most refined, but, as far as I can see (given not a lot of testing), it works for our circumstance where the nested groups under a group uses "member" attr. (I guess one can make this to be another parameter.) Hope this would be a use to someone.... Or at least a starting point to someone.

This function returns an array of the groups a user's groups belong to recursively.

// recursively collecting of groups until it does not find anymore
function ldapgroups_detect_group_recur($ldapgroups_ldap,$branch,$entries_groups,$arr_pickstr) {
        foreach ($entries_groups as $gp){
                $member_line[0][] = "member=".$gp;
        }
        $grp_stacker = null;
        $quit = false;
        $level = 0;
        while (!$quit) {
                $result = false;
                $temp_member_line = null;
                $next_level = $level+1;
                $level_result = false;
                // this will be going though every level
                foreach ($member_line[$level] as $ea_member_line) {
                        $entries_g = $ldapgroups_ldap->search($branch,$ea_member_line,$arr_pickstr);
                        if ($entries_g["count"] > 0) {
                                // this level will go thorugh each searching node
                                foreach ($entries_g as $idx => $entry_g) {
                                        if (isset($entry_g["dn"])) {
                                                $grp_stacker[] = $entry_g["dn"];
                                                $member_line[$next_level][] = "member=".$entry_g["dn"];
                                                $result = true;
                                        }
                                }
                                // if there is ever true in the next level, we will proceed.
                                // if everything is false, we come out of while loop.
                        }
                }
                if (!$result) {
                        $quit = true;
                }
                if (isset($member_line[$next_level])) $level++;
                $loopcnt++;
        }
        return $grp_stacker;
}

For instance, I have the following code in function called function _ldapgroups_detect_groups() calling above function ldapgroups_detect_group_recur(). The function generates the additional array to add to $entries_groups. (I use the section 3 here because that is what I use in LDAP group setting.)

  // Strategy 3: groups as entries
  $entries_groups = array();
  if ($groups_as_entries && $branches = $group_entries) {
    $branches_array = explode("\r\n", $branches);
    $group_attr = ($row->ldap_group_entries_attribute ? $row->ldap_group_entries_attribute : LDAP_DEFAULT_GROUP_ENTRIES_ATTRIBUTE);
    foreach ($branches_array as $branch) {
      $entries = $ldapgroups_ldap->search($branch,  "$group_attr=$user->ldap_dn", array($group_attr));
      if ($entries['count'] == 0) {
        $entries = $ldapgroups_ldap->search($branch,  "$group_attr=$user->name", array($group_attr));
      }
      foreach ($entries as $entry) {
        if (isset($entry['dn'])) { 
          $entries_groups[] = $entry['dn'];
        }
      }
      // === start of the custom code ===
      foreach ($branches_array as $branch) {
        $grps = ldapgroups_detect_group_recur($ldapgroups_ldap,$branch,$entries_groups,array("memberof"));
        if (is_array($grps)){
          foreach ($grps as $grp) {
            $entries_groups[] = $grp;
          }
        }
      }
      // === end of  the code ==
    }
mariomaric’s picture

Hm...I solved this problem without any coding, you can read about in How to map AD role to custom named role.

Cheers.

kotoponus’s picture

I am glad your problem resolved that way. I really did not want to have to code either.

I also looked into the way you pointed while I was looking for options, but we really could not afford any resources to manually map groups. As we have many departments and groups, I really do not want to have to amend it manually as the logistics of communicating the organisational changes were a nightmare-ish at our place.

Also, may I suggest a few improvements:

1. When you have a multiple domains to juggle, it would be a good idea to be able to select your domain at the login stage. It seems like other LDAP authenticated applications do something similar like that. This will make the authentication process speedier.

2. I saw this in Confluence, but it would also be a good idea if the groups can be mass populated initially in Drupal. Not at the point to of login. This would allow us to organise the access levels in advance.

These may already be addressed and apologies in advance if I am already circumventing anyone's effort...

claar’s picture

Title: Active Directory groups within groups within groups... Will these map using LDAP Integration Groups? » Support nested groups
Version: 5.x-1.3 » 6.x-1.x-dev
Category: support » feature

Manually setting up role mappings in no way solves the lack of support for LDAP group-in-groups. Someone (me, if I ever find time) needs to take a stab at adapting #2 to 6.x. Also see comment #1 at http://drupal.org/node/143217 for things to think about when implementing this.

claar’s picture

Component: Documentation » Code
claar’s picture

claar’s picture

For anyone needing a temporary solution to add nested groups in 6.x, the code by jipsi in #436962-7: LDAP Groups module does not recurse through AD security group containers to discover nested group members works beautifully with ldapgroups 6.x-1.0-beta2, but you must be using "Strategy 2"/"groups in user attributes".

claar’s picture

I found bugs in jipsi's code referenced in #6 -- it wasn't picking up all nested groups.

The attached patch against 6.x-1.0-beta2 gives better nested group support for "Strategy 2"/"groups in user attributes" (see code).

If someone were to add nested group support for the other two strategies, we'd have full support. This is a handy work-around for now, though.

EDIT: I've already found flaws with this code (doesn't handle infinite recursion) but I'm not certain it's appropriate to fill this ticket with bug fixes. For now I'll do development on this code at http://drupal.org/sandbox/claar/1459160

cgmonroe’s picture

Status: Active » Postponed

FYI - The current dev includes support for a hook to alter / add groups detected. See, hook_ldap_user_groups_alter() in the ldapgroups.api.php file. So, rather than trying to maintain a branched version of ldap integration, you can create now create a separate module to support recursive groups.

For full details of what's new see: #1475272: 6.x-1.0 Release Candidate 1 Status

Marking this as postponed since it can be handled with an external module now and the effort to make a generically useful version part of ldap integration seems to be more than the demand for it. But if someone wants to create a patch....

kenorb’s picture

Status: Postponed » Closed (outdated)
Related issues: +#1475272: 6.x-1.0 Release Candidate 1 Status

The 6.x most likely is not supported anymore. Feel free to re-open for 7.x