Лучший способ быстро определить, входит ли учетная запись пользователя в группу AD?

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

Этот код (VB.NET) пытается использовать свойство member объекта группы, но возвращает false, даже если пользователь является членом этой группы. Может ли кто-нибудь увидеть, что я здесь делаю не так?

Dim group As DirectoryEntry =  GetNetworkObject(GroupDomanName, NetworkObjectType.NetworkGroup, GroupName)
Dim user As DirectoryEntry =GetNetworkObject(UserDomainName, NetworkObjectType.NetworkUser, Login)

Return group.Properties("member").Contains(user.Path)

К вашему сведению: вызовы GetNetworkObject просто возвращают объект directoryEntry, я подтвердил, что правильный объект возвращается как для объекта группы, так и для объекта пользователя.


person JohnFx    schedule 15.12.2008    source источник


Ответы (4)


Если вы используете стек .NET 3.5, System.DirectoryServices.AccountManagement. dll имеет приятный API поверх AD. Для решения вашей проблемы можно использовать следующий метод:

static bool IsUserMemberOf(string userName, string groupName)
{
    using (var ctx = new PrincipalContext(ContextType.Domain))
    using (var groupPrincipal = GroupPrincipal.FindByIdentity(ctx, groupName))
    using (var userPrincipal = UserPrincipal.FindByIdentity(ctx, userName))
    {
        return userPrincipal.IsMemberOf(groupPrincipal);
    }
}

// Usage:
bool result = IsUserMemberOf("CONTOSO\\john.doe", "CONTOSO\\Administrators");

Я не знаю, как работает этот метод, но это чистое решение.

person huseyint    schedule 15.12.2008
comment
Спасибо. Я даже не догадывался, что 3.5 добавил этот (очень необходимый) уровень абстракции для AD. Я проголосую за ответ, потому что он отличный, но, увы, моя среда развертывания по-прежнему NET 2.0. - person JohnFx; 15.12.2008

Вот что я использовал в прошлом в сценарии VBS, который работал очень хорошо:

Set wshNet = CreateObject("WScript.Network")                'Setup connection to the Network
Set fso = CreateObject("Scripting.FileSystemObject")        'Create File System Object for any file manipulations

Set ADSysInfo = CreateObject("ADSystemInfo")                'Setup connection to Active Directory
Set CurrentUser = GetObject("LDAP://" & ADSysInfo.UserName) 'Setup current user to look for in Active Directory
strGroups = LCase(Join(CurrentUser.MemberOf))               'Grabs all the groups the current user is a member of

Затем я использую InStr, чтобы узнать, является ли пользователь частью этой группы:

If InStr(strGroups, "MyGroup") Then MyGroupSub

Возможно, вы сможете адаптировать вышеуказанное в своем проекте.

Между прочим, я заметил, что в вашем коде у вас есть groupdoman в качестве последнего параметра для 'группы'. Не уверен, что вы хотите, чтобы это было groupdomain или нет:

Затемнить группу как DirectoryEntry = GetNetworkObject (GroupDomanName, NetworkObjectType.NetworkGroup, GroupName, groupdoman)

vs

Затемнить группу как DirectoryEntry = GetNetworkObject (GroupDomanName, NetworkObjectType.NetworkGroup, GroupName, groupdomain)

Позвольте мне знать, если это помогает! JFV

person JFV    schedule 15.12.2008
comment
Хороший улов по параметру groupdomain. На самом деле это была часть кода, не имеющего отношения к проблеме, которую я удалил только наполовину (упс, сейчас исправлено), это позволило мне передать OU для группы. - person JohnFx; 15.12.2008

Я нашел ответ, который, кажется, работает в NET 2.0, относительно быстр и преодолевает возможную проблему групп, содержащих более 100 элементов (которые требуют поиска по диапазону)

Вот код, который я получил:

Dim DSearcher As New DirectorySearcher(group, "(&(objectClass=user)(cn=" + Login + "))", New String() {"member;Range=0-5000"}, SearchScope.OneLevel)                  
group = GetNetworkObject(GroupDomanName, NetworkObjectType.NetworkGroup, GroupName)
user = GetNetworkObject(UserDomainName, NetworkObjectType.NetworkUser, Login)
DSearcher.AttributeScopeQuery = "member"
Return (DSearcher.FindOne() IsNot Nothing)
person JohnFx    schedule 15.12.2008
comment
Берегись. Я изменю эту запись, когда закончу тестирование, но я обнаружил, что она не работает в двух случаях: 1) Если пользователь существует в группе, но из другого доверенного леса. 2) Если в группу входит пользователь с тем же именем, но с другим доменом. - person JohnFx; 16.12.2008

Вот еще один способ использования поисковика по каталогам и memberOf. Здесь используется objectSID текущего пользователя, но вы можете изменить его на другой идентификатор.

dSearch.Filter = String.Format("(&(memberOf={0})(objectSid={1}))", groupDN, WindowsIdentity.GetCurrent.User)

Return dSearch.FindOne() IsNot Nothing

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

searchName = searchName.Replace("\", "\5c"). _
                                Replace("/", "\2f"). _
                                Replace("*", "\2a"). _
                                Replace("(", "\28"). _
                                Replace(")", "\29")
person dotjoe    schedule 15.12.2008
comment
Параметры фильтра LDAP должны быть экранированы, иначе в какой-то момент ваш фильтр сломается. См. Мой ответ на: stackoverflow.com/questions/190516/ - person Tomalak; 16.12.2008