DirectoryEntry.Invoke(groups,null) не извлекает все группы?

Я создал веб-службу WCF для возврата информации о пользователе и группе из Active Directory. Это работает для большинства групп и пользователей.

Я использую directoryEntry.Invoke("groups",null) для возврата групп, членом которых является указанный пользователь. Это возвращает группы MOST. Странно то, что я могу найти любую группу и перечислить ее членов, даже если это одна из отсутствующих групп, когда я использую запрос вызова для одного из ее членов.

Большинство групп, демонстрирующих такое поведение, поддерживают Exchange. Большинство проблемных учетных записей пользователей относятся к пользователям в федеративном домене, которые используют сервер Exchange в домене, который я запрашиваю. Я не пытаюсь запрашивать объекты в федеративном домене.

Мои теории на данный момент:

  • некоторые ограничения безопасности не позволяют перечислить все группы с помощью вызова(), хотя я могу запрашивать отсутствующие группы и перечислять их членов.

  • у вызова есть проблемы с некоторыми подмножествами групп. Возможно, задействованы универсальные, динамические или поддерживаемые Exchange свойства.

  • метод вызова не выбирает все группы, потому что «федеративные» учетные записи (созданные как часть их настройки учетной записи Exchange) каким-то образом отличаются от обычных учетных записей домена за пределами сопоставления sid обратно с их доменом входа.


person HeathenWorld    schedule 12.08.2009    source источник


Ответы (3)


Есть две известные проблемы с использованием свойства «Группы» в DirectoryEntry:

  • он не покажет вам «группу по умолчанию», в которой находится пользователь (обычно «Пользователи»)
  • он не покажет вам членство во вложенных группах

Таким образом, если пользователь является членом группы A, а эта группа, в свою очередь, является членом группы B, то в Windows это означает, что пользователь также является членом группы B. Однако DirectoryEntry не покажет вам эту вложенную группу. членство.

Это два единственных ограничения, которые я знаю для прямой Active Directory (без Exchange).

Получить группу по умолчанию немного сложно, но у меня есть пример кода для этого.

private string GetPrimaryGroup(DirectoryEntry aEntry, DirectoryEntry aDomainEntry)
{
   int primaryGroupID = (int)aEntry.Properties["primaryGroupID"].Value;
   byte[] objectSid = (byte[])aEntry.Properties["objectSid"].Value;

   StringBuilder escapedGroupSid = new StringBuilder();

   // Copy over everything but the last four bytes(sub-authority)
   // Doing so gives us the RID of the domain
   for(uint i = 0; i < objectSid.Length - 4; i++)
   {
        escapedGroupSid.AppendFormat("\\{0:x2}", objectSid[i]);
   }

   //Add the primaryGroupID to the escape string to build the SID of the primaryGroup
   for(uint i = 0; i < 4; i++)
   {
       escapedGroupSid.AppendFormat("\\{0:x2}", (primaryGroupID & 0xFF));
       primaryGroupID >>= 8;
   }

   //Search the directory for a group with this SID
   DirectorySearcher searcher = new DirectorySearcher();
   if(aDomainEntry != null)
   {
      searcher.SearchRoot = aDomainEntry;
   }

   searcher.Filter = "(&(objectCategory=Group)(objectSID=" + escapedGroupSid.ToString() + "))";
   searcher.PropertiesToLoad.Add("distinguishedName");

   return searcher.FindOne().Properties["distinguishedName"][0].ToString();
}

Получение вложенных групп также требует нескольких шагов, и мне придется искать решение для этого, если это проблема.

Марк

PS: в качестве примечания - с какой стати вы делаете вызов "DirectoryEntry.Invoke("groups", null)"? Почему бы вам просто не перечислить свойство DirectoryEntry.Properties["memberOf"] , которое является многозначным (содержит несколько значений) и содержит DN (отличительное имя) группы?

foreach(string groupDN in myUser.Properties["memberOf"])
{
  string groupName = groupDN;
}

ИЛИ, если вы используете .NET 3.5, вы можете использовать новые классы Security Principal в S.DS.AccountManagement. Одним из них является «UserPrincipal», у которого есть метод «GetAuthorizationGroups()», который делает всю эту тяжелую работу за вас — в основном бесплатно!

См. превосходную статью MSDN, в которой описываются эти новые .NET 3.5 S.DS. особенности для вас.

person marc_s    schedule 12.08.2009
comment
Это хорошие предложения, и вы правы насчет статьи MSDN, я должен был прочитать ее перед тем, как начать. Что касается того, почему я использовал метод вызова, в данном случае все, что мне было нужно, это имена групп, и это казалось эффективным способом получения информации. Я не очень много программировал для Active Directory, поэтому я все еще очень много изучаю, как лучше действовать. Интересно, насколько .NET развился в этой области с версии 1.1! - person HeathenWorld; 13.08.2009
comment
Никаких проблем - просто любопытно, была ли у вас конкретная причина для использования подхода Invoke(). И эй, в этом вся суть StackOverflow — помочь вам, когда вы не видите леса за деревьями :-) - person marc_s; 13.08.2009

Я думаю, что marc_s прав. Если вам нужны все группы, вы можете использовать следующий фрагмент:

using (DirectoryEntry obj = new DirectoryEntry("LDAP://" + dn))
{
    obj.RefreshCache(new string[] { "tokenGroups" });
    string[] sids = new string[obj.Properties["tokenGroups"].Count];
    int i = 0;
    foreach (byte[] bytes in obj.Properties["tokenGroups"])
    {
        sids[i] = _ConvertSidToString(bytes);
        ++i;
    }
    obj.Close();
    return sids;
}

Обратите внимание, что вычисление вложенных групп — дорогостоящая операция, поэтому RefreshCache может занять много времени.

person On Freund    schedule 12.08.2009

О Фрейнде,

Я пытаюсь использовать ваш код и не очень далеко. Я обновил путь входа в каталог на «LDAP://DC=myDomain,DC=co,DC=uk», но не получил никаких результатов (obj.Properties["tokenGroups"].Count = 0)

Я не понимаю, как указывается пользователь для списка группы.

Не могли бы вы указать мне правильное направление?

Спасибо

РЕДАКТИРОВАТЬ:

Я разобрался в итоге. Запись каталога для получения групп токенов должна быть записью пользователя... если это имеет смысл...

Я включил некоторый код на случай, если у кого-то еще будет такой же запрос:

Dim directoryEntry As DirectoryEntry = _
      New DirectoryEntry("LDAP://CN=users,DC=domanName,DC=com")
Dim directorySearcher As DirectorySearcher = _
      New DirectorySearcher(directoryEntry, "(sAMAccountName=" & UserName & ")")
Dim searchResult As SearchResult = directorySearcher.FindOne()

If Not searchResult Is Nothing Then
    Dim userDirectoryEntry As DirectoryEntry = searchResult.GetDirectoryEntry
    userDirectoryEntry.RefreshCache(New String() {"tokenGroups"})
    ... etc ...
End If
person Community    schedule 13.08.2009