How to get user groups in Active Directory? (C #, asp.net)

I use this code to get the groups of the current user. But I want to manually give the user and then get his groups. How can i do this?

using System.Security.Principal; public ArrayList Groups() { ArrayList groups = new ArrayList(); foreach (IdentityReference group in System.Web.HttpContext.Current.Request.LogonUserIdentity.Groups) { groups.Add(group.Translate(typeof(NTAccount)).ToString()); } return groups; } 
+84
c # active-directory
Mar 15 '11 at 9:50
source share
5 answers

If you are using .NET 3.5 or higher, you can use the new System.DirectoryServices.AccountManagement (S.DS.AM) namespace, which makes this a lot easier than before.

Read more about this here: Guide for Security Managers in the .NET Framework 3.5

Update: old MSDN magazine articles are no longer online, you unfortunately need to download the CHM for January 2008 Microsoft's MSDN magazine and read the article there.

Basically, you need to have a โ€œmain contextโ€ (usually your domain), a user principle, and then you easily get its groups:

 public List<GroupPrincipal> GetGroups(string userName) { List<GroupPrincipal> result = new List<GroupPrincipal>(); // establish domain context PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain); // find your user UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, userName); // if found - grab its groups if(user != null) { PrincipalSearchResult<Principal> groups = user.GetAuthorizationGroups(); // iterate over all groups foreach(Principal p in groups) { // make sure to add only group principals if(p is GroupPrincipal) { result.Add((GroupPrincipal)p); } } } return result; } 

and that everything is there! Now you have the result (list) of authorization groups to which the user belongs - sort them, print their names or whatever you need to do.

Update. To access certain properties that are not displayed on the UserPrincipal object, you need to search the underlying DirectoryEntry :

 public string GetDepartment(Principal principal) { string result = string.Empty; DirectoryEntry de = (principal.GetUnderlyingObject() as DirectoryEntry); if (de != null) { if (de.Properties.Contains("department")) { result = de.Properties["department"][0].ToString(); } } return result; } 

Update # 2: It doesn't seem to be too hard to put these two pieces of code together ... but fine - here it is:

 public string GetDepartment(string username) { string result = string.Empty; // if you do repeated domain access, you might want to do this *once* outside this method, // and pass it in as a second parameter! PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain); // find the user UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, username); // if user is found if(user != null) { // get DirectoryEntry underlying it DirectoryEntry de = (user.GetUnderlyingObject() as DirectoryEntry); if (de != null) { if (de.Properties.Contains("department")) { result = de.Properties["department"][0].ToString(); } } } return result; } 
+132
Mar 15 '11 at 10:22
source share

GetAuthorizationGroups() does not find nested groups. To really get all the groups, this user is a member (including nested groups), try the following:

 using System.Security.Principal private List<string> GetGroups(string userName) { List<string> result = new List<string>(); WindowsIdentity wi = new WindowsIdentity(userName); foreach (IdentityReference group in wi.Groups) { try { result.Add(group.Translate(typeof(NTAccount)).ToString()); } catch (Exception ex) { } } result.Sort(); return result; } 

I use try/catch because I had some exceptions from 2 out of 200 groups in very large AD, because some SIDs were no longer available. (A call to Translate() converts SID -> Name.)

+44
Oct. 16 '13 at 14:03
source share

First of all, GetAuthorizationGroups () is a great feature, but unfortunately it has 2 drawbacks:

  • Performance is poor, especially in a large company with many users and groups. It retrieves a lot more data than you really need, and makes a server call for each iteration of the loop as a result.
  • It contains errors that can cause your application to stop working "sometime" when groups and users develop. Microsoft has recognized the problem and is associated with some SIDs. The error you get is "An error occurred while listing groups"

So I wrote a little function to replace GetAuthorizationGroups () with better performance and security. It only makes 1 LDAP call with a query using indexed fields. It can be easily extended if you need more properties than just group names (cn property).

 // Usage: GetAdGroupsForUser2("domain\user") or GetAdGroupsForUser2("user","domain") public static List<string> GetAdGroupsForUser2(string userName, string domainName = null) { var result = new List<string>(); if (userName.Contains('\\') || userName.Contains('/')) { domainName = userName.Split(new char[] { '\\', '/' })[0]; userName = userName.Split(new char[] { '\\', '/' })[1]; } using (PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, domainName)) using (UserPrincipal user = UserPrincipal.FindByIdentity(domainContext, userName)) using (var searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + domainContext.Name))) { searcher.Filter = String.Format("(&(objectCategory=group)(member={0}))", user.DistinguishedName); searcher.SearchScope = SearchScope.Subtree; searcher.PropertiesToLoad.Add("cn"); foreach (SearchResult entry in searcher.FindAll()) if (entry.Properties.Contains("cn")) result.Add(entry.Properties["cn"][0].ToString()); } return result; } 
+10
Apr 07 '16 at 6:50
source share

Within AD, each user has a memberOf property. It contains a list of all groups to which it belongs.

Here is an example of a little code:

 // (replace "part_of_user_name" with some partial user name existing in your AD) var userNameContains = "part_of_user_name"; var identity = WindowsIdentity.GetCurrent().User; var allDomains = Forest.GetCurrentForest().Domains.Cast<Domain>(); var allSearcher = allDomains.Select(domain => { var searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + domain.Name)); // Apply some filter to focus on only some specfic objects searcher.Filter = String.Format("(&(&(objectCategory=person)(objectClass=user)(name=*{0}*)))", userNameContains); return searcher; }); var directoryEntriesFound = allSearcher .SelectMany(searcher => searcher.FindAll() .Cast<SearchResult>() .Select(result => result.GetDirectoryEntry())); var memberOf = directoryEntriesFound.Select(entry => { using (entry) { return new { Name = entry.Name, GroupName = ((object[])entry.Properties["MemberOf"].Value).Select(obj => obj.ToString()) }; } }); foreach (var item in memberOf) { Debug.Print("Name = " + item.Name); Debug.Print("Member of:"); foreach (var groupName in item.GroupName) { Debug.Print(" " + groupName); } Debug.Print(String.Empty); } } 
+9
Mar 15 2018-11-11T00:
source share

In my case, the only way I could use GetGroups () without any exploits was to add the user (USER_WITH_PERMISSION) to a group that has permission to read AD (Active Directory). It is imperative to create a PrincipalContext by passing this user and password.

 var pc = new PrincipalContext(ContextType.Domain, domain, "USER_WITH_PERMISSION", "PASS"); var user = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, userName); var groups = user.GetGroups(); 

The steps you can follow in Active Directory to get it working:

  • In the Active Directory, create a group (or take it), and on the secutiry tab, add "Windows Authorization Access Group"
  • Click the Advanced button
  • Select "Windows Authorization Access Group" and click "View"
  • Check "Reading TokensGroupsGlobalAndUniversal"
  • Find the right user and add to the group created (taken) from the first step.
+1
Jan 28 '16 at 11:25
source share



All Articles