Как получить группы пользователей в Active Directory?(c #, asp.net) - PullRequest
101 голосов
/ 15 марта 2011

Я использую этот код для получения групп текущего пользователя. Но я хочу вручную дать пользователю, а затем получить его группы. Как я могу это сделать?

using System.Security.Principal;

public ArrayList Groups()
{
    ArrayList groups = new ArrayList();

    foreach (IdentityReference group in System.Web.HttpContext.Current.Request.LogonUserIdentity.Groups)
    {
        groups.Add(group.Translate(typeof(NTAccount)).ToString());
    }

    return groups;
}

Ответы [ 8 ]

150 голосов
/ 15 марта 2011

Если вы используете .NET 3.5 или более позднюю версию, вы можете использовать новое пространство имен System.DirectoryServices.AccountManagement (S.DS.AM), которое делает это намного проще, чем раньше.

Читать всеоб этом здесь: Управление принципами безопасности каталогов в .NET Framework 3.5

Обновление: старые статьи журнала MSDN больше не в сети,к сожалению - вам нужно загрузить CHM для журнала MSDN за январь 2008 года от Microsoft и прочитать там статью.

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

public List<GroupPrincipal> GetGroups(string userName)
{
   List<GroupPrincipal> result = new List<GroupPrincipal>();

   // establish domain context
   PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain);

   // find your user
   UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, userName);

   // if found - grab its groups
   if(user != null)
   {
      PrincipalSearchResult<Principal> groups = user.GetAuthorizationGroups();

      // iterate over all groups
      foreach(Principal p in groups)
      {
         // make sure to add only group principals
         if(p is GroupPrincipal)
         {
             result.Add((GroupPrincipal)p);
         }
      }
   }

   return result;
}

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

Обновление: Для доступанекоторые свойства, которые не отображаются на объекте UserPrincipal, необходимо изучить в DirectoryEntry:

public string GetDepartment(Principal principal)
{
    string result = string.Empty;

    DirectoryEntry de = (principal.GetUnderlyingObject() as DirectoryEntry);

    if (de != null)
    {
       if (de.Properties.Contains("department"))
       {
          result = de.Properties["department"][0].ToString();
       }
    }

    return result;
}

Обновление № 2: не должно быть слишкомтрудно соединить эти два фрагмента кода вместе ... но все в порядке - вот и все:

public string GetDepartment(string username)
{
    string result = string.Empty;

    // if you do repeated domain access, you might want to do this *once* outside this method, 
    // and pass it in as a second parameter!
    PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain);

    // find the user
    UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, username);

    // if user is found
    if(user != null)
    {
       // get DirectoryEntry underlying it
       DirectoryEntry de = (user.GetUnderlyingObject() as DirectoryEntry);

       if (de != null)
       {
          if (de.Properties.Contains("department"))
          {
             result = de.Properties["department"][0].ToString();
          }
       }
    }

    return result;
}
52 голосов
/ 16 октября 2013

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

using System.Security.Principal

private List<string> GetGroups(string userName)
{
    List<string> result = new List<string>();
    WindowsIdentity wi = new WindowsIdentity(userName);

    foreach (IdentityReference group in wi.Groups)
    {
        try
        {
            result.Add(group.Translate(typeof(NTAccount)).ToString());
        }
        catch (Exception ex) { }
    }
    result.Sort();
    return result;
}

Я использую try/catch, потому что у меня были некоторые исключения с 2 из 200 групп в очень большой AD, потому что некоторые SID больше не были доступны. (Вызов Translate() выполняет преобразование SID -> имени.)

15 голосов
/ 07 апреля 2016

Прежде всего, GetAuthorizationGroups () - отличная функция, но, к сожалению, имеет 2 недостатка:

  1. Производительность низкая, особенно в большой компании с большим количеством пользователей и групп.Он извлекает намного больше данных, чем вам действительно нужно, и выполняет серверный вызов для каждой итерации цикла, в результате
  2. Он содержит ошибки, которые могут привести к тому, что ваше приложение перестает работать «однажды», когда группы и пользователи развиваются.Microsoft признала проблему и связана с некоторыми SID.Вы получите сообщение об ошибке «Произошла ошибка при перечислении групп»

Поэтому я написал небольшую функцию, чтобы заменить GetAuthorizationGroups () на более высокую производительность и безопасную от ошибок.Он делает только 1 вызов LDAP с запросом с использованием индексированных полей.Его можно легко расширить, если вам нужно больше свойств, чем только имена групп (свойство "cn").

// Usage: GetAdGroupsForUser2("domain\user") or GetAdGroupsForUser2("user","domain")
public static List<string> GetAdGroupsForUser2(string userName, string domainName = null)
{
    var result = new List<string>();

    if (userName.Contains('\\') || userName.Contains('/'))
    {
        domainName = userName.Split(new char[] { '\\', '/' })[0];
        userName = userName.Split(new char[] { '\\', '/' })[1];
    }

    using (PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, domainName))
        using (UserPrincipal user = UserPrincipal.FindByIdentity(domainContext, userName))
            using (var searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + domainContext.Name)))
            {
                searcher.Filter = String.Format("(&(objectCategory=group)(member={0}))", user.DistinguishedName);
                searcher.SearchScope = SearchScope.Subtree;
                searcher.PropertiesToLoad.Add("cn");

                foreach (SearchResult entry in searcher.FindAll())
                    if (entry.Properties.Contains("cn"))
                        result.Add(entry.Properties["cn"][0].ToString());
            }

    return result;
}
10 голосов
/ 15 марта 2011

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

Вот небольшой пример кода:

// (replace "part_of_user_name" with some partial user name existing in your AD)
var userNameContains = "part_of_user_name";

var identity = WindowsIdentity.GetCurrent().User;
var allDomains = Forest.GetCurrentForest().Domains.Cast<Domain>();

var allSearcher = allDomains.Select(domain =>
{
    var searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + domain.Name));

    // Apply some filter to focus on only some specfic objects
    searcher.Filter = String.Format("(&(&(objectCategory=person)(objectClass=user)(name=*{0}*)))", userNameContains);
    return searcher;
});

var directoryEntriesFound = allSearcher
    .SelectMany(searcher => searcher.FindAll()
        .Cast<SearchResult>()
        .Select(result => result.GetDirectoryEntry()));

var memberOf = directoryEntriesFound.Select(entry =>
{
    using (entry)
    {
        return new
        {
            Name = entry.Name,
            GroupName = ((object[])entry.Properties["MemberOf"].Value).Select(obj => obj.ToString())
        };
    }
});

foreach (var item in memberOf)
{
    Debug.Print("Name = " + item.Name);
    Debug.Print("Member of:");

    foreach (var groupName in item.GroupName)
    {
        Debug.Print("   " + groupName);
    }

    Debug.Print(String.Empty);
}
}
1 голос
/ 28 января 2016

В моем случае единственным способом, которым я мог продолжать использовать GetGroups () без каких-либо исключений, было добавление пользователя (USER_WITH_PERMISSION) в группу, которая имеет разрешение на чтение AD (Active Directory). Чрезвычайно важно создать PrincipalContext, передавая этого пользователя и пароль.

var pc = new PrincipalContext(ContextType.Domain, domain, "USER_WITH_PERMISSION", "PASS");
var user = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, userName);
var groups = user.GetGroups();

Шаги, которые вы можете выполнить внутри Active Directory, чтобы заставить его работать:

  1. В Active Directory создайте группу (или возьмите одну) и на вкладке «Безопасность» добавьте «Группа доступа авторизации Windows»
  2. Нажмите на кнопку «Дополнительно»
  3. Выберите «Группа доступа авторизации Windows» и нажмите «Просмотр»
  4. Установите флажок «Читать токенГруппыГлобальный и Универсальный»
  5. Найдите нужного пользователя и добавьте в группу, которую вы создали (взяли) с первого шага
0 голосов
/ 19 февраля 2019

Ответ зависит от того, какие группы вы хотите получить. Пространство имен System.DirectoryServices.AccountManagement предоставляет два метода поиска группы:

GetGroups - Возвращает коллекцию групповых объектов, которые указывают группы, членом которых является текущий участник.

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

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

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

Итак, GetGroups получает все группы, членом которых является пользователь direct , а GetAuthorizationGroups получает все полномочия групп, в которые входит пользователь прямой или косвенный член.

Несмотря на то, как они названы, одно не является подмножеством другого. Могут быть группы, возвращаемые GetGroups, не возвращаемые GetAuthorizationGroups, и наоборот.

Вот пример использования:

PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, "MyDomain", "OU=AllUsers,DC=MyDomain,DC=Local");
UserPrincipal inputUser = new UserPrincipal(domainContext);
inputUser.SamAccountName = "bsmith";
PrincipalSearcher adSearcher = new PrincipalSearcher(inputUser);
inputUser = (UserPrincipal)adSearcher.FindAll().ElementAt(0);
var userGroups = inputUser.GetGroups();
0 голосов
/ 19 июня 2018

Это работает для меня

public string[] GetGroupNames(string domainName, string userName)
    {
        List<string> result = new List<string>();

        using (PrincipalContext principalContext = new PrincipalContext(ContextType.Domain, domainName))
        {
            using (PrincipalSearchResult<Principal> src = UserPrincipal.FindByIdentity(principalContext, userName).GetGroups())
            {
                src.ToList().ForEach(sr => result.Add(sr.SamAccountName));
            }
        }

        return result.ToArray();
    }
0 голосов
/ 13 марта 2018

В случае, если Translate работает локально, но не удаленно e.i group. Translate (typeof (NTAccount)

Если вы хотите, чтобы код приложения выполнялся с использованием идентификатора LOGGED IN USER, включите олицетворение. Олицетворение можно включить через IIS или , добавив следующий элемент в web.config .

<system.web>
<identity impersonate="true"/>

Если олицетворение включено, приложение выполняется с разрешениями, указанными в вашей учетной записи пользователя. Таким образом, если вошедший в систему пользователь имеет доступ к определенному сетевому ресурсу, только тогда он сможет получить доступ к этому ресурсу через приложение.

Спасибо PRAGIM tech за эту информацию из его усердного видео

Проверка подлинности Windows в asp.net. Часть 87:

https://www.youtube.com/watch?v=zftmaZ3ySMc

Но олицетворение создает много накладных расходов на сервере

Лучшее решение, позволяющее пользователям определенных сетевых групп , - запретить анонимность в веб-конфигурации. <authorization><deny users="?"/><authentication mode="Windows"/>

и в вашем коде позади, предпочтительно в global.asax, используйте HttpContext.Current.User.IsInRole :

Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
If HttpContext.Current.User.IsInRole("TheDomain\TheGroup") Then
//code to do when user is in group
End If

ПРИМЕЧАНИЕ. Группа должна быть написана с обратной косой чертой \, т.е. "TheDomain \ TheGroup"

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