¿Cómo obtener los grupos de un usuario en Active Directory? (c #, asp.net)

Uso este código para obtener los grupos del usuario actual. Pero quiero dar manualmente al usuario y luego obtener sus grupos. ¿Cómo puedo hacer esto?

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

Si usa .NET 3.5 o superior, puede usar el nuevo espacio de nombres System.DirectoryServices.AccountManagement (S.DS.AM), que hace que esto sea mucho más fácil de lo que solía ser.

Lea todo al respecto aquí: Administración de los principales de seguridad de directorios en .NET Framework 3.5

Actualización: los artículos más antiguos de la revista MSDN ya no están en línea. Desafortunadamente, deberá descargar el CHM para la revista MSDN de enero de 2008 de Microsoft y leer el artículo allí.

Básicamente, necesita tener un “contexto principal” (generalmente su dominio), un usuario principal, y luego obtiene sus grupos muy fácilmente:

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

y eso es todo lo que hay! Ahora tiene un resultado (una lista) de los grupos de autorización a los que pertenece el usuario: itere sobre ellos, imprima sus nombres o lo que necesite hacer.

Actualización: para acceder a ciertas propiedades, que no aparecen en el objeto UserPrincipal , debe profundizar en el DirectoryEntry subyacente:

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

Actualización n. ° 2: parece que no debería ser demasiado difícil juntar estos dos fragmentos de código … pero está bien, aquí va:

 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() no encuentra grupos nesteds. Para obtener realmente todos los grupos de los que es miembro un usuario determinado (incluidos los grupos nesteds), intente esto:

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

Uso try/catch porque tuve algunas excepciones con 2 de 200 grupos en un AD muy grande porque algunos SID ya no estaban disponibles. (La llamada Translate() hace un SID -> conversión de nombre.)

En primer lugar, GetAuthorizationGroups () es una gran función, pero desafortunadamente tiene 2 desventajas:

  1. El rendimiento es pobre, especialmente en grandes empresas con muchos usuarios y grupos. Obtiene mucha más información de la que realmente necesita y hace una llamada al servidor para cada iteración de bucle en el resultado
  2. Contiene errores que pueden hacer que su aplicación deje de funcionar “algún día” cuando los grupos y los usuarios evolucionan. Microsoft reconoció el problema y está relacionado con algunos SID. El error que obtendrá es “Se produjo un error al enumerar los grupos”

Por lo tanto, escribí una pequeña función para reemplazar GetAuthorizationGroups () con un mejor rendimiento y sin errores. Solo hace 1 llamada LDAP con una consulta usando campos indexados. Se puede extender fácilmente si necesita más propiedades que solo los nombres de grupo (propiedad “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 del AD cada usuario tiene un memberOf . Esto contiene una lista de todos los grupos a los que pertenece.

Aquí hay un pequeño ejemplo 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); } } 

En mi caso, la única forma en que podía seguir usando GetGroups () sin ninguna expiación era agregar al usuario (USER_WITH_PERMISSION) al grupo que tiene permiso para leer el AD (Active Directory). Es extremadamente esencial construir el PrincipalContext pasando este usuario y contraseña.

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

Pasos que puede seguir dentro de Active Directory para que funcione:

  1. En Active Directory crea un grupo (o toma uno) y debajo de la pestaña de seguridad agrega “Windows Authorization Access Group”
  2. Haga clic en el botón “Avanzado”
  3. Seleccione “Grupo de acceso de autorización de Windows” y haga clic en “Ver”
  4. Marque “Leer tokenGroupsGlobalAndUniversal”
  5. Ubique el usuario deseado y agréguelo al grupo que creó (tomado) desde el primer paso

En caso de que Translate funcione localmente pero no remotamente ei group. Traducir (typeof (NTAccount)

Si desea que el código de la aplicación se ejecute utilizando la identidad LOGGED IN USER, habilite la suplantación. La suplantación se puede habilitar a través de IIS o agregando el siguiente elemento en web.config .

   

Si la suplantación está habilitada, la aplicación se ejecuta con los permisos encontrados en su cuenta de usuario. Entonces, si el usuario conectado tiene acceso a un recurso de red específico, solo entonces podrá acceder a ese recurso a través de la aplicación.

Gracias tecnología PRAGIM por esta información de su video diligente

Autenticación de Windows en asp.net Parte 87:

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

Pero la suplantación crea una gran cantidad de gastos generales en el servidor

La mejor solución para permitir a los usuarios de ciertos grupos de red es negar el anonimato en la configuración web

y en su código, preferiblemente en el archivo global.asax, use 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: El grupo debe escribirse con una barra invertida \ ie “TheDomain \ TheGroup”

Esto funciona para mí

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