Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine all the groups a user belongs to (including nested groups) in ActiveDirectory and .NET 3.5

Tags:

I have an application that uses ActiveDirecotry authorisation and it has been decided that it needs to support nested AD groups, e.g.:

MAIN_AD_GROUP      |      |-> SUB_GROUP               |                |-> User 

So, the user in not directly a member of MAIN_AD_GROUP. I'd like to be able to look for the user recursively, searching the groups nested in MAIN_AD_GROUP.

The main problem is that I'm using .NET 3.5 and there is a bug in System.DirectoryServices.AccountManagement in .NET 3.5 whereby the method UserPrincipal.IsMemberOf() will not work for groups with more than 1500 users. So I can't use UserPrincipal.IsMemberOf() and no, I can't switch to .NET 4 either.

I've worked around this last problem with the following function:

private bool IsMember(Principal userPrincipal, Principal groupPrincipal) {     using (var groups = userPrincipal.GetGroups())     {         var isMember = groups.Any(g =>              g.DistinguishedName == groupPrincipal.DistinguishedName);         return isMember;     } } 

But userPrincipal.GetGroups() only returns the groups of which the user is a direct member.

How can I get this to work with nested groups?

like image 658
Sergi Papaseit Avatar asked Mar 15 '11 13:03

Sergi Papaseit


People also ask

How do I check my nested group membership?

We can get group members by using the Active Directory PowerShell cmdlet Get-ADGroupMember. The Get-ADGroupMember cmdlet provides the option to get all the nested group members by passing the parameter -Recursive.

How do I find out who a user belongs to an ad group?

You can check group membership with the Active Directory Users and Computers (ADUC) console snap-in by finding the user or group of interest and drilling down into the object's properties and clicking the “Members” or “Member Of” tab.

What is a nested group in Active Directory?

What is group nesting? AD group nesting, simply put, is the process of putting one group inside another group. Nested groups inherit the permissions and privileges of the group they are put under, and hence this makes privilege administration easier.


1 Answers

Workaround #1

This bug is reported here at Microsoft Connect along with the following code that works around this issue by manually iterating through the PrincipalSearchResult<Principal> returned objects, catching this exception, and continuing on:

PrincipalSearchResult<Principal> groups = user.GetAuthorizationGroups(); var iterGroup = groups.GetEnumerator(); using (iterGroup) {     while (iterGroup.MoveNext())     {         try         {             Principal p = iterGroup.Current;             Console.WriteLine(p.Name);         }         catch (NoMatchingPrincipalException pex)         {             continue;         }     } } 

Workaround #2

Another workaround found here avoids the AccountManagement class, and uses the System.DirectoryServices API instead:

using System;   using System.Collections.Generic;   using System.Linq;   using System.Text;   using System.DirectoryServices;    namespace GetGroupsForADUser   {       class Program       {           static void Main(string[] args)           {               String username = "Gabriel";                List<string> userNestedMembership = new List<string>();                DirectoryEntry domainConnection = new DirectoryEntry(); // Use this to query the default domain             //DirectoryEntry domainConnection = new DirectoryEntry("LDAP://example.com", "username", "password"); // Use this to query a remote domain              DirectorySearcher samSearcher = new DirectorySearcher();                samSearcher.SearchRoot = domainConnection;               samSearcher.Filter = "(samAccountName=" + username + ")";               samSearcher.PropertiesToLoad.Add("displayName");                SearchResult samResult = samSearcher.FindOne();                if (samResult != null)               {                   DirectoryEntry theUser = samResult.GetDirectoryEntry();                   theUser.RefreshCache(new string[] { "tokenGroups" });                    foreach (byte[] resultBytes in theUser.Properties["tokenGroups"])                   {                       System.Security.Principal.SecurityIdentifier mySID = new System.Security.Principal.SecurityIdentifier(resultBytes, 0);                        DirectorySearcher sidSearcher = new DirectorySearcher();                        sidSearcher.SearchRoot = domainConnection;                       sidSearcher.Filter = "(objectSid=" + mySID.Value + ")";                       sidSearcher.PropertiesToLoad.Add("distinguishedName");                        SearchResult sidResult = sidSearcher.FindOne();                        if (sidResult != null)                       {                           userNestedMembership.Add((string)sidResult.Properties["distinguishedName"][0]);                       }                   }                    foreach (string myEntry in userNestedMembership)                   {                       Console.WriteLine(myEntry);                   }                }               else              {                   Console.WriteLine("The user doesn't exist");               }                Console.ReadKey();            }       }   }   
like image 144
Tim Lewis Avatar answered Sep 17 '22 22:09

Tim Lewis