Сбой функции поиска в группе Active Directory - PullRequest
2 голосов
/ 02 декабря 2009

Помощь! Я пытался написать функцию, которая будет подтверждать членство пользователя в группе Active Directory, и, хотя он работает, если член входит в группу, он выдает исключение, если пользователь не входит.

Вот функция:

private bool IsUserMemberOfGroup(string user, string group)
{
  using (var ctx = new PrincipalContext(ContextType.Domain))
  using (var groupPrincipal = GroupPrincipal.FindByIdentity(ctx, group))
  using (var userPrincipal = UserPrincipal.FindByIdentity(ctx, user))
  {
    if (groupPrincipal == null)
    {
      return false;
    }
    else
    {
      return userPrincipal.IsMemberOf(groupPrincipal);
    }
  }
}

А вот YSOD:

Ошибка сервера в приложении '/'.

Неизвестная ошибка (0x80005000)

Описание: Произошло необработанное исключение во время выполнения текущего веб-запроса. Пожалуйста, просмотрите трассировку стека для получения дополнительной информации об ошибке и о том, где она возникла в коде.

Сведения об исключении:

System.Runtime.InteropServices.COMException: неизвестная ошибка (0x80005000)

Ошибка источника:

Line 34: else Line 35: { Line 36: return userPrincipal.IsMemberOf(groupPrincipal); Line 37: } Line 38: }

Я не знаю, связано ли это, но когда я перехожу через функцию, groupPrincipal.Members.Count генерирует исключение типа «System.NullReferenceException», а Count.Base показывает исключение с сообщением «Ссылка на объект не установить экземпляр объекта ".

Что, черт возьми, происходит? Почему бул по имени IsMemberOf просто не возвращает false, если кто-то не является участником?

Спасибо

Daniel

Ответы [ 3 ]

4 голосов
/ 02 декабря 2009

Я думаю, вы могли бы немного упростить вещи:

private bool IsUserMemberOfGroup(string user, string group)
{
  using (var ctx = new PrincipalContext(ContextType.Domain))
  using (var userPrincipal = UserPrincipal.FindByIdentity(ctx, user))
  {
      PrincipalSearchResult<Principal> result = userPrincipal.GetGroups();

      GroupPrincipal groupPrincipal = 
           result.Where(g => g.SamAccountName == groupName).FirstOrDefault();

      return (groupPrincipal != null);
  }
}

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

Если вы нашли нужную группу в PrincipalSearchResult<Principal>, возвращаемом GetGroups(), то ваш пользователь является членом этой группы.

С этим вы можете сохранить себе хотя бы один вызов "FindByIdentity".

1 голос
/ 13 июня 2011

Незначительная модификация поверх кода от marc_s, у меня есть:

using (var ctx = new PrincipalContext(ContextType.Domain)) 
using (var userPrincipal = UserPrincipal.FindByIdentity(ctx, user)) 
using (var groupPrincipal = GroupPrincipal.FindByIdentity(ctx, group))
{
     if (userPrincipal == null) return false;
     if (groupPrincipal == null) return false;

     PrincipalSearchResult<Principal> result = userPrincipal.GetGroups(); 
     Principal grp = result.Where(g => g.Sid == groupPrincipal.Sid).FirstOrDefault(); 
     return (grp != null);
}

Сравнение Sid работает надежнее, чем сравнение SamAccountName.

0 голосов
/ 30 марта 2015

В нашей настройке была небольшая группа ядовитых людей, которая приводила к сбою некоторых пользователей, но не других. Логика «FirstOrDefault» в других предложенных ответах МОЖЕТ помочь нам увернуться от ядовитой группы, но это не гарантия.

У нас есть два предложения для других с этой проблемой. Сначала проверьте, есть ли у вас группы с косой чертой в имени группы (фактическое имя группы, а не имя «pre-windows 2000», которое заменит его подчеркиванием). Если вы можете переименовать все такие группы, которые могут решить вашу проблему ... это сработало для нас.

Этот обходной путь также работал для нас:

/// <summary>
/// This does a recursive group search for the given user or computer principal.
/// </summary>
public IEnumerable<Principal> GetGroups(Principal principal)
{
    return GetGroups(null, principal);
}

private IEnumerable<Principal> GetGroups(HashSet<SecurityIdentifier> ancestorPrincipalSids, Principal parentPrincipal)
{
    try
    {
        //enumerate this here so errors are thrown now and not later
        //if the current group name has a forward-slash, I think this 
        //will always error here
        var groups = parentPrincipal.GetGroups().ToArray();
        if (groups == null)
        {
            return Enumerable.Empty<Principal>();
        }

        //keep track of all ancestors in the group hierarchy to this point
        //so that we can handle circular references below
        var newAncestors = new HashSet<SecurityIdentifier>(ancestorPrincipalSids ?? Enumerable.Empty<SecurityIdentifier>());
        newAncestors.Add(parentPrincipal.Sid);

        return groups
            .Concat(groups
                .Where(g => !newAncestors.Contains(g.Sid)) //handle circular references
                .SelectMany(g => GetGroups(newAncestors, g)));
    }
    catch
    {
        return Enumerable.Empty<Principal>();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...