【问题标题】:DirectoryEntry.Invoke("groups",null) not retrieving all groups?DirectoryEntry.Invoke("groups",null) 没有检索所有组?
【发布时间】:2009-08-12 03:09:43
【问题描述】:

我创建了一个 WCF Web 服务来从 Active Directory 返回用户和组信息。它适用于大多数组和用户。

我使用 directoryEntry.Invoke("groups",null) 返回指定用户所属的组。这将返回 MOST 组。奇怪的是,我可以找到任何组并枚举其成员,即使它是我在其成员之一上使用调用查询时丢失的组之一。

大多数表现出这种行为的组都启用了 Exchange。大多数有问题的用户帐户是针对联合域中的用户的,这些用户在我查询的域中使用 Exchange 服务器。我不是在尝试查询联合域中的对象。

到目前为止我的理论:

  • 某些安全限制不允许通过 invoke() 枚举所有组,即使我可以查询丢失的组并枚举其成员。

  • invoke 的某些组子集存在问题。也许通用、动态或支持 Exchange 的属性正在发挥作用

  • invoke 方法不会选择所有组,因为除了将 sid 映射回其登录域之外,“联合”帐户(作为其 Exchange 帐户设置的一部分创建)在某种程度上不同于常规域帐户。

【问题讨论】:

    标签: c# windows active-directory active-directory-group


    【解决方案1】:

    在 DirectoryEntry 上使用“组”属性存在两个已知问题:

    • 它不会显示用户所在的“默认组”(通常是“用户”)
    • 它不会显示嵌套组成员身份

    因此,如果用户是组 A 的成员,而该组又是组 B 的成员,那么在 Windows 中,这意味着该用户也是组 B 的成员。但是,DirectoryEntry 不会显示给您嵌套组成员资格。

    这是我所知道的对于直接 Active Directory(没有 Exchange)的唯一两个限制。

    获取默认组有点复杂,但我确实有一个代码示例。

    private string GetPrimaryGroup(DirectoryEntry aEntry, DirectoryEntry aDomainEntry)
    {
       int primaryGroupID = (int)aEntry.Properties["primaryGroupID"].Value;
       byte[] objectSid = (byte[])aEntry.Properties["objectSid"].Value;
    
       StringBuilder escapedGroupSid = new StringBuilder();
    
       // Copy over everything but the last four bytes(sub-authority)
       // Doing so gives us the RID of the domain
       for(uint i = 0; i < objectSid.Length - 4; i++)
       {
            escapedGroupSid.AppendFormat("\\{0:x2}", objectSid[i]);
       }
    
       //Add the primaryGroupID to the escape string to build the SID of the primaryGroup
       for(uint i = 0; i < 4; i++)
       {
           escapedGroupSid.AppendFormat("\\{0:x2}", (primaryGroupID & 0xFF));
           primaryGroupID >>= 8;
       }
    
       //Search the directory for a group with this SID
       DirectorySearcher searcher = new DirectorySearcher();
       if(aDomainEntry != null)
       {
          searcher.SearchRoot = aDomainEntry;
       }
    
       searcher.Filter = "(&(objectCategory=Group)(objectSID=" + escapedGroupSid.ToString() + "))";
       searcher.PropertiesToLoad.Add("distinguishedName");
    
       return searcher.FindOne().Properties["distinguishedName"][0].ToString();
    }
    

    获取嵌套组也需要几个步骤,如果这是问题,我将不得不寻找解决方案。

    马克

    PS:附带说明 - 你到底为什么要调用“DirectoryEntry.Invoke("groups", null)"?为什么不直接枚举 DirectoryEntry.Properties["memberOf"] 属性,该属性是多值(包含多个值)并在其中包含组的 DN(可分辨名称)?

    foreach(string groupDN in myUser.Properties["memberOf"])
    {
      string groupName = groupDN;
    }
    

    或者,如果您使用的是 .NET 3.5,则可以使用 S.DS.AccountManagement 中的新安全主体类。其中之一是“UserPrincipal”,它有一个名为“GetAuthorizationGroups()”的方法,可以为您完成所有这些艰苦的工作——基本上是免费的!

    请参阅出色的 MSDN article,它为您描述了这些新的 .NET 3.5 S.DS 功能。

    【讨论】:

    • 这些都是很好的建议,你对 MSDN 文章的看法是正确的,我应该在开始之前阅读它。关于我为什么使用调用方法,在这种情况下,我只需要组名,这似乎是获取信息的有效方法。我还没有针对 Active Directory 进行太多编程,所以我仍在学习如何进行的最佳方法。有趣的是,自 1.1 以来 .NET 在该领域的发展程度!
    • 完全没有问题 - 只是好奇您是否有特殊原因使用 Invoke() 方法。嘿 - 这就是 StackOverflow 的全部意义所在 - 当你只见树木不见森林时为你提供帮助 :-)
    【解决方案2】:

    我认为 marc_s 是正确的。如果想要所有组,可以使用下面的sn-p:

    using (DirectoryEntry obj = new DirectoryEntry("LDAP://" + dn))
    {
        obj.RefreshCache(new string[] { "tokenGroups" });
        string[] sids = new string[obj.Properties["tokenGroups"].Count];
        int i = 0;
        foreach (byte[] bytes in obj.Properties["tokenGroups"])
        {
            sids[i] = _ConvertSidToString(bytes);
            ++i;
        }
        obj.Close();
        return sids;
    }
    

    请注意,计算嵌套组是一项昂贵的操作,因此 RefreshCache 可能需要很长时间才能完成。

    【讨论】:

      【解决方案3】:

      关于弗氏,

      我正在尝试使用您的代码,但并没有走得太远。我已将目录条目路径更新为 "LDAP://DC=myDomain,DC=co,DC=uk" 但我没有得到任何结果 (obj.Properties["tokenGroups"].Count = 0)

      我不明白如何指定要为其列出组的用户。

      你能指出我正确的方向吗?

      谢谢

      编辑:

      最后我把它整理好了。从中获取令牌组的目录条目应该是用户条目...如果有意义的话...

      我已经包含了一些代码,以防其他人有相同的查询:

      Dim directoryEntry As DirectoryEntry = _
            New DirectoryEntry("LDAP://CN=users,DC=domanName,DC=com")
      Dim directorySearcher As DirectorySearcher = _
            New DirectorySearcher(directoryEntry, "(sAMAccountName=" & UserName & ")")
      Dim searchResult As SearchResult = directorySearcher.FindOne()
      
      If Not searchResult Is Nothing Then
          Dim userDirectoryEntry As DirectoryEntry = searchResult.GetDirectoryEntry
          userDirectoryEntry.RefreshCache(New String() {"tokenGroups"})
          ... etc ...
      End If
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-18
        • 1970-01-01
        • 2012-02-23
        • 2012-08-09
        • 2021-04-13
        • 1970-01-01
        相关资源
        最近更新 更多