我有一个使用ActiveDirecotry授权的应用程序,并且已经决定它需要支持嵌套的AD组,例如:
MAIN_AD_GROUP
|
|-> SUB_GROUP
|
|-> User
因此,的用户直接 MAIN_AD_GROUP
的成员。我希望能够递归地查找用户,搜索嵌套在MAIN_AD_GROUP
中的组。
主要问题是我使用的是.NET 3.5,并且.NET 3.5中的System.DirectoryServices.AccountManagement
存在一个错误,因此方法UserPrincipal.IsMemberOf()
不适用于的组超过1500名用户 。所以我不能使用UserPrincipal.IsMemberOf()
而不是,我也无法切换到.NET 4。
我使用以下功能解决了最后一个问题:
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()
仅返回用户所属的组。
如何让它与嵌套组一起使用?
答案 0 :(得分:33)
通过手动迭代PrincipalSearchResult<Principal>
返回的对象,捕获此异常并继续执行以下代码,报告此错误here at Microsoft Connect以及解决此问题的以下代码:
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;
}
}
}
另一种解决方法found here避免使用AccountManagement
类,而是使用System.DirectoryServices
API:
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();
}
}
}
答案 1 :(得分:13)
改为使用UserPrincipal.GetAuthorizationGroups()
- 来自MSDN docs:
此方法搜索所有组 递归地并返回组中的 用户是其成员。该 返回集也可能包括 系统会有的其他组 认为用户是for的成员 授权目的。
由此返回的组 方法可以包括来自a的组 不同的范围和商店比 主要。例如,如果 principal是一个AD DS对象 DN为 “CN = SpecialGroups,DC = Fabrikam的,DC = COM, 返回的集可以包含组 属于的 “CN = NormalGroups,DC = Fabrikam的,DC = COM。
答案 2 :(得分:6)
我知道这是一个旧帖子,但它是谷歌的最佳结果,所以如果这对任何人都有帮助,这就是我提出的使用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;
}
}
答案 3 :(得分:1)
有效的方法是通过使用正确的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;
}
您需要使用AD中的正确值替换YOURDOMAIN和GROUPNAME。
需要加入using System.DirectoryServices;