当组(如果递归或子组)包含ForeignSecurityPrincipal GroupPrincip

2019-06-25 02:04发布

这与其说是为任何人遇到同样的问题信息的问题。

出现以下错误:

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()

当下面的代码运行和一组或儿童组包含一个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)
                }
            }
        }
    }
}

我提出与微软支持呼叫,他们已经证实这是个问题。 一个错误已经在内部提出,但它并没有被证实是否这将是固定的。

微软提出以下解决方法的代码,但它组,大量因为重复调用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);
            }
        }                 
    }
}

上面的代码可以被修改,以找到造成问题的群体国外安全主体。

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

这是在AD一类对象的表示从外部源(这样另一个林/域或低于“特殊”的帐户之一)安全主体。 该类记录在这里: http://msdn.microsoft.com/en-us/library/cc221858(v=PROT.10).aspx和容器记录在这里: http://msdn.microsoft.com/en -us /库/ cc200915(v = PROT.10).ASPX甲FSP是不是在AD的真实对象,而是一个占位符(指针),其生活在一个不同的,受信任域/森林的对象。 它也可以是“特殊身份”,这是众所周知的帐户一堆谁也归类为FSP的,因为他们的SID的是域SID不同的一个。 例如,匿名身份验证的用户,批次等几个账户如下记载: http://technet.microsoft.com/en-us/library/cc779144(v=WS.10).aspx

Answer 1:

当然这是一个古老的线程,但可能帮助别人。 我用下面的代码块中的解决问题。 委托类公开了一个名为StructuralObjectClass属性,它告诉你什么是主要的AD类。 我用这个来决定对象是否是用户。 该GetMembers(真)递归搜索在groupPrincipal所有嵌套成员的问题。

希望这可以帮助别人。

    List<UserPrincipal> members = new List<UserPrincipal>();
    foreach (var principal in groupPrincipal.GetMembers(true))
    {
        var type = principal.StructuralObjectClass;
        if (type.Contains("user"))
            members.Add((UserPrincipal)principal);
    }

谢谢,R



Answer 2:

该accountmanagement图书馆有许多令人痛心的缺陷,这仅仅是众多的其他...

有一两件事你可以做,使事情稍微快一点会使其在同一时间同时检查组成员和对象类型作为查询的一部分,而不是在循环调整LDAP查询。 老实说,我怀疑这会带来多大的改变,但。

大部分的灵感查询来自如何编写LDAP查询测试,如果用户是一个组的成员? 。

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

注:这是一个未经考验的查询...

如果是运行AccountManagement LDAP查询(我的另一个抱怨)的方式那么这将是你的烦恼的结束,你可以运行查询,并让AccountManagement从那里,但该选项不存在...

根据个人经验,我没有看到任何其他的选择,如果你坚持AccountManagement。 你可以做的是转储AccountManagement和只使用的DirectoryServices。 引擎盖下的所有AccountManagement确实是反正包裹的DirectoryEntry对象,你可以写几个辅助类做类似的事情。



Answer 3:

作为替代方案,您可以使用此代码来获取成员:

var pth = "LDAP://ex.invalid/CN=grpName,OU=Groups,OU=whatever,DC=ex,DC=invalid";
var dirEntry = new DirectoryEntry(pth);
var members = dirEntry.Invoke("Members"); //COM object
foreach (var member in (IEnumerable)members) {
    var userEntry = new DirectoryEntry(member); //member is COM object
    var sid = new SecurityIdentifier((byte[]) userEntry.InvokeGet("objectSid"), 0);
    var typ = typeof(System.Security.Principal.NTAccount);
    var account = (NTAccount)sid.Translate(typ);
    Console.WriteLine(account.Value);
}


文章来源: GroupPrincipal.GetMembers fails when group (or child group if recursive) contains ForeignSecurityPrincipal