DirectoryEntry.Invoke ("groups", null) does not retrieve all groups?

I created a WCF web service to return user and group information from Active Directory. It works for most groups and users.

I use directoryEntry.Invoke ("groups", null) to return the groups to which the specified user belongs. This returns the MOST groups. It is strange that I can find any group and list its members, even if it is one of the groups that are missing when I use the invoke query for one of my members.

Most groups that exhibit this behavior support Exchange. Most problematic user accounts are for users in the federated domain who use the Exchange server in the domain I am requesting. I am not trying to request objects in a federated domain.

My theories so far are:

  • some security restriction does not allow listing all groups via invoke (), although I can query for missing groups and list their members.

  • invoke has problems with a subset of groups. Perhaps universal, dynamic, or Exchange-supported properties are in the game

  • the invoke method does not display all groups, because the "federated" accounts (created as part of their Exchange account settings) are somewhat different from regular domain accounts outside of the sid mapping back to their login domain.

+4
source share
3 answers

There are two known problems using the "Groups" property in DirectoryEntry:

  • it will not show you the "default group" in which the user is located (usually "users").
  • he will not show you membership in nested groups

So, if a user is a member of group A, and this group, in turn, is a member of group B, then on Windows this means that the user is also a member of group B. However, DirectoryEntry will not show you this nested membership in the group.

These are the two limitations that I know for direct Active Directory (without Exchange).

Getting the default group is a bit tied up, but for this I have some sample code.

private string GetPrimaryGroup(DirectoryEntry aEntry, DirectoryEntry aDomainEntry) { int primaryGroupID = (int)aEntry.Properties["primaryGroupID"].Value; byte[] objectSid = (byte[])aEntry.Properties["objectSid"].Value; StringBuilder escapedGroupSid = new StringBuilder(); // Copy over everything but the last four bytes(sub-authority) // Doing so gives us the RID of the domain for(uint i = 0; i < objectSid.Length - 4; i++) { escapedGroupSid.AppendFormat("\\{0:x2}", objectSid[i]); } //Add the primaryGroupID to the escape string to build the SID of the primaryGroup for(uint i = 0; i < 4; i++) { escapedGroupSid.AppendFormat("\\{0:x2}", (primaryGroupID & 0xFF)); primaryGroupID >>= 8; } //Search the directory for a group with this SID DirectorySearcher searcher = new DirectorySearcher(); if(aDomainEntry != null) { searcher.SearchRoot = aDomainEntry; } searcher.Filter = "(&(objectCategory=Group)(objectSID=" + escapedGroupSid.ToString() + "))"; searcher.PropertiesToLoad.Add("distinguishedName"); return searcher.FindOne().Properties["distinguishedName"][0].ToString(); } 

Getting nested groups also takes several steps, and I will have to look for a solution to this if this is a problem.

Mark

PS: as a side note - why are you making a "DirectoryEntry.Invoke (" groups ", null)" call? Why don't you just list the DirectoryEntry.Properties ["memberOf"] property, which is multi-valued (contains multiple values) and has a DN group in it (distinguished name)?

 foreach(string groupDN in myUser.Properties["memberOf"]) { string groupName = groupDN; } 

OR if you are using .NET 3.5, you can use the new security principal classes in S.DS.AccountManagement. One of them is "UserPrincipal", which has the "GetAuthorizationGroups ()" method, which does all this hard work for you - for free, basically!

See the excellent MSDN article that describes these new features in .NET 3.5 S.DS.

+5
source

I think marc_s is correct. If you want all groups, you can use the following snippet:

 using (DirectoryEntry obj = new DirectoryEntry("LDAP://" + dn)) { obj.RefreshCache(new string[] { "tokenGroups" }); string[] sids = new string[obj.Properties["tokenGroups"].Count]; int i = 0; foreach (byte[] bytes in obj.Properties["tokenGroups"]) { sids[i] = _ConvertSidToString(bytes); ++i; } obj.Close(); return sids; } 

Note that calculating nested groups is an expensive operation, so RefreshCache can be time consuming.

0
source

In Freund,

I am trying to use your code and not very far. I updated the directory path, which should be "LDAP: // DC = myDomain, DC = co, DC = uk", but I do not get any results (obj.Properties ["tokenGroups"]. Count = 0)

I do not know how the username for the list is specified.

Could you point me in the right direction?

thanks

EDIT:

In the end, I sorted it. The directory entry for getting marker groups should be a user entry ... if that makes sense ...

I included some code in case someone else has the same request:

 Dim directoryEntry As DirectoryEntry = _ New DirectoryEntry("LDAP://CN=users,DC=domanName,DC=com") Dim directorySearcher As DirectorySearcher = _ New DirectorySearcher(directoryEntry, "(sAMAccountName=" & UserName & ")") Dim searchResult As SearchResult = directorySearcher.FindOne() If Not searchResult Is Nothing Then Dim userDirectoryEntry As DirectoryEntry = searchResult.GetDirectoryEntry userDirectoryEntry.RefreshCache(New String() {"tokenGroups"}) ... etc ... End If 
0
source

All Articles