Добавить участника в группу AD из доверенного домена

У меня есть два домена в доверенных отношениях, которые я пытаюсь использовать из веб-приложения С#. Для этого я должен олицетворять двух разных технических пользователей, но это работает хорошо, поэтому я не буду подчеркивать эту часть кода.

Чтобы создать правильные и простые в управлении ACL для файловой системы, я должен

  • Создайте группу в domainA (OK!)
  • Найти пользователя в домене (OK!)
  • Добавьте пользователя в группу (FAILS при совершении изменений, сообщение об ошибке: There is no such object on the server. (Exception from HRESULT: 0x80072030))

Если я добавляю пользователя из того же домена, код работает отлично, поэтому я считаю, что я просто пропускаю небольшую частичную информацию здесь. Я использовал этот документ в качестве ссылки и увидел этот вопрос (и несколько ссылок на это сообщение об ошибке), но ни один из них не помог.

Код (блок 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 я застрял. Любой хороший совет?

Ответ 1

Следуя вашему коду, я вижу, что вы получаете de в качестве параметра, который находится в Domain A. Затем вы создаете объект DirectoryEntry dom, который получает impersonated, но никогда не будет использоваться. Однако вы пытаетесь добавить объект с Domain B в de напрямую, используя LDAP. Эта строка:

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

не получает impersonated.

Предполагая, что ваш impersonation работает правильно, используйте dom объект, который уже impersonated с DirectorySearcher, чтобы найти пользователя в 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 в приведенном выше коде.

Ответ 2

В конечном итоге работали с принципами, предложенными Бурзумом. Исходные образцы кода, которые вы видите в статье MSDN, связанной с вопросом, здесь не работали. Таким образом, основанный на принципах подход является недостаточным орехом. Перед внесением изменений в новую группу вам понадобится еще одна строка:

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

По умолчанию было 0x8000000, и мне пришлось изменить его на 0x80000004, чтобы он мог принимать FSP из другого домена.

Итак, теперь группа существует, она имеет членов, она добавляется в ACL папки.