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?
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();
}
}
}
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.
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;
}
}
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.
Besoin d'inclure using System.DirectoryServices;