GroupPrincipal.GetMembers在组(或子组,如果递归)包含ForeignSecurityPrincipal时失败

Sim*_*ane 12 c# directoryservices active-directory

对于遇到同样问题的人来说,这不是一个问题.

发生以下错误:

System.DirectoryServices.AccountManagement.PrincipalOperationException: An error (87) occurred while enumerating the groups. The group's SID could not be resolved. 
at System.DirectoryServices.AccountManagement.SidList.TranslateSids(String target, IntPtr[] pSids) 
at System.DirectoryServices.AccountManagement.SidList.ctor(List`1 sidListByteFormat, String target, NetCred credentials) 
at System.DirectoryServices.AccountManagement.ADDNLinkedAttrSet.TranslateForeignMembers()
Run Code Online (Sandbox Code Playgroud)

运行以下代码并且组或子组包含ForeignSecurityPrincipal时:

private static void GetUsersFromGroup()
{
    var groupDistinguishedName = "CN=IIS_IUSRS,CN=Builtin,DC=Domain,DC=com";
    //NB: Exception thrown during iteration of members rather than call to GetMembers.    
    using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "Domain", "Username", "Password"))
    {
        using (GroupPrincipal groupPrincipal = GroupPrincipal.FindByIdentity(ctx, IdentityType.DistinguishedName, groupDistinguishedName))
        {                    
            using (var searchResults = groupPrincipal.GetMembers(true))//Occurs when false also.
            {
                foreach (UserPrincipal item in searchResults.OfType())
                {
                    Console.WriteLine("Found user: {0}", item.SamAccountName)
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我向微软提出了一个支持电话,他们已经确认这是一个问题.内部已经出现了一个错误,但尚未确定是否会修复此错误.

Microsoft建议使用以下解决方法代码,但由于重复调用UserPrincipal.FindByIdentity,因此对具有大量用户的组执行效果不佳.

class Program
{
    //"CN=IIS_IUSRS,CN=Builtin,DC=dev-sp-sandbox,DC=local"; //TODO MODIFY THIS LINE ACCORDING TO YOUR DC CONFIGURATION

    static void Main(string[] args)
    {
        if (args.Length != 1)
        {
            Console.WriteLine("Usage: ListGroupMembers \"group's DistinguishedName\"");
            Console.WriteLine("Example: ListGroupMembers \"CN=IIS_IUSRS,CN=Builtin,DC=MyDomain,DC=local\"");
            return;
        }

        string groupDistinguishedName = args[0];

        PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "dev-sp-dc", "Administrator", "Corp123!");
        List<UserPrincipal> users = new List<UserPrincipal>();
        listGroupMembers(groupDistinguishedName, ctx, users);

        foreach (UserPrincipal u in users)
        {
            Console.WriteLine(u.DistinguishedName);
        }
    }

    //Recursively list the group's members which are not Foreign Security Principals
    private static void listGroupMembers(string groupDistinguishedName, PrincipalContext ctx, List<UserPrincipal> users)
    {
        DirectoryEntry group = new DirectoryEntry("LDAP://" + groupDistinguishedName);
        foreach (string dn in group.Properties["member"])
        {

            DirectoryEntry gpMemberEntry = new DirectoryEntry("LDAP://" + dn);
            System.DirectoryServices.PropertyCollection userProps = gpMemberEntry.Properties;

            object[] objCls = (userProps["objectClass"].Value) as object[];

            if (objCls.Contains("group"))
                listGroupMembers(userProps["distinguishedName"].Value as string, ctx, users);

            if (!objCls.Contains("foreignSecurityPrincipal"))
            {                    
                UserPrincipal u = UserPrincipal.FindByIdentity(ctx, IdentityType.DistinguishedName, dn);
                if(u!=null)  // u==null for any other types except users
                    users.Add(u);
            }
        }                 
    }
}
Run Code Online (Sandbox Code Playgroud)

可以修改上述代码以查找导致组中出现问题的外部安全主体.

Microsoft提供了有关外部安全主体的以下信息:

这是AD中的一类对象,它表示来自外部源的安全主体(因此另一个林/域或下面的"特殊"帐户之一).该课程在此处记录:http ://msdn.microsoft.com/en-us/library/cc221858(v = PO10.10).aspx此处记录了容器:http://msdn.microsoft.com/en -us/library/cc200915(v = PROT.10).aspx FSP不是AD中的真实对象,而是位于不同的受信任域/林中的对象的占位符(指针).它也可以是一个"特殊身份",它是一群众所周知的帐户,也被归类为FSP,因为它们的SID与域SID不同.例如,匿名,经过身份验证的用户,批处理以及此处记录的其他几个帐户:http: //technet.microsoft.com/en-us/library/cc779144(v = WS.10).aspx

Pet*_*ter 2

帐户管理库有许多令人悲伤的缺陷,这只是众多缺陷中的另一个......

为了使速度稍微快一些,您可以做的一件事是调整您的 LDAP 查询,以便它作为查询的一部分同时检查组成员资格和对象类型,而不是在循环中。老实说,我怀疑这会产生很大的影响。

该查询的大部分灵感来自 如何编写 LDAP 查询来测试用户是否是组的成员?

询问: (&(!objectClass=foreignSecurityPrincipal)(memberof=CN=YourGroup,OU=Users,DC=YourDomain,DC=com))

注意:这是一个未经测试的查询...

如果有一种方法可以在 AccountManagement 中运行 LDAP 查询(我的另一个抱怨),那么这将结束您的麻烦,因为您可以运行查询并让 AccountManagement 从那里获取它,但此选项不存在...

根据个人经验,如果您坚持使用帐户管理,我看不到任何其他选择。您可以做的是转储 AccountManagement 并仅使用 DirectoryServices。无论如何,AccountManagement 所做的所有工作实际上都是包装 DirectoryEntry 对象,您可以编写一些辅助类来执行类似的操作。