2

I need to find all users that are members of two groups (GroupA and GroupB). I also need to take into account nested groups. What is the best way to do this?

I know that doing an ldap search using memberOf does not take into account nested groups. I could also locate the two groups specifically, get a list of members, and iterate through them, matching up ones that are members of both lists, but the members collection of a group doesn't take into account nested groups either. Are there any methods that do work with nested groups, or do I need to write my own recursive logic?

Edit Nested group: If I have a security group called GroupA. GroupA can have members which are either users or other groups. GroupB is what I am calling a 'nested group' if it is a member of GroupA.

Jeremy
  • 44,950
  • 68
  • 206
  • 332
  • Please define 'nested groups'. – Till Jun 23 '11 at 16:58
  • Sorry, 'Nested group' is probably my own term, so I've added a description of what that is... – Jeremy Jun 23 '11 at 18:39
  • This is very similar to my unanswered question http://stackoverflow.com/questions/4430567/handling-nested-group-permisions-asp-net-role-provider – Peter Jun 23 '11 at 18:43

3 Answers3

2

Here is something working in an ActiveDirectory 2003 ans 2008 R2. I use Microsoft LDAP_MATCHING_RULE_IN_CHAIN to :

1) Search recursively (but in one query) all the users from the first group (be careful it return users from security and distributions group)

2) For each user from the first query, I again search recursively (but in one query) if the user belongs to the second group.

static void Main(string[] args)
{
  //Connection to Active Directory
  string sFromWhere = "LDAP://SRVENTR2:389/dc=societe,dc=fr";
  DirectoryEntry deBase = new DirectoryEntry(sFromWhere, "societe\\administrateur", "test.2011");

  // To find all the users member of groups "Grp1"  :
  // Set the base to the groups container DN; for example root DN (dc=societe,dc=fr) 
  // Set the scope to subtree
  // Use the following filter :
  // (member:1.2.840.113556.1.4.1941:=CN=Grp1,OU=MonOu,DC=X)
  //
  DirectorySearcher dsLookFor = new DirectorySearcher(deBase);
  dsLookFor.Filter = "(&(memberof:1.2.840.113556.1.4.1941:=CN=Grp1,OU=MonOu,DC=societe,DC=fr)(objectCategory=user))";
  dsLookFor.SearchScope = SearchScope.Subtree;
  dsLookFor.PropertiesToLoad.Add("cn");

  SearchResultCollection srcUsers = dsLookFor.FindAll();

  // Just to know if user is present in an other group
  foreach (SearchResult srcUser in srcUsers)
  {
    Console.WriteLine("{0}", srcUser.Path);

    // To check if a user "user1" is a member of group "group1".
    // Set the base to the user DN (cn=user1, cn=users, dc=x)
    // Set the scope to base
    // Use the following filter :
    // (memberof:1.2.840.113556.1.4.1941:=(cn=Group1,OU=groupsOU,DC=x))
    DirectoryEntry deBaseUsr = new DirectoryEntry(srcUser.Path, "societe\\administrateur", "test.2011");
    DirectorySearcher dsVerify = new DirectorySearcher(deBaseUsr);
    dsVerify.Filter = "(memberof:1.2.840.113556.1.4.1941:=CN=Grp3,OU=MonOu,DC=societe,DC=fr)";
    dsVerify.SearchScope = SearchScope.Base;
    dsVerify.PropertiesToLoad.Add("cn");

    SearchResult srcTheUser = dsVerify.FindOne();

    if (srcTheUser != null)
    {
      Console.WriteLine("Bingo {0}", srcTheUser.Path);
    }
  }
  Console.ReadLine();
}
JPBlanc
  • 70,406
  • 17
  • 130
  • 175
0

I don't know of any way to do this except via recursion. Get the group membership for group a. Loop through the list, if item is a user add to second list, if item is a group then perform recursion.

Peter
  • 9,643
  • 6
  • 61
  • 108
0

Is there a requirement that you use ldap search to do this? The WindowsPrincipal.IsInRole() method will test for membership both directly and via a nested group - at least it did for the test I ran.

This code tests the current thread's identity against GroupA and GroupB but you could use a similar approach to enumerate the members of GroupA and then test each of those against GroupB by calling IsInRole...

AppDomain myDomain = Thread.GetDomain();

myDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

WindowsPrincipal myPrincipal = (WindowsPrincipal)Thread.CurrentPrincipal;

NTAccount groupA = new NTAccount("Domain\\GroupA");

SecurityIdentifier sidGroupA = (SecurityIdentifier)groupA.Translate(typeof(SecurityIdentifier));

bool inGroupA = myPrincipal.IsInRole(sidGroupA);

NTAccount groupB = new NTAccount("Domain\\GroupB");

SecurityIdentifier sidGroupB = (SecurityIdentifier)groupB.Translate(typeof(SecurityIdentifier));

bool inGroupB = myPrincipal.IsInRole(sidGroupB);

Console.WriteLine("{0}, {1}", groupA, inGroupA);

Console.WriteLine("{0}, {1}", groupB, inGroupB);

Console.ReadLine();
Frank Boyne
  • 4,400
  • 23
  • 30
  • I don't think this will work in my situtation because I'm not interested in if the current user is in both groups, I'm interested in testing if any selected account chosen by the current user is in both groups. – Jeremy Jun 24 '11 at 15:35
  • Don't get too hung up on the sample code, that's just there to let you quickly check that the code does what I think it does with your GroupA and GroupB. In your situation you would enumerate the members of group A (or group B), create a Windows Principal for each of those users and then call principal.IsInRole against group B (or group A if you originally enumerated group B). You know the principal in question is a member of the group you enumerated. The IsInRole call will tell you whether it is in the other group and that tells you what you want to know. – Frank Boyne Jun 24 '11 at 17:46