递归查询LDAP组成员资格

时间:2011-10-19 19:24:08

标签: c# asp.net-mvc-3 ldap

我正在编写一个基于MVC(.NET 4.0)的网站,该网站需要我公司LDAP服务器的登录凭据。我的代码需要的是仅允许属于某个组的用户。例如,我可能正在寻找属于“企业IT”小组的用户。我的凭据可能是“系统管理员”组的一部分,该组是“企业IT”的子组。我正在使用表单身份验证。

如何以递归方式检查用户登录时所在的群组?

4 个答案:

答案 0 :(得分:6)

对于搜索此类查询的其他人来说,以下是我在应用程序中的操作方式:

密钥是1.2.840.113556.1.4.1941扩展搜索过滤器。由于此特定过滤器仅适用于DN,因此我首先获取要检查的用户的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;
        }
}

答案 1 :(得分:3)

我发现将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));
    }

}

答案 2 :(得分:1)

如果要检查特定用户的成员身份,请绑定到相关AD对象并检索tokenGroups属性。它包含二进制形式的所有直接和间接组成员资格 - 它是一个字节数组的数组。每个字节数组都可以传递给SecurityIdentifier类的构造函数,然后转换为NTAccount,其中包含以明文形式显示的组的名称。

var sids = new IdentityReferenceCollection();
foreach (byte[] group in tokenGroups)
{
    sids.Add(new SecurityIdentifier(group, 0));
}
var accounts = sids.Translate(typeof(NTAccount));

答案 3 :(得分:0)

这是一个完全不同的解决方案。测试并在我的域上工作。一些注意事项:您必须正确使用DirectorySearcher.Filter。为AD层次结构添加多个OU(按相反顺序,自下而上)。还要注意,为了安全起见,我在“using”语句中处理了一些对象,因为它们实现了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
        }
    }