Finding Active Directory user’s group membership in C#

Hi there,

there are a couple of ways to programmatically find a user and groups he belongs to in Active Directory. Recently I tested a few of them and here are some thoughts of what I found out.

DirectorySearcher

The System.DirectoryServices namespace provides us with a DirectorySearcher class. Filter property of that class can be used in order to specify the search query on the entire directory. An example filter for a user with login name ‘lkarolak’ could look like this:

(&(objectClass=user)(SAMAccountName=lkarolak))

If search is successful, the FindOne() method of the DirectorySearcher class should return an object of type DirectoryEntry. Finding this object’s membership requires iterating through its properties, finding the ones with name ‘memberOf’, and then (if needed) also performing some recursion in order to find out the nested group membership. After all, a bit complicated and quite resource-costly.

SearchRequest

Similar approach could be to use the SearchRequest and SearchResponse objects (this time from System.DirectoryServices.Protocols namespace), which are executed within a LDAP connection. The filter for the query looks just as in the previous example. Also in this case one has to recursively search within the result class’ (SearchResultEntry) attributes in order to get all the user’s nested groups.

Here’s a small example:

// establish a connection to LDAP
LdapDirectoryIdentifier id = new LdapDirectoryIdentifier(domain, port);
LdapConnection _connection = new LdapConnection(id);
_connection.SessionOptions.SecureSocketLayer = secureConnection;
_connection.AuthType = AuthType.Basic;
_connection.Credential = new NetworkCredential(ldapUser, ldapPassword);
_connection.Bind();

// distinguished name of the object 
// at which to start the search.
String _target = "dc=EXAMPLE,dc=COM";

String filter = "(&(objectCategory=person)(SAMAccountName=lkarolak))";
String[] attributesToReturn = { "SAMAccountName", "memberOf", "cn" };

SearchRequest searchRequest = new SearchRequest(_target, filter,
      SearchScope.Subtree, attributesToReturn);
SearchResponse response =
      (SearchResponse)_connection.SendRequest(searchRequest);

if (response.Entries.Count == 1)
{
  SearchResultEntry entry = response.Entries[0];
  for (int index = 0; index < entry.Attributes["memberOf"].Count; index++)
  {
      // get the group name, for example:
      String groupName = entry.Attributes["memberOf"][index].ToString();
  }
}

GroupPrincipal

The most interesting and straightforward solution to me was, however, another approach. Within the namespace System.DirectoryServices.AccountManagement we can find an easy way to find a user in AD and check his group memberships. Without having to recursively loop over the parent groups, we’re able to fetch the groups of the user, an much more data. The only constraint is that the code has to be run on a machine that is located within the domain. Let’s have a look at this sample code:

// "company" is the domain we would like to search in
PrincipalContext pc = new PrincipalContext(ContextType.Domain, "COMPANY");

// get the user of that domain by his username, within the context
UserPrincipal up = UserPrincipal.FindByIdentity(pc, username);

// fetch the group list
PrincipalSearchResult groups = up.GetAuthorizationGroups();
GroupPrincipal[] filteredGroups = (from p in groups
           where p.ContextType == ContextType.Domain
           && p.Guid != null
           && p is GroupPrincipal
           && ((GroupPrincipal)p).GroupScope == GroupScope.Universal
           select p as GroupPrincipal).ToArray();

The last lines actually do the trick. The GetAuthorizationGroups() method would fetch all the security groups of the user. If we would also like to have the distribution groups of the user, we’d have to use the GetGroups() method instead. Of course one could want to filter out some groups, like “Everyone” etc., maybe with help of a LINQ query like here, or in another way.
Anyway, the GroupPrincipal object returned contains the properties we need in order to get the name of the groups of a user (first of all, the DistinguishedName property).

After some unit tests done, it seems also that this last method is the fastest approach of those three mentioned here, probably also due to lack of recursive functions.

Hope this helps,
Łukasz

About these ads

~ by Łukasz on 17 November 2010.

17 Responses to “Finding Active Directory user’s group membership in C#”

  1. Its really helpful for me. Your are just briliant…

  2. Thanks for the using System.DirectoryServices.AccountManagement; example!! Had to figure some part out myself but I finally got it.

  3. PrincipalSearchResult groups = up.GetAuthorization();

    Thanks…

    I was using the “memberOf” property but Microsoft seems to have removed that in Windows 2008 Domain Controllers…

  4. PrincipalSearchResult(LT)Principal(GT) groups = up.GetAuthorization();

    (LT) =

    LMAO….
    Thanks Again…

  5. Stupid HTML Tags…

  6. Just one question, I’ve tried all of this and more but cannot get any domain local groups from other domains.

    Case in point, I belong to 238 groups in our forest. Our forest has a number of domains based on region so I belong to one Universal group and three domain local groups in the Southwest domain but my account is in the Northwest domain. The code only returns the one Universal group from the Southwest domain.

    I’m told this is by design from Microsoft and have yet to hear of a solution.

    Thanks,

    Ron

  7. [...] you’re using the membership provider’s methods in codebehind, in this blog post you’ll find the explanation on how to fetch the needed properties of an Active Directory user [...]

  8. Thanks it worked for me !!!

  9. Long lasting batteries are also very common and
    they allow the user to continue typing even long after the
    electric connection has been cut. The Android operating-system this phone uses is capable of doing supporting
    several gamers that may play both Mp3 and Mp4 format files.
    You can also view images of towns and cities in a fairly elaborate manner.

  10. This is awesome. I can’t thank you enough.

    Merry Christmas

    Happy New Year

  11. Hi, i think that i saw you visited my weblog so i came to “return
    the favor”.I am trying to find things to enhance my web site!
    I suppose its ok to use some of your ideas!!

  12. Hey guys,

    What do I have to write instead of COMPANY if I want to search the entire directory?

    PrincipalContext pc = new PrincipalContext(ContextType.Domain, “COMPANY”);

    THX
    Dan

    • Hi Dan, I think it should be the name of the company’s active directory domain.
      Lukasz

      • It didn’t work with that, but I found a solution, looking like this:

        PrincipalContext pc = new PrincipalContext(ContextType.Domain, “COMPANY:3268”, “DC=company,DC=com”);

  13. There is a faster way to get recursive group membership using the System.DirectoryServices.AccountManagement namespace.

    PrincipalContext domainContext = new PrincipalContext(ContextType.Domain,”domain.com”);

    GroupPrincipal gp = GroupPrincipal.FindByIdentity(domainContext, “adgroup”);
    UserPrincipal aUser = UserPrincipal.FindByIdentity(domainContext, IdentityType.Name, “user1″);

    bool isingroup = gp.GetMembers(true).Contains(aUser);

    For me, the total time required to get the group principal, the user principal and then use the GetMembers(true) function was under a second whereas using the approach proposed was taking 4 or more seconds more.

    Hope that helps.

  14. […] http://lkarolak.wordpress.com/2010/11/17/finding-active-directory-users-group-membership-in-c/ […]

  15. […] Here is the url: Finding active directory properties for a specific user. […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: