为什么 Principal.IsMemberOf() 对某些组返回误报

本文关键字:返回 Principal IsMemberOf 为什么 | 更新日期: 2023-09-27 18:30:55

为什么Principal.IsMemberOf(GroupPrincipal) (MSDN) 在下面的测试中返回Domain Computers组的误报?

[TestMethod]
public void DomainComputerTest()
{
    var distinguishedName = "CN=MyMachine,DC=SomeDomain,DC=local";
    using( var pc = new PrincipalContext( ContextType.Domain, "SomeDomain.local", "UserName", "Password" ) )
    using( var computer = ComputerPrincipal.FindByIdentity( pc, IdentityType.DistinguishedName, distinguishedName ) )
    {
        Assert.IsNotNull( computer );
        // Get the groups for the computer.
        var groups = computer.GetGroups().Cast<GroupPrincipal>();
        foreach( var group in groups )
        {
            // Immediately turn around and test that the computer is a member of the groups it returned.
            Assert.IsTrue( computer.IsMemberOf( group ), "Computer is not member of group {0}", group.Name );
        }
    }
}

结果消息:断言.IsTrue 失败。计算机不是"域计算机"组的成员

计算机确实是"域计算机"组的成员,"GetGroups()"方法正确返回了该组。实际上,如果尝试将计算机添加到组中,则会引发 PrincipalExistsException。

我可以重现与用户和"域用户"组完全相同的行为。这是因为组是主体组吗?是因为这些是"默认"组吗?

编辑以添加:我们使用的是 .NET 4.5.1。

为什么 Principal.IsMemberOf() 对某些组返回误报

这似乎是一个一直存在的问题。

我发现的同一个问题的每一个问题都没有答案。我找不到任何说这是作为错误提交的,但似乎自 .NET 3.5 以来就存在了。

我试图让你的例子返回true(当然,将信息更改为我的工作领域)。无论如何,它都返回了false.在dotPeek中反编译Principal类只产生了猜测。在完成并设置Visual Studio以允许单步进入.NET框架代码之后,这是一个失败,因为它不会步入必要的方法。我可以单步执行其他 .NET 框架代码,但Principal上没有任何内容。不确定这是否与标记为SecurityCriticalAttribute的方法有关。希望确认这一点。

我给你的建议是将其作为一个错误提交,同时采取不同的路线来确定计算机是否是成员。在我的测试中,group.Members确实包含计算机。

我在运行 .NET 3.5、4.0、4.5、4.5.1 时遇到了同样的问题

以下是一些参考资料:

解决方法 -- GroupPrincipal.IsMemberOf 总是返回 false

2010 MSDN 博客条目,其中包含与您具有相同问题的注释。

注意:我通常不会这样回答,但是因为我发现这个问题的每个问题都有0个答案或解决方法,我认为未来的读者实际看到关于这个问题的某种"答案"将是有益的。

对于其他发现这一点的开发人员,这是我最终所做的。这是我部署的代码的简化版本,但总而言之,我假设问题是主要组关系。这可能不正确,但它现在对我们有用。

您可以获取此类ComputerPrincipalDirectoryEntry实例。

var entry = (DirectoryEntry)computerPrincipal.GetUnderlyingObject();

我正在使用这种扩展方法来检查主要组关系。

public static bool IsPrimaryGroupFor( this GroupPrincipal group, DirectoryEntry target )
{
    // .Value will return an int like "123", which is the last part of the group's SID
    var id = target.Properties[ "primaryGroupID" ].Value.ToString();
    // strip the account domain SID from the group SID.
    var groupId = group.Sid.Value.Remove( 0, group.Sid.AccountDomainSid.Value.Length + 1 );
    // If the 
    return id.Equals( groupId, StringComparison.OrdinalIgnoreCase );
}

我们正在同步 AD 组成员身份,因此我们在类似于以下内容的代码中发现了此问题;

public void AddComputerToGroups( ComputerPrincipal computer, ICollection<GroupPrincipal> groups )
{
    var directoryEntry = (DirectoryEntry)computer.GetUnderlyingObject();
    foreach( var principal in groups.Where(g=> !computer.IsMemberOf(g) )
    {
        principal.Members.Add( computer );
        principal.Save(); // Exception thrown because computer already existed in the primary group.
    }
}

如果您要测试的组成员过多,也会发生这种情况。IsMemberOf 似乎只检查前 1000 个左右的条目。要绕过这种情况,请检查是否分组。成员包含用户/计算机。

因此,我相信您可能会遇到与我在这里相同的问题,但针对的是计算机帐户而不是用户帐户。

Principal.IsInRole("AD 组名称") 始终返回 false,不引发异常

验证执行代码的帐户是否对导致错误/遇到问题的计算机注册到的域中的ComputersUsers容器具有读取权限。