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;
}
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;
}
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.)
Tout d’abord, GetAuthorizationGroups () est une fonction intéressante mais présente malheureusement 2 inconvénients:
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;
}
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);
}
}
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:
- Dans Active Directory, créez un groupe (ou prenez-en un) et sous l'onglet Secutiry, ajoutez "Windows Authorization Access Group"
- Cliquez sur le bouton "Avancé"
- Sélectionnez "Windows Authorization Access Group" et cliquez sur "View"
- Cochez "Lire tokenGroupsGlobalAndUniversal"
- Localisez l'utilisateur souhaité et ajoutez-le au groupe que vous avez créé (pris) dès la première étape.
Ç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();
}
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"
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();