从受信任的域中将成员添加到 AD 组

Add member to AD group from a trusted domain

我有两个处于信任关系中的域,我正尝试通过 C# Web 应用程序对其进行管理。为此,我必须模拟两个不同的技术用户,但这很好用,所以我不会强调那部分代码。

要为文件系统构建正确且易于管理的 ACL,我必须

如果我从同一个域中添加用户,该代码可以完美运行,所以我相信我在这里只遗漏了一小部分信息。我也使用了 this document as a reference and saw this question(还有一些人引用了这条错误消息),但它们都没有帮助。

代码(删除了 try-catch 块以使其更简单)

// de is a DirectoryEntry object of the AD group, received by the method as a parameter
// first impersonation to search in domainB
// works all right
if (impersonator.impersonateUser("techUser1", "domainB", "pass")) {
    DirectoryEntry dom = new DirectoryEntry("LDAP://domainB.company.com/OU=MyOU,DC=domainB,DC=company,DC=com", "techUser1", "pass");
    de.Invoke("Add", new object[] { "LDAP://domainB.company.com/CN=theUserIWantToAdd,OU=MyOU,DC=domainB,DC=company,DC=com" });
    // de.Invoke("Add", new object[] { "LDAP://domainA.company.com/CN=anotherUserFromDomainA,OU=AnotherOU,DC=domainB,DC=company,DC=com" });
    impersonator.undoImpersonation();
}

// second impersonation because the group (de) is in domainA
// and techUser2 has account operator privileges there
if (impersonator.impersonateUser("techUser2", "domainA", "pass"))
{
    de.CommitChanges();
    impersonator.undoImpersonation();
    return true;
}
else
{
    // second impersonation was unsuccessful, so return an empty object
    return false;
}

第 6 行有效,如果我调试它或强制将属性写入 HttpResponse,它显然在那里。所以 LDAP 查询似乎没问题。

此外,如果我注释掉第 6 行并取消注释第 7 行,那么基本上我添加了来自同一域的用户,整个过程奇迹般地工作。对于 domainB,我被卡住了。有什么好的建议吗?

按照您的代码,我看到您将 de 作为参数获取,它位于 Domain A 中。然后您正在创建 DirectoryEntry 对象 dom,它正在 impersonated,但从未被使用。但是,您正在尝试使用 LDAP 直接将对象从 Domain B 添加到 de。这一行:

de.Invoke("Add", new object[{"LDAP://domainB.company.com/CN=theUserIWantToAdd,OU=MyOU,DC=domainB,DC=company,DC=com" }); 

没有得到 impersonated

假设您的 impersonation 工作正常, 使用已经 impersonatedDirectorySearcherdom 对象来查找用户在 Domain B 中,然后将用户对象从 Domain B 添加到 de

...
using (DirectoryEntry dom = new DirectoryEntry("LDAP://domainB.company.com/OU=MyOU,DC=domainB,DC=company,DC=com", "techUser1", "pass"))
{
    using (DirectorySearcher searcher = new DirectorySearcher(dom))
    {
        searcher.Filter = "(&(objectClass=user)(CN=theUserIWantToAdd))";
        SearchResult result = searcher.FindOne();
        de.Invoke("Add", new object[] { result.Path });
    }
}
...

UDPATE

此示例将向您展示如何从一个域获取用户 SID、从另一个域搜索组以及使用 SID 将用户添加到组。

//GET THE USER FROM DOMAIN B
using (UserPrincipal userPrincipal = UserPrincipal.FindByIdentity(domainContext, UPN))
{
    if (userPrincipal != null)
    {
       //FIND THE GROUP IN DOMAIN A
       using (GroupPrincipal groupPrincipal = GroupPrincipal.FindByIdentity(domainContext, groupName))
       {
          if (groupPrincipal != null)
          {
             //CHECK TO MAKE SURE USER IS NOT IN THAT GROUP
             if (!userPrincipal.IsMemberOf(groupPrincipal))
             {
                string userSid = string.Format("<SID={0}>", userPrincipal.SID.ToString());
                DirectoryEntry groupDirectoryEntry = (DirectoryEntry)groupPrincipal.GetUnderlyingObject();
                groupDirectoryEntry.Properties["member"].Add(userSid);
                groupDirectoryEntry.CommitChanges();
              }
           }
        }
     }
 }

请注意,我跳过了上面代码中的所有 impersonation

最终起作用的是按照 Burzum 的建议使用委托人。您可以在问题中链接的 MSDN 文章中看到的原始代码示例在这里不起作用。因此,基于主体的方法是绝对不够的。在提交新组的更改之前,您还需要一行:

group.Properties["groupType"].Value = (-2147483644);

默认值为 0x8000000,我不得不将其更改为 0x80000004 以使其能够接受来自另一个域的 FSP。

所以现在组已经存在,它有成员,它被添加到文件夹的 ACL 中。