一尘不染

使用C#查找递归组成员身份(Active Directory)

c#

我正在寻找用户在Active
Directory中所属的所有组的列表,它们都在memberOf属性列表中显式列出,并且通过嵌套的组成员身份隐式列出。例如,如果我检查UserA并且UserA是GroupA和GroupB的一部分,那么如果GroupB是GroupC的成员,我也想列出GroupC。

为了使您对我的应用程序有更多了解,我将在有限的基础上进行此操作。基本上,我偶尔需要进行安全检查,该检查将列出这些其他成员身份。我将要区分两者,但这并不难。

我的问题是我还没有找到一种有效的方法来使此查询工作。Active
Directory上的标准文本(此CodeProject文章)显示了一种执行此操作的方法,该方法基本上是递归查找。这似乎效率极低。即使在我的小型域中,用户也可能拥有30多个组成员身份。这意味着一个用户需要30多个Active
Directory调用。

我研究了以下LDAP代码以一次获取所有memberOf条目:

(memberOf:1.2.840.113556.1.4.1941:={0})

其中{0}是我的LDAP路径(例如:CN = UserA,OU = Users,DC = foo,DC =
org)。但是,它不返回任何记录。即使该方法可行,它的缺点是我不知道哪个组是显式的,哪个组是隐式的。

到目前为止,这就是我所拥有的。我想知道是否有比CodeProject文章更好的方法,如果可以的话,如何实现(实际代码会很棒)。我正在使用.NET
4.0和C#。我的Active Directory处于Windows 2008功能级别(尚不是R2)。


阅读 276

收藏
2020-05-19

共1个答案

一尘不染

谢谢您提出这个有趣的问题。

接下来,只是更正,您说:

我研究了以下LDAP代码以一次获取所有memberOf条目:

(memberOf:1.2.840.113556.1.4.1941:={0})

你没有使它工作。我记得当我了解它的存在时使它起作用,但是它在LDIFDE.EXE筛选器中。因此,我将其应用于C#中的ADSI,并且仍在工作。我从Microsoft那里获得的示例中括号过多,但可以正常工作(来自AD
Search过滤器语法
)。

根据您关于我们不知道用户是否明确属于该组这一事实的说法,我再添加一个请求。我知道这不是很好,但这是我能做的最好的。

static void Main(string[] args)
{
  /* Connection to Active Directory
   */
  DirectoryEntry deBase = new DirectoryEntry("LDAP://WM2008R2ENT:389/dc=dom,dc=fr");


  /* To find all the groups that "user1" is a member of :
   * Set the base to the groups container DN; for example root DN (dc=dom,dc=fr) 
   * Set the scope to subtree
   * Use the following filter :
   * (member:1.2.840.113556.1.4.1941:=cn=user1,cn=users,DC=x)
   */
  DirectorySearcher dsLookFor = new DirectorySearcher(deBase);
  dsLookFor.Filter = "(member:1.2.840.113556.1.4.1941:=CN=user1 Users,OU=MonOu,DC=dom,DC=fr)";
  dsLookFor.SearchScope = SearchScope.Subtree;
  dsLookFor.PropertiesToLoad.Add("cn");

  SearchResultCollection srcGroups = dsLookFor.FindAll();

  /* Just to know if user is explicitly in group
   */
  foreach (SearchResult srcGroup in srcGroups)
  {
    Console.WriteLine("{0}", srcGroup.Path);

    foreach (string property in srcGroup.Properties.PropertyNames)
    {
      Console.WriteLine("\t{0} : {1} ", property, srcGroup.Properties[property][0]);
    }

    DirectoryEntry aGroup = new DirectoryEntry(srcGroup.Path);
    DirectorySearcher dsLookForAMermber = new DirectorySearcher(aGroup);
    dsLookForAMermber.Filter = "(member=CN=user1 Users,OU=MonOu,DC=dom,DC=fr)";
    dsLookForAMermber.SearchScope = SearchScope.Base;
    dsLookForAMermber.PropertiesToLoad.Add("cn");

    SearchResultCollection memberInGroup = dsLookForAMermber.FindAll();
    Console.WriteLine("Find the user {0}", memberInGroup.Count);

  }

  Console.ReadLine();
}

在我的测试树中,这给出了:

LDAP://WM2008R2ENT:389/CN=MonGrpSec,OU=MonOu,DC=dom,DC=fr
adspath : LDAP://WM2008R2ENT:389/CN=MonGrpSec,OU=MonOu,DC=dom,DC=fr
cn : MonGrpSec
Find the user 1

LDAP://WM2008R2ENT:389/CN=MonGrpDis,OU=ForUser1,DC=dom,DC=fr
adspath : LDAP://WM2008R2ENT:389/CN=MonGrpDis,OU=ForUser1,DC=dom,DC=fr
cn : MonGrpDis
Find the user 1

LDAP://WM2008R2ENT:389/CN=MonGrpPlusSec,OU=ForUser1,DC=dom,DC=fr
adspath : LDAP://WM2008R2ENT:389/CN=MonGrpPlusSec,OU=ForUser1,DC=dom,DC=fr
cn : MonGrpPlusSec
Find the user 0

LDAP://WM2008R2ENT:389/CN=MonGrpPlusSecUniv,OU=ForUser1,DC=dom,DC=fr
adspath : LDAP://WM2008R2ENT:389/CN=MonGrpPlusSecUniv,OU=ForUser1,DC=dom,DC=fr
cn : MonGrpPlusSecUniv
Find the user 0

(已编辑)“ 1.2.840.113556.1.4.1941”在W2K3 SP1中不起作用,开始在SP2中起作用。我想与W2K3
R2相同。它应该可以在W2K8上运行。我在这里用W2K8R2进行测试。我很快就能在W2K8上对其进行测试。

2020-05-19