Как проверить, принадлежит ли пользователь группе AD и вложенным группам? - PullRequest
5 голосов
/ 21 апреля 2010

У меня есть приложение ASP.NET 3.5, использующее аутентификацию Windows и реализующее наш собственный RoleProvider.

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

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

Например: скажем, мы хотим проверить, является ли Пользователь членом группы E , но Пользователь не является прямым членом * E ", она является членом "A", который является членом "B", который действительно является членом E , поэтому Пользователь является членом * E "

Одно из решений, которое у нас есть, очень медленное, хотя и дает правильный ответ

using (var context = new PrincipalContext(ContextType.Domain))
  {
    using (var group = GroupPrincipal.FindByIdentity(context, IdentityType.Name, "DL-COOL-USERS"))
    {
      var users = group.GetMembers(true); // recursively enumerate

      return users.Any(a => a.Name == "userName");
    }
  }

Исходное решение и то, что я пытался заставить работать, используя .NET 3.5 System.DirectoryServices.AccountManagement и оно работает, когда пользователи являются прямыми членами рассматриваемой группы, выглядит следующим образом:

public bool IsUserInGroup(string userName, string groupName)
{
  var cxt = new PrincipalContext(ContextType.Domain, "DOMAIN");
  var user = UserPrincipal.FindByIdentity(cxt, IdentityType.SamAccountName, userName);

 if (user == null)
  {       
    return false;
  }


  var group = GroupPrincipal.FindByIdentity(cxt, groupName);

  if (group == null)
  {        
    return false;
  }

  return user.IsMemberOf(group);
}

Суть в том, что нам нужно проверять членство, даже если группы вложены на многих уровнях вниз.

Большое спасибо!

Ответы [ 2 ]

1 голос
/ 23 апреля 2010

Что ж, мне пришлось размышлять над этим квадратом, и, к счастью, заглянув в AD, мы обнаружили, что все 3000+ людей, которым приходилось видеть страницы, имеют ключевое слово в собственном свойстве AD. Поэтому все, что мне нужно было сделать, это загрузить объект из AD и посмотреть его. Конечный результат клиент очень доволен! В данный момент это выглядит как грязное решение, но, как всегда, это работает отлично, и мы должны перейти к другим вещам!

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

public static bool IsEmployeeCoolEnoughToSeePages(string userName)
{
  if (string.IsNullOrEmpty(userName))
  {
    throw new ArgumentNullException("Current user's Username cannot be null");
  }

  using (var searcher = new DirectorySearcher(("LDAP://YOURDOMAIN.com")))
  {
    searcher.Filter = string.Format("(&(objectCategory=user)(samAccountName={0}))", ariseUserName);
    SearchResultCollection searchResultCollection = searcher.FindAll();

    if (searchResultCollection.Count == 1)
    {
      var values = searchResultCollection[0].Properties["title"];

      if (values.Count == 1)
      {
        return values[0].ToString().StartsWith("_COOLNES_");
      }
    }

    return false;
  }
}
1 голос
/ 21 апреля 2010

Решение 1. Используйте web.config для ограничения доступа

Поскольку вы используете ASP.NET, гораздо более простым решением для ограничения доступа является его настройка в web.config, например:

<configuration>
  <location path="protected/url/path">
    <system.web>
      <authorization>
        <allow roles="DOMAIN\group"/>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>
</configuration>

Для получения дополнительной информации: http://msdn.microsoft.com/en-us/library/wce3kxhd.aspx и http://msdn.microsoft.com/en-us/library/b6x6shw7.aspx.

Решение 2. Более быстрая реализация IsUserInGroup

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

static bool IsUserInGroup(DirectoryEntry user, string groupName)
{
    user.RefreshCache(new string[] {"tokenGroups"});
    for (int i = 0; i < user.Properties["tokenGroups"].Count; i++) {
        SecurityIdentifier sid = new SecurityIdentifier((byte[]) user.Properties["tokenGroups"][i], 0);
        try {
            NTuser nt = (NTuser) sid.Translate(typeof(NTuser));
            if (nt.Value.ToLower().EndsWith("\\" + groupName.ToLower())) {
                return true;
            }
        } catch (IdentityNotMappedException) {
            continue;
        }
    }

    return false;
}
...