Comment déterminer tous les groupes auxquels un utilisateur appartient (y compris les groupes imbriqués) dans ActiveDirectory and.NET 3,5

j'ai une application qui utilise ActiveDirecotry autorisation et il a été décidé qu'il doit soutenir imbriquée groupes d'ANNONCES, par exemple:

MAIN_AD_GROUP
     |
     |-> SUB_GROUP
              | 
              |-> User

Donc, l'utilisateur ne directement membre MAIN_AD_GROUP. J'aimerais pouvoir rechercher l'utilisateur de façon récursive, en cherchant les groupes imbriqués dans MAIN_AD_GROUP.

le problème principal est que j'utilise .NET 3.5 et qu'il y a un bug dans System.DirectoryServices.AccountManagement dans .NET 3.5 où la méthode UserPrincipal.IsMemberOf() ne fonctionnera pas pour groupes plus de 1500 utilisateurs. Donc je ne peux pas utiliser UserPrincipal.IsMemberOf() et Non, Je ne peux pas passer à .NET 4 non plus.

j'ai travaillé sur ce dernier problème avec la fonction suivante:

private bool IsMember(Principal userPrincipal, Principal groupPrincipal)
{
    using (var groups = userPrincipal.GetGroups())
    {
        var isMember = groups.Any(g => 
            g.DistinguishedName == groupPrincipal.DistinguishedName);
        return isMember;
    }
}

Mais userPrincipal.GetGroups() ne renvoie que les groupes dont l'utilisateur est un membre direct.

Comment faire pour que cela fonctionne avec les groupes imbriqués?

21
demandé sur Simon 2011-03-15 16:52:10

4 réponses

Solution # 1

Ce bug est signalé ici à Microsoft Connect avec le code suivant qui fonctionne autour de cette question en itérant manuellement à travers le PrincipalSearchResult<Principal> renvoie des objets, enregistrant cette exception, et continuant sur:

PrincipalSearchResult<Principal> groups = user.GetAuthorizationGroups();
var iterGroup = groups.GetEnumerator();
using (iterGroup)
{
    while (iterGroup.MoveNext())
    {
        try
        {
            Principal p = iterGroup.Current;
            Console.WriteLine(p.Name);
        }
        catch (NoMatchingPrincipalException pex)
        {
            continue;
        }
    }
}

Solution # 2

une Autre solution trouvé ici évite les AccountManagement et utilise la classe System.DirectoryServices API au lieu de:

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
using System.DirectoryServices;  

namespace GetGroupsForADUser  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            String username = "Gabriel";  

            List<string> userNestedMembership = new List<string>();  

            DirectoryEntry domainConnection = new DirectoryEntry(); // Use this to query the default domain
            //DirectoryEntry domainConnection = new DirectoryEntry("LDAP://example.com", "username", "password"); // Use this to query a remote domain

            DirectorySearcher samSearcher = new DirectorySearcher();  

            samSearcher.SearchRoot = domainConnection;  
            samSearcher.Filter = "(samAccountName=" + username + ")";  
            samSearcher.PropertiesToLoad.Add("displayName");  

            SearchResult samResult = samSearcher.FindOne();  

            if (samResult != null)  
            {  
                DirectoryEntry theUser = samResult.GetDirectoryEntry();  
                theUser.RefreshCache(new string[] { "tokenGroups" });  

                foreach (byte[] resultBytes in theUser.Properties["tokenGroups"])  
                {  
                    System.Security.Principal.SecurityIdentifier mySID = new System.Security.Principal.SecurityIdentifier(resultBytes, 0);  

                    DirectorySearcher sidSearcher = new DirectorySearcher();  

                    sidSearcher.SearchRoot = domainConnection;  
                    sidSearcher.Filter = "(objectSid=" + mySID.Value + ")";  
                    sidSearcher.PropertiesToLoad.Add("distinguishedName");  

                    SearchResult sidResult = sidSearcher.FindOne();  

                    if (sidResult != null)  
                    {  
                        userNestedMembership.Add((string)sidResult.Properties["distinguishedName"][0]);  
                    }  
                }  

                foreach (string myEntry in userNestedMembership)  
                {  
                    Console.WriteLine(myEntry);  
                }  

            }  
            else 
            {  
                Console.WriteLine("The user doesn't exist");  
            }  

            Console.ReadKey();  

        }  
    }  
}  
32
répondu Tim Lewis 2015-01-02 20:04:59

Utiliser UserPrincipal.GetAuthorizationGroups() au lieu de cela - de son MSDN docs:

Cette méthode recherche tous les groupes de manière récursive et renvoie les groupes dont l'utilisateur est membre. Le retournée peuvent également inclure d'autres groupes système considérer l'utilisateur comme un membre de de autorisation fins.

les groupes qui sont retournés par ceci la méthode peut inclure des groupes d'une champ d'application différent et stocker de l' principal. Pour exemple, si l' le principal est un objet adds qui a un DN de "CN = SpecialGroups, DC=Fabrikam, DC = com, le jeu retourné peut contenir des groupes qui appartiennent à la "CN=NormalGroups, DC=Fabrikam,DC = com.

13
répondu marc_s 2011-03-15 14:19:10

je sais que c'est un vieux fil, mais c'est le résultat de haut sur Google, donc au cas où cela aide quelqu'un, voici ce que j'ai inventé qui utilise les trucs de gestion de Compte, mais rend cette requête particulière beaucoup plus facile.

public static class AccountManagementExtensions
{
    public static bool IsNestedMemberOf(this Principal principal, GroupPrincipal group)
    {
        // LDAP Query for memberOf Nested 
        var filter = String.Format("(&(sAMAccountName={0})(memberOf:1.2.840.113556.1.4.1941:={1}))",
                principal.SamAccountName,
                group.DistinguishedName
            );

        var searcher = new DirectorySearcher(filter);

        var result = searcher.FindOne();

        return result != null;
    }
}
6
répondu GhotiPhud 2016-02-17 17:46:03

la manière efficace est de faire une seule requête publicitaire en ayant le bon filtre DirectorySearcher pour par exemple

public bool CheckMemberShip(string userName)
    {

        bool membership = false;
        string connection = "LDAP://"+YOURDOMAIN;
        DirectoryEntry entry = new DirectoryEntry(connection);
        DirectorySearcher mySearcher = new DirectorySearcher(entry);
        mySearcher.Filter = "(&(objectClass=user)(memberOf:1.2.840.113556.1.4.1941:=cn=GROUPNAME,OU=Groups,OU=ABC,OU=ABC,OU=IND,DC=ad,DC=COMPANY,DC=com)(|(sAMAccountName=" + userName + ")))";
        SearchResult result = mySearcher.FindOne();

        // No search result, hence no membership
        if (result == null)
        {
            membership = false;
        }

        entry.Close();
        entry.Dispose();
        mySearcher.Dispose();

        membership = true;
        return membership;
    }

vous devez remplacer votredomaine et GROUPNAME par les bonnes valeurs de votre annonce.

Source : Comment obtenir récursivement l'appartenance de groupe d'un utilisateur dans Active Directory en utilisant .NET / C# et LDAP (Sans seulement 2 hits dans Active Directory)

Besoin d'inclure using System.DirectoryServices;

1
répondu Antoops 2015-07-30 13:28:20