Como obter os grupos de um usuário no Active Directory? (c #, asp.net)

Eu uso esse código para obter os grupos do usuário atual. Mas eu quero dar manualmente o usuário e, em seguida, obter seus grupos. Como posso fazer isso?

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; } 

Se você estiver no .NET 3.5 ou superior, poderá usar o novo namespace System.DirectoryServices.AccountManagement (S.DS.AM), que torna isso muito mais fácil do que costumava ser.

Leia tudo sobre isso aqui: Gerenciando Diretórios de Segurança de Diretórios no .NET Framework 3.5

Atualização: artigos antigos da revista MSDN não estão mais online, infelizmente – você precisará baixar o CHM para a revista MSDN de janeiro de 2008 da Microsoft e ler o artigo lá.

Basicamente, você precisa ter um “contexto principal” (normalmente seu domínio), um usuário principal, e então você consegue seus grupos com muita facilidade:

 public List GetGroups(string userName) { List result = new List(); // 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 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; } 

e isso é tudo que existe! Agora você tem um resultado (uma lista) de grupos de autorização a que o usuário pertence – iterar sobre eles, imprimir seus nomes ou o que você precisa fazer.

Atualização: Para acessar determinadas propriedades, que não são UserPrincipal object UserPrincipal , você precisa acessar o DirectoryEntry subjacente:

 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; } 

Atualização # 2: parece que não deve ser muito difícil colocar esses dois trechos de código juntos … mas ok – aqui vai:

 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; } 

GetAuthorizationGroups() não encontra grupos nesteds. Para obter todos os grupos dos quais um determinado usuário é membro (incluindo grupos nesteds), tente isto:

 using System.Security.Principal private List GetGroups(string userName) { List result = new List(); 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; } 

Eu uso try/catch porque eu tive algumas exceções com 2 de 200 grupos em um AD muito grande porque alguns SIDs não estavam mais disponíveis. (A chamada do Translate() faz uma conversão SID -> Name.)

Primeiro de tudo, GetAuthorizationGroups () é uma ótima function, mas infelizmente tem duas desvantagens:

  1. O desempenho é ruim, especialmente em grandes empresas, com muitos usuários e grupos. Ele busca muito mais dados do que você realmente precisa e faz uma chamada de servidor para cada iteração de loop no resultado
  2. Ele contém bugs que podem fazer com que seu aplicativo pare de funcionar “algum dia” quando grupos e usuários estão evoluindo. A Microsoft reconheceu o problema e está relacionada com alguns SIDs. O erro que você receberá é “Ocorreu um erro ao enumerar os grupos”

Portanto, eu escrevi uma pequena function para replace GetAuthorizationGroups () com melhor desempenho e com segurança de erros. Faz apenas 1 chamada LDAP com uma consulta usando campos indexados. Ele pode ser facilmente estendido se você precisar de mais propriedades do que apenas os nomes dos grupos (propriedade “cn”).

 // Usage: GetAdGroupsForUser2("domain\user") or GetAdGroupsForUser2("user","domain") public static List GetAdGroupsForUser2(string userName, string domainName = null) { var result = new List(); 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; } 

Dentro do AD, todo usuário tem uma propriedade memberOf . Contém uma lista de todos os grupos aos quais ele pertence.

Aqui está um pequeno exemplo de código:

 // (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(); 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() .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); } } 

No meu caso, a única maneira que eu poderia continuar usando GetGroups () sem qualquer expction era adicionar o usuário (USER_WITH_PERMISSION) ao grupo que tem permissão para ler o AD (Active Directory). É extremamente importante construir o PrincipalContext passando este usuário e senha.

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

Etapas que você pode seguir dentro do Active Directory para fazê-lo funcionar:

  1. No Active Directory, crie um grupo (ou pegue um) e, na guia secutiry, adicione “Grupo de Acesso à Autorização do Windows”
  2. Clique no botão “Avançado”
  3. Selecione “Grupo de Acesso à Autorização do Windows” e clique em “Visualizar”
  4. Marque “Ler tokenGroupsGlobalAndUniversal”
  5. Localize o usuário desejado e adicione ao grupo que você criou (tirado) da primeira etapa

Caso o Translate funcione localmente, mas não remotamente o ei group. Translate (typeof (NTAccount)

Se você deseja que o código do aplicativo seja executado usando a identidade LOGGED IN USER, ative a representação. A representação pode ser habilitada através do IIS ou adicionando o seguinte elemento no web.config .

   

Se a representação estiver ativada, o aplicativo será executado usando as permissions encontradas na sua conta de usuário. Portanto, se o usuário logado tiver access a um recurso de rede específico, somente ele poderá acessar esse recurso por meio do aplicativo.

Agradeça à tecnologia PRAGIM por esta informação do seu vídeo diligente

Autenticação do Windows no asp.net Parte 87:

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

Mas a representação cria muita sobrecarga no servidor

A melhor solução para permitir que usuários de determinados grupos de rede neguem anonimamente na configuração da web

e no seu código por trás, preferencialmente no global.asax, use o 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 

NOTA: O grupo deve ser escrito com uma barra invertida \ ie “TheDomain \ TheGroup”

Isso funciona para mim

 public string[] GetGroupNames(string domainName, string userName) { List result = new List(); using (PrincipalContext principalContext = new PrincipalContext(ContextType.Domain, domainName)) { using (PrincipalSearchResult src = UserPrincipal.FindByIdentity(principalContext, userName).GetGroups()) { src.ToList().ForEach(sr => result.Add(sr.SamAccountName)); } } return result.ToArray(); }