【问题标题】:Add member to AD group from a trusted domain从受信任域将成员添加到 AD 组
【发布时间】:2015-08-13 09:15:22
【问题描述】:

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

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

  • 在 domainA 中创建一个组(好的!)
  • 在域 B 中查找用户(好的!)
  • 将用户添加到组(提交更改时失败,错误消息:There is no such object on the server. (Exception from HRESULT: 0x80072030)

如果我要添加来自同一域的用户,则代码可以完美运行,所以我相信我在这里只遗漏了一小部分信息。我使用this document 作为参考,也看到了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,我被困住了。有什么好的建议吗?

【问题讨论】:

  • 好的,我还没有代码,但我找到了一个线索:来自不同域的组成员可以添加为 ForeignSecurityPincipals,所以不是正常的方式。
  • 您是否仅在尝试将用户从一个域添加到另一个域组或执行其他一些操作时遇到问题?出于测试目的,您可以尝试在模拟时更新用户名吗?
  • 我在domainB中没有账号操作权限,所以不用尝试。在 domainA 中,一切正常,我可以创建组、用户、重置密码、解锁帐户等。

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


【解决方案1】:

按照您的代码,我看到您将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 工作正常, 使用已经是impersonateddom 对象和DirectorySearcherDomain B 中查找用户,然后从@987654336 添加用户对象@到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

【讨论】:

  • 在最后一行之前工作。所以找到用户,我可以看到它的完整路径或任何其他属性,但添加它失败。 de.Invoke 处的错误消息:System.DirectoryServices.DirectoryServicesCOMException:服务器上没有这样的对象。 (来自 HRESULT 的异常:0x80072030)。我已经用我原来的方法遇到了这个错误消息,我相信问题是我试图用来自 DomainB 的成员在 DomainA 中保存一个组对象。这就是为什么必须以某种方式涉及到 foreignsecuritypricipal 对象的原因。
  • 但无论如何,您的评论和回答帮助我从 4.0 迁移到 4.5 并将 System.DirectoryServices.AccountManagement 添加到我的项目中,感谢您指出!
  • 当我使用 SysInternals 工具查看 DomainA 中的其他组(手动创建)时,我看到来自 domainB 的成员被添加为“CN=,CN=ForeignSecurityPrincipals,DC=domainA ,DC=公司,DC=com”。看到不同。所以这些用户在 domainA 中也有一个对象,我什至可以在 AD 的 CN=ForeignSecurityPrincipals 部分找到它们。不好的是它们不包含人类可读的属性,所以我无法在这里通过名称或 samaccountname 找到用户。尚未找到标识 domainB 中对象的属性 ...
  • 好。您可以使用AccountManagement 命名空间发布更新的代码吗?您可以使用ADSI 工具吗?
  • 另外,你能告诉我Domain A 中的组。它是一个什么样的群体? User, Global, Local?您在两个域之间有什么样的信任?我会尽快更新我的答案...
【解决方案2】:

最终奏效的是按照 Burzum 的建议使用校长。您可以在问题中链接的 MSDN 文章中看到的原始代码示例在此处不起作用。因此,基于 Principal 的方法是必须的,还不够。在提交新组的更改之前,您还需要一行:

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

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

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

【讨论】:

  • 我知道这是旧的,但我认为需要澄清。将groupType 设置为0x80000004 会将“组范围”设置为“域本地”,将“组类型”设置为“安全”。重要的部分是将“组范围”设置为“域本地”,因为这将允许添加来自受信任域的用户。只需执行一次,因此可以在 AD 用户和计算机中手动完成。
  • @GabrielLuci 通常是的,但这是一个自助服务网络应用程序,您可以在其中设置新的组文件共享并根据您的项目需要设置访问权限。因此,它为每个新文件共享创建了组:一个用于管理员,一个用于 R,另一个用于 RW 访问。我必须将用户添加到这些组中。组和用户位于不同但受信任的域中。
  • 是的,如果您也以编程方式创建组,这很有意义。
  • 并注意-2147483644也可以表示为unchecked((int) 0x80000004)。编译器会将其编译成-2147483644,但关键是可读性,因为微软的所有文档都显示了十六进制值。但最终,两者都会起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-12
  • 1970-01-01
  • 2021-01-11
相关资源
最近更新 更多