DirectoryEntry.Invoke(“groups”,null)没有检索所有组?

时间:2009-08-12 03:09:44

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

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

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

展示此行为的大多数组都启用了Exchange。大多数有问题的用户帐户都是针对联合域中的用户,他们在我查询的域中使用Exchange服务器。我不是在尝试查询联邦域中的对象。

到目前为止我的理论:

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

  • invoke与某些子组有问题。也许通用,动态或启用Exchange的属性正在发挥作用

  • 调用方法不会获取所有组,因为“联合”帐户(作为其Exchange帐户设置的一部分创建)与sid映射回登录域之外的常规域帐户有所不同。

3 个答案:

答案 0 :(得分:6)

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

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

因此,如果用户是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)”调用?为什么不直接枚举多值(包含多个值)并且包含组的DN(可分辨名称)的DirectoryEntry.Properties [“memberOf”]属性?

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功能。

答案 1 :(得分:0)

我认为marc_s是正确的。如果您想要所有群组,可以使用以下代码段:

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可能需要很长时间才能完成。

答案 2 :(得分:0)

弗雷德,

我正在尝试使用您的代码而不是走得太远。我已将目录条目路径更新为“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