C# 如何在ActiveDirectory和.NET3.5中确定用户所属的所有组(包括嵌套组)
我有一个使用ActiveDirectry授权的应用程序,并且已经决定它需要支持嵌套的广告组,例如:C# 如何在ActiveDirectory和.NET3.5中确定用户所属的所有组(包括嵌套组),c#,.net-3.5,active-directory,directoryservices,C#,.net 3.5,Active Directory,Directoryservices,我有一个使用ActiveDirectry授权的应用程序,并且已经决定它需要支持嵌套的广告组,例如: MAIN_AD_GROUP | |-> SUB_GROUP | |-> User 因此,用户不能直接成为MAIN\u AD\u组的成员。我希望能够递归地查找用户,搜索嵌套在MAIN\u AD\u GROUP中的组 主要问题是,我使用的是.NET 3.5,而.NET 3.5中的System.Directory
MAIN_AD_GROUP
|
|-> SUB_GROUP
|
|-> User
因此,用户不能直接成为MAIN\u AD\u组的成员。我希望能够递归地查找用户,搜索嵌套在MAIN\u AD\u GROUP
中的组
主要问题是,我使用的是.NET 3.5,而.NET 3.5中的System.DirectoryServices.AccountManagement
中存在一个bug,因此UserPrincipal.IsMemberOf()方法将无法用于用户数超过1500的组。所以我不能使用UserPrincipal.IsMemberOf()
,也不能切换到.NET4
我使用以下函数解决了最后一个问题:
private bool IsMember(Principal userPrincipal, Principal groupPrincipal)
{
using (var groups = userPrincipal.GetGroups())
{
var isMember = groups.Any(g =>
g.DistinguishedName == groupPrincipal.DistinguishedName);
return isMember;
}
}
但是userPrincipal.GetGroups()
只返回用户是其直接成员的组
如何使其与嵌套组一起工作?使用UserPrincipal.GetAuthorizationGroups()
,而不是从其:
此方法搜索所有组
递归地并返回
用户是其中的一个成员。这个
返回的集合还可能包括
该系统将支持的其他组
考虑用户的成员
授权目的
此操作返回的组
方法可以包括来自
不同于
校长。例如,如果
主体是一个具有
一群
“CN=SpecialGroup,DC=Fabrikam,DC=com,
返回的集合可以包含组
属于
“CN=NormalGroups,DC=Fabrikam,DC=com
解决办法#1
通过手动迭代PrincipalSearchResult
返回的对象,捕获此异常并继续,报告此错误以及以下解决此问题的代码:
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;
}
}
}
有效的方法是通过使用正确的DirectorySearcher筛选器来执行单个AD查询,例如:
public bool CheckMemberShip(string userName)
{
bool membership = false;
string connection = "LDAP://"+YOURDOMAIN;
DirectoryEntry entry = new DirectoryEntry(connection);
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = "(&(objectClass=user)(memberOf:1.2.840.113556.1.4.1941:=cn=GROUPNAME,OU=Groups,OU=ABC,OU=ABC,OU=IND,DC=ad,DC=COMPANY,DC=com)(|(sAMAccountName=" + userName + ")))";
SearchResult result = mySearcher.FindOne();
// No search result, hence no membership
if (result == null)
{
membership = false;
}
entry.Close();
entry.Dispose();
mySearcher.Dispose();
membership = true;
return membership;
}
你需要用广告中正确的值替换域名和组名
资料来源:
需要包括使用System.DirectoryServices的代码>我知道这是一个旧的线程,但它是Google上的最高结果,因此,如果这对任何人都有帮助,下面是我使用AccountManagement的东西得出的结论,但它使这个特定的查询更容易
public static class AccountManagementExtensions
{
public static bool IsNestedMemberOf(this Principal principal, GroupPrincipal group)
{
// LDAP Query for memberOf Nested
var filter = String.Format("(&(sAMAccountName={0})(memberOf:1.2.840.113556.1.4.1941:={1}))",
principal.SamAccountName,
group.DistinguishedName
);
var searcher = new DirectorySearcher(filter);
var result = searcher.FindOne();
return result != null;
}
}
谢谢,但不幸的是,这会引发一个PrincipalOperationException
异常,并显示消息“服务器上没有这样的对象”。UserPrincipal肯定存在,因为我上面的方法确实返回顶级组的正确授权。UserPrincipal.GetAuthorizationGroups()
如果存在用户仍然是其成员的已删除组,则会被阻塞。只需检查组名是否不为空,在这种情况下@jprochI选择实施变通办法#2。YMMV的解决方案#1.好帖子。解决方案#1在iterGroup.MoveNext()上失败,并出现相同的错误“服务器上没有此类对象”。只有当程序从登录到域的计算机上运行时,解决方案2才能工作。如果您从其他域查询ldap,则无法使用它。@Kiquenet&@Ronen看起来您可以为DirectoryEntry domainConnection
使用另一个构造函数来传递在不同域上有效的用户名和密码。请参阅:我编辑了答案以包含一行可用于连接到远程域的代码:DirectoryEntry domainConnection=newdirectoryEntry(“LDAP://example.com”、“username”、“password”);/使用此选项查询远程域
此原样回答将始终返回true(假设返回前的行中有一个membership=true)
public static class AccountManagementExtensions
{
public static bool IsNestedMemberOf(this Principal principal, GroupPrincipal group)
{
// LDAP Query for memberOf Nested
var filter = String.Format("(&(sAMAccountName={0})(memberOf:1.2.840.113556.1.4.1941:={1}))",
principal.SamAccountName,
group.DistinguishedName
);
var searcher = new DirectorySearcher(filter);
var result = searcher.FindOne();
return result != null;
}
}