web-dev-qa-db-fra.com

Comment obtenir les groupes d'un utilisateur dans Active Directory? (c #, asp.net)

J'utilise ce code pour obtenir les groupes de l'utilisateur actuel. Mais je veux donner à l'utilisateur manuellement et ensuite obtenir ses groupes. Comment puis-je faire ceci?

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

Si vous utilisez une version .NET 3.5 ou ultérieure, vous pouvez utiliser le nouvel espace de noms System.DirectoryServices.AccountManagement (S.DS.AM), ce qui simplifie grandement la tâche.

Lisez tout a propos de ça ici: Gestion des entités principales de sécurité de l'annuaire dans le .NET Framework 3.5

Mise à jour: les anciens articles du magazine MSDN ne sont plus en ligne, malheureusement - vous devez télécharger le CHM du magazine MSDN de janvier 2008 de Microsoft et lire l'article qui s'y trouve.

En gros, vous devez avoir un "contexte principal" (généralement votre domaine), un principal utilisateur, puis vous obtenez très facilement ses groupes:

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

et c'est tout ce qu'il y a! Vous avez maintenant un résultat (une liste) de groupes d’autorisations auxquels l’utilisateur appartient: parcourez-les, imprimez leurs noms ou faites ce que vous devez faire.

Update: Pour accéder à certaines propriétés qui ne sont pas surfacées sur l'objet UserPrincipal, vous devez creuser dans la DirectoryEntry sous-jacente:

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

Mise à jour n ° 2: semble ne devrait pas être trop difficile de mettre ces deux extraits de code ensemble .... mais bon, voilà:

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

GetAuthorizationGroups() ne trouve pas les groupes imbriqués. Pour vraiment obtenir tous les groupes dont un utilisateur donné est membre (y compris les groupes imbriqués), essayez ceci:

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

J'utilise try/catch parce que j'avais quelques exceptions avec 2 groupes sur 200 dans une très grande AD car certains SID n'étaient plus disponibles. (L’appel Translate() effectue une conversion SID -> Nom.)

51
Mickey Mouse

Tout d’abord, GetAuthorizationGroups () est une fonction intéressante mais présente malheureusement 2 inconvénients:

  1. Les performances sont médiocres, en particulier dans les grandes entreprises comptant de nombreux utilisateurs et groupes. Il récupère beaucoup plus de données que nécessaire et effectue un appel de serveur pour chaque itération de boucle dans le résultat.
  2. Il contient des bogues qui peuvent empêcher votre application de fonctionner «un jour» lorsque les groupes et les utilisateurs évoluent. Microsoft a reconnu le problème et est lié à certains SID. L'erreur que vous obtenez est "Une erreur s'est produite lors de l'énumération des groupes"

Par conséquent, j'ai écrit une petite fonction pour remplacer GetAuthorizationGroups () par de meilleures performances et une sécurité optimale. Il ne fait qu'un appel LDAP avec une requête utilisant des champs indexés. Il peut être facilement étendu si vous avez besoin de plus de propriétés que seulement les noms de groupe (propriété "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;
}
14
Bigjim

Dans l’AD, chaque utilisateur a une propriété memberOf. Ceci contient une liste de tous les groupes auxquels il appartient.

Voici un petit exemple de code:

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

Dans mon cas, la seule façon pour moi de continuer à utiliser GetGroups () sans aucune restriction était d'ajouter l'utilisateur (USER_WITH_PERMISSION) au groupe autorisé à lire AD (Active Directory). Il est extrêmement essentiel de construire le PrincipalContext en passant cet utilisateur et mot de passe.

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

Les étapes que vous pouvez suivre dans Active Directory pour le faire fonctionner:

  1. Dans Active Directory, créez un groupe (ou prenez-en un) et sous l'onglet Secutiry, ajoutez "Windows Authorization Access Group"
  2. Cliquez sur le bouton "Avancé"
  3. Sélectionnez "Windows Authorization Access Group" et cliquez sur "View"
  4. Cochez "Lire tokenGroupsGlobalAndUniversal"
  5. Localisez l'utilisateur souhaité et ajoutez-le au groupe que vous avez créé (pris) dès la première étape.
1
Gandarez

Ça marche pour moi

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
Taran

Dans le cas où Translate fonctionne localement mais pas à distance e.i groupe .Translate (typeof (NTAccount)

Si vous souhaitez que le code de l'application s'exécute sous l'identité LOGGED IN USER, activez l'emprunt d'identité. L'emprunt d'identité peut être activé via IIS ou en ajoutant l'élément suivant dans le fichier web.config.

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

Si l'emprunt d'identité est activé, l'application s'exécute en utilisant les autorisations trouvées dans votre compte d'utilisateur. Ainsi, si l'utilisateur connecté a accès à une ressource réseau spécifique, il sera alors le seul à pouvoir accéder à cette ressource via l'application.

Merci à PRAGIM tech pour cette information tirée de sa vidéo diligente

Authentification Windows dans asp.net Partie 87: 

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

Mais l'emprunt d'identité crée beaucoup de surcharge sur le serveur

La meilleure solution pour autoriser les utilisateurs de certains groupes du réseau est de refuser l'anonymat dans la configuration Web <authorization><deny users="?"/><authentication mode="Windows"/>

et dans votre code derrière, de préférence dans le fichier global.asax, utilisez le 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

Remarque: le groupe doit être écrit avec une barre oblique inverse\i.e. "TheDomain\TheGroup"

0

La réponse dépend du type de groupe que vous souhaitez récupérer. L'espace de nom System.DirectoryServices.AccountManagement fournit deux méthodes de récupération de groupe:

GetGroups - Retourne une collection d'objets groupe qui spécifient les groupes dont le principal actuel est membre.

Cette méthode surchargée ne renvoie que les groupes dont le principal est directement membre; aucune recherche récursive n'est effectuée.

GetAuthorizationGroups - Retourne une collection d'objets principaux contenant tous les groupes d'autorisations dont cet utilisateur est membre. Cette fonction ne renvoie que les groupes qui sont des groupes de sécurité. les groupes de distribution ne sont pas renvoyés.

Cette méthode recherche tous les groupes de manière récursive et renvoie les groupes dont l'utilisateur est membre. L'ensemble renvoyé peut également inclure des groupes supplémentaires que le système considérerait comme un membre de l'utilisateur à des fins d'autorisation. 

Ainsi, GetGroups obtient tous les groupes dont l'utilisateur est un membre direct et GetAuthorizationGroups obtient tous les groupes autorisation dont l'utilisateur est un membre direct ou indirect.

Malgré la manière dont ils sont nommés, l’un n’est pas un sous-ensemble de l’autre. Il peut y avoir des groupes retournés par GetGroups non retournés par GetAuthorizationGroups et vice versa.

Voici un exemple d'utilisation:

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
Tawab Wakil