LDAP_MATCHING_RULE_IN_CHAIN ​​не работает с группами AD по умолчанию - Пользователи домена - PullRequest
0 голосов
/ 23 ноября 2018

В моей программе мне нужно получить все группы AD для пользователя.Текущая версия моей программы использует System.DirectoryServices.AccountManagement.UserPrincipal.GetAuthorizationGroups.

Это работает хорошо, пока у нас не появился новый клиент с гораздо большим AD.Там это действительно медленно.(До 60 секунд)

Теперь я осмотрелся и увидел сообщения о том, что AccountManagement прост в использовании, но медленен.

Я также обнаружил, что LDAP_MATCHING_RULE_IN_CHAIN ​​также должен извлекать всевложенные группы, в которые входит пользователь.И более производительный.

С эта ссылка.

Но у меня проблема с группами по умолчанию, которые существуют в AD.

ДляНапример, группа «Пользователи домена» не возвращается функцией.У них также есть группа "BDOC", которая в качестве члена имеет "Пользователи домена".Эта группа также не возвращается.

Через GetAuthorizationGroups она возвращается правильно.

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

VB.NET:

Dim strFilter As String = String.Format("(member:1.2.840.113556.1.4.1941:={0})", oUserPrincipal.DistinguishedName)
Dim objSearcher As New DirectoryServices.DirectorySearcher("LDAP://" & oLDAPAuthenticationDetail.Domain & If(Not String.IsNullOrWhiteSpace(oLDAPAuthenticationDetail.Container), oLDAPAuthenticationDetail.Container, String.Empty))
objSearcher.PageSize = 1000
objSearcher.Filter = strFilter
objSearcher.SearchScope = DirectoryServices.SearchScope.Subtree
objSearcher.PropertiesToLoad.Add(sPropGuid)
objSearcher.PropertiesToLoad.Add(sPropDisplayName)


Dim colResults As DirectoryServices.SearchResultCollection = objSearcher.FindAll()

После этого я тестировал с помощью скрипта по ссылке, можно ли было извлечь всех пользователей из группы «Пользователи домена», изменив «member» на «memberOf».«в фильтре.Когда я помещаю группу администраторов домена в фильтр, она показывает правильных администраторов.Когда я помещаю группу «Пользователи домена» в фильтр, она ничего не возвращает.

Powershell:

$userdn = 'CN=Domain Users,CN=Users,DC=acbenelux,DC=local'
$strFilter = "(memberOf:1.2.840.113556.1.4.1941:=$userdn)"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry("LDAP://rootDSE")
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = "LDAP://$($objDomain.rootDomainNamingContext)"
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter
$objSearcher.SearchScope = "Base"
$colProplist = "name"
foreach ($i in $colPropList)
{
    $objSearcher.PropertiesToLoad.Add($i) > $nul
}
$colResults = $objSearcher.FindAll()
foreach ($objResult in $colResults)
{
    $objItem = $objResult.Properties
    $objItem.name
}

Я не знаю, что я делаю неправильно.Или, может быть, просто невозможно получить «группы по умолчанию» с этим фильтром?Что тогда является хорошей альтернативой?

1 Ответ

0 голосов
/ 24 ноября 2018

Группа по умолчанию нечетная.Он не сохраняется в memberOf или даже в атрибуте member группы.Вот почему ваш поиск не найдет его.Группа по умолчанию определяется primaryGroupId пользователя.Этот атрибут хранит RID (последнюю часть SID) группы.Это немного глупо, я знаю:)

Я действительно написал статью о 3 (да 3) различных способах, которыми кто-то может быть членом группы: Что делает участника участником?

Я также написал статью о том, как получить все группы, к которым принадлежит один пользователь, и как учесть все 3 способа: Поиск всех групп пользователя

Например, вот код C #, который я вставил в эту статью о том, как найти имя основной группы для пользователя (с учетом DirectoryEntry).Не должно быть слишком сложно перевести это на VB.NET:

private static string GetUserPrimaryGroup(DirectoryEntry de) {
    de.RefreshCache(new[] {"primaryGroupID", "objectSid"});

    //Get the user's SID as a string
    var sid = new SecurityIdentifier((byte[])de.Properties["objectSid"].Value, 0).ToString();

    //Replace the RID portion of the user's SID with the primaryGroupId
    //so we're left with the group's SID
    sid = sid.Remove(sid.LastIndexOf("-", StringComparison.Ordinal) + 1);
    sid = sid + de.Properties["primaryGroupId"].Value;

    //Find the group by its SID
    var group = new DirectoryEntry($"LDAP://<SID={sid}>");
    group.RefreshCache(new [] {"cn"});

    return group.Properties["cn"].Value as string;
}

Вы правы, что пространство имен AccountManagement упрощает задачу, но иногда оно действительно имеет ужасную производительность.Я никогда больше этим не пользуюсь.Я обнаружил, что DirectoryEntry / DirectorySearcher дает вам гораздо больший контроль над тем, как часто ваш код обращается к AD.

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

Обновление: Так что если вам нужны вложенные группы для пользователя, включая членство в основной группе, то вы можете найти основную группуво-первых, затем выполните поиск LDAP_MATCHING_RULE_IN_CHAIN ​​для групп, в которых члены и пользователь, и основная группа являются членами:

 (|(member:1.2.840.113556.1.4.1941:={userDN})(member:1.2.840.113556.1.4.1941:={primaryGroupDN}))

Обновление: Если вы хотите включить в свой поиск Authenticated Users (измените DC часть distinguishedName):

 (|(member:1.2.840.113556.1.4.1941:=CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=domain,DC=com)(member:1.2.840.113556.1.4.1941:={userDN})(member:1.2.840.113556.1.4.1941:={primaryGroupDN})

Обратите внимание, что вы также можете использовать атрибут tokenGroups пользователя, чтобы узнать все группы аутентификации для пользователя.Атрибут tokenGroups является составным атрибутом, поэтому вы можете получить его, только если специально его попросите (с помощью DirectoryEntry.RefreshCache() или, при поиске, добавьте его к DirectorySearcher.PropertiesToLoad.

Предостережение заключается в том, что tokenGroups - это список SID, а не distinguishedName, но вы можете напрямую связываться с объектом, используя SID с синтаксисом LDAP://<SID={sid}>.

...