使用C#查找递归组成员(活动目录)递归、组成员、目录

2023-09-02 10:19:34 作者:冷风浮

我希望得到所有用户是在Active Directory中的成员的组,无论是在的memberOf属性列表中明确列出,以及隐含在嵌套组成员的名单。举例来说,如果我检查用户A和用户A是组A和组B的一部分,我也想列出C组,如果组B是C组中的一员。

I am looking to get a list of all of the groups that a user is a member of in Active Directory, both explicitly listed in the memberOf property list as well as implicitly through nested group membership. For example, if I examine UserA and UserA is a part of GroupA and GroupB, I also want to list GroupC if GroupB is a member of GroupC.

要给你一点更深入地了解我的申请,我将有限制地这样做。基本上,我希望有一个安全检查偶尔会列出这些附加的成员。我将要区分这两种但这应该不难。

To give you a bit more insight into my application, I will be doing this on a limited basis. Basically, I want a security check occasionally that will list these additional memberships. I will want to differentiate the two but that shouldn't be hard.

我的问题是,我还没有找到一个有效的方法,使这个查询工作。在活动目录(这$ C $的CProject文章)的标准文本显示的方式做这一点,基本上是一个递归查询。这似乎是非常低效的。即使在我小的领域,用户可能有30多个组成员。这意味着30+调用到Active Directory的一个用户。

My problem is that I have not found an efficient way to make this query work. The standard text on Active Directory (This CodeProject Article) shows a way to do this that is basically a recursive lookup. That seems terribly inefficient. Even in my small domain, a user might have 30+ group memberships. That means 30+ calls to Active Directory for one user.

我已经研究过以下LDAP code得到所有的memberOf条目一次:

I've looked into the following LDAP code to get all of the memberOf entries at once:

(memberOf:1.2.840.113556.1.4.1941:={0})

{0}将是我的LDAP路径(例如:CN =用户​​A,OU =用户,DC = foo,那么DC = ORG)。然而,它不返回任何记录。这种方法的缺点,即使它的工作,将是我不知道哪组明确的,哪些是隐含的。

where {0} would be my LDAP path (ex: CN=UserA,OU=Users,DC=foo,DC=org). However, it does not return any records. The downside of this method, even if it worked, would be that I wouldn't know which group was explicit and which was implicit.

这是我到目前为止所。我想知道是否有比$ C $的CProject文章更好的方式,如果是这样,如何​​可以完成(实际code将是美好的)。我使用.NET 4.0和C#。我的Active Directory是在Windows 2008功能级别(它不是R2还)。

That is what I have so far. I would like to know if there is a better way than the CodeProject article and, if so, how that could be accomplished (actual code would be wonderful). I am using .NET 4.0 and C#. My Active Directory is at a Windows 2008 functional level (it isn't R2 yet).

推荐答案

渴感谢,一个有趣的问题。

Thirst thanks for this an interesting question.

接下来,只是修正,你说:

Next, just a correction, you say :

我已经研究过以下LDAP code得到所有的memberOf条目一次:

I've looked into the following LDAP code to get all of the memberOf entries at once:

(memberOf:1.2.840.113556.1.4.1941:={0})

您不能使其工作。我记得我做它的工作,当我得知它的存在,但它是在LDIFDE.EXE过滤器。所以我将它应用于ADSI在C#中,它仍然工作。有样,我从微软花了太多的括号,但它的工作(的源AD搜索过滤语法)。

You don't make it work. I remember I make it work when I learnt about its existence, but it was in an LDIFDE.EXE filter. So I apply it to ADSI in C# and it's still working. There were too much parenthesis in the sample I took from Microsoft, but it was working (source in AD Search Filter Syntax).

根据你有关的事实,我们不知道,如果用户明确地属于I组添加一个要求的话。我知道这是不是很好,但它是最好的我'abable做。

According to your remark concerning the fact that we don't know if a user explicitly belongs to the group I add one more request. I know this is not very good, but it's the best I'am abable to do.

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();
}

在我的测试中,这一给予:

In my test tree this give :

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的工作。我presume它同样与W2K3 R2。它应该工作在W2K8。我测试这里W2K8R2。我很快就可以在W2K8测试。

(edited) '1.2.840.113556.1.4.1941' is not working in W2K3 SP1, it begins to work with SP2. I presume it's the same with W2K3 R2. It's supposed to work on W2K8. I test here with W2K8R2. I'll soon be able to test this on W2K8.