C# 递归查询LDAP组成员资格
我正在编写一个基于MVC的(.NET 4.0)网站,它需要来自公司LDAP服务器的登录凭据。我的代码要求只允许属于某个组的用户。例如,我可能正在寻找属于“企业IT”组的用户。我的凭证可以是“系统管理员”组的一部分,该组是“公司IT”的一个子组。我正在使用表单身份验证C# 递归查询LDAP组成员资格,c#,asp.net-mvc-3,ldap,C#,Asp.net Mvc 3,Ldap,我正在编写一个基于MVC的(.NET 4.0)网站,它需要来自公司LDAP服务器的登录凭据。我的代码要求只允许属于某个组的用户。例如,我可能正在寻找属于“企业IT”组的用户。我的凭证可以是“系统管理员”组的一部分,该组是“公司IT”的一个子组。我正在使用表单身份验证 当用户登录时,我如何递归地检查他们属于哪个组?如果要检查特定用户的成员身份,请绑定到相关的AD对象并检索属性。它包含二进制形式的所有直接和间接组成员身份-它是一个字节数组数组。可以将每个字节数组传递给SecurityIdentifi
当用户登录时,我如何递归地检查他们属于哪个组?如果要检查特定用户的成员身份,请绑定到相关的AD对象并检索属性。它包含二进制形式的所有直接和间接组成员身份-它是一个字节数组数组。可以将每个字节数组传递给SecurityIdentifier类的构造函数,然后将其转换为包含明文中组名称的NTAccount
var sids = new IdentityReferenceCollection();
foreach (byte[] group in tokenGroups)
{
sids.Add(new SecurityIdentifier(group, 0));
}
var accounts = sids.Translate(typeof(NTAccount));
这里有一个完全不同的解决方案。在我的域名上测试和工作。注意:您必须获得DirectorySearcher.Filter正确。为您的广告层次结构添加多个OU(按相反顺序,自底向上)。另外请注意,为了安全起见,我在“使用”语句中处理了一些对象,因为它们实现了System.ComponentModel.Component,而System.ComponentModel.Component反过来又实现了IDisposable。。。所以,安全总比后悔好
public bool IsUserMemberOfGroup(string groupName)
{
// CN is your distro group name. OU is the object(s) in your AD hierarchy. DC is for your domain and domain suffix (e.g., yourDomain.local)
string searchFilter = String.Format(@"(&(objectcategory=user)(sAMAccountName=markp)(memberof=CN={0},OU=System Admins,OU=USA,DC=yourDomain,DC=local))", groupName);
SearchResultCollection searchResult;
using (var dirEntry = new DirectoryEntry("LDAP://dc=yourDomain,dc=local"))
{
using (var dirSearch = new DirectorySearcher(dirEntry))
{
dirSearch.SearchScope = SearchScope.Subtree;
dirSearch.Filter = searchFilter;
searchResult = dirSearch.FindAll();
}
}
if (searchResult.Count <= 0 || searchResult == null) {
return false; // not in group
}
else {
return true; // in group
}
}
public bool IsUserMemberOfGroup(字符串groupName)
{
//CN是您的发行组名称。OU是您的广告层次结构中的对象。DC是您的域和域后缀(例如,yourDomain.local)
string searchFilter=string.Format(@“(&(objectcategory=user)(sAMAccountName=markp)(memberof=CN={0},OU=System Admins,OU=USA,DC=yourDomain,DC=local)),groupName);
SearchResultCollection searchResult;
使用(var dirEntry=newdirectoryEntry(“LDAP://dc=yourDomain,dc=local”))
{
使用(var dirSearch=newdirectorysearcher(dirEntry))
{
dirSearch.SearchScope=SearchScope.Subtree;
dirSearch.Filter=searchFilter;
searchResult=dirSearch.FindAll();
}
}
如果(searchResult.Count对于搜索此类查询而来的任何其他人,我是如何在我的应用程序中执行此操作的:
关键是扩展搜索筛选器。由于此特定筛选器仅适用于DNs,我首先获取要检查的用户的DN,然后查询组,以查看此特定用户是否是链中任何组的成员
internal const string UserNameSearchFilter = "(&(objectCategory=user)(objectClass=user)(|(userPrincipalName={0})(samAccountName={0})))";
internal const string MembershipFilter = "(&(objectCategory=group)(objectClass=group)(cn=MyGroup)(member:1.2.840.113556.1.4.1941:={0}))";
using (var de = new DirectoryEntry(AppSettings.LDAPRootContainer, AppSettings.AdminUser, AppSettings.AdminPassword, AuthenticationTypes.FastBind))
using (var ds = new DirectorySearcher(de) { Filter = string.Format(UserNameSearchFilter, username) })
{
ds.PropertiesToLoad.AddRange(new[] { "distinguishedName" });
var user = ds.FindOne();
if (user != null)
using (var gds = new DirectorySearcher(de) { PropertyNamesOnly = true, Filter = string.Format(MembershipFilter, user.Properties["distinguishedName"][0] as string) })
{
gds.PropertiesToLoad.AddRange(new[] { "objectGuid" });
return gds.FindOne() != null;
}
}
我发现使用带有递归标志的GroupPrincipal.GetMembers
是快速有效的
public bool IsMember(string groupName, string samAccountName)
{
using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
using (UserPrincipal user = UserPrincipal.FindByIdentity(context, samAccountName))
using(GroupPrincipal group = GroupPrincipal.FindByIdentity(context, groupName))
{
return group.GetMembers(true).OfType<Principal>().Any(u => u.SamAccountName.Equals(user.SamAccountName, StringComparison.InvariantCultureIgnoreCase));
}
}
public bool IsMember(字符串groupName,字符串samAccountName)
{
使用(PrincipalContext上下文=新PrincipalContext(ContextType.Domain))
使用(UserPrincipal user=UserPrincipal.FindByIdentity(上下文,samAccountName))
使用(GroupPrincipal组=GroupPrincipal.FindByIdentity(上下文,组名))
{
return group.GetMembers(true).OfType().Any(u=>u.SamAccountName.Equals(user.SamAccountName,StringComparison.InvariantCultureIgnoreCase));
}
}
这项技术有效,但不包括通讯组列表,只包括安全组。如果有人知道如何获取通讯组列表,那就太好了。事实上,我正在寻找组枚举。包含通讯组的组枚举?根据MSDN,GetGroups方法不会执行组成员的递归查找bership,因此它不会返回间接的组成员身份。GetAuthorizationGroups可以进行递归查找,但仅限于安全组,就像我的方法一样。你说得对,Henning。很好。我想这个问题可能有些模糊。@MarkP想得更多,你实际上不需要查看/列出所有组,是吗?你只需要验证用户是否在某个特定(AD发行版)中组。对吗?如果是这样,那是可行的。否则,您将看到递归he*l,或者甚至调用PowerShell。是的,我只需要验证某个用户是否是更大组的一部分。@MarkP完全更改了答案。解决方案现在应该适合您了。@PatrickPitre-此新解决方案将只获得直接组成员身份,since您正在测试memberOf属性。