问题描述
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?
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();
}
}
}
这篇关于如何在 ActiveDirectory 和 .NET 3.5 中确定用户所属的所有组(包括嵌套组)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!