5

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

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

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

到目前为止我的理论:

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

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

  • 调用方法不会获取所有组,因为“联合”帐户(作为其 Exchange 帐户设置的一部分创建)在某种程度上不同于常规域帐户,而不仅仅是将 sid 映射回其登录域。

4

3 回答 3

7

在 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 文章,该文章为您描述了这些新的 .NET 3.5 S.DS 功能。

于 2009-08-12T04:52:51.523 回答
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
于 2009-08-13T10:37:23.613 回答
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 可能需要很长时间才能完成。

于 2009-08-12T05:05:47.300 回答