【问题标题】:GroupPrincipal.GetMembers fails when group (or child group if recursive) contains ForeignSecurityPrincipal当组(或递归的子组)包含 ForeignSecurityPrincipal 时 GroupPrincipal.GetMembers 失败
【发布时间】:2012-06-01 16:23:02
【问题描述】:

这不是一个问题,而是为遇到同样问题的人提供的信息。

出现以下错误:

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

我向 Microsoft 拨打了支持电话,他们已确认这是一个问题。内部提出了一个错误,但尚未确认是否会修复。

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);
            }
        }                 
    }
}

上面的代码可以修改,以找到导致组问题的外部安全主体。

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

这是 AD 中的一类对象,它代表来自外部来源的安全主体(即另一个林/域或下面的“特殊”帐户之一)。 该课程记录在这里:http://msdn.microsoft.com/en-us/library/cc221858(v=PROT.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

【问题讨论】:

  • 你有没有机会尝试我的答案?还是您采取了替代路线?
  • 您知道此错误是否已在较新的 .net 框架版本中得到修复?

标签: c# active-directory directoryservices


【解决方案1】:

当然这是一个旧线程,但可能会对某人有所帮助。我使用下面的代码块来解决问题。 Principal 类公开了一个名为 StructuralObjectClass 的属性,它告诉您该主体的 AD 类是什么。我用它来确定对象是否是用户。 GetMembers(true) 递归搜索相关 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);
    }

谢谢, 回复

【讨论】:

  • 如果groupPrincipal.GetMembers() 计数为 0,foreach 将失败。
【解决方案2】:

accountmanagement 库有许多令人痛心的缺陷,这只是众多缺陷中的另一个......

您可以做的事情稍微加快一点,那就是调整您的 LDAP 查询,以便它同时检查组成员资格和对象类型作为查询的一部分,而不是在循环中。老实说,我怀疑它会产生很大的不同。

查询的大部分灵感来自How to write LDAP query to test if user is member of a group?

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

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

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

根据个人经验,如果您坚持使用 AccountManagement,我看不到任何其他选项。您可以做的是转储 AccountManagement 并仅使用 DirectoryServices。无论如何,AccountManagement 所做的一切都是包装 DirectoryEntry 对象,您可以编写一些帮助类来做类似的事情。

【讨论】:

  • 非常感谢彼得。尚未尝试您的建议。
【解决方案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);
}

【讨论】:

  • 你这个无名英雄。这是多年来唯一有效的解决方案!
猜你喜欢
  • 1970-01-01
  • 2019-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-18
  • 2017-05-14
  • 2015-12-27
  • 1970-01-01
相关资源
最近更新 更多