2009-08-12 8 views
4

J'ai créé un service Web WCF pour renvoyer des informations sur les utilisateurs et les groupes à partir d'Active Directory. Cela fonctionne pour la plupart des groupes et des utilisateurs.DirectoryEntry.Invoke ("groups", null) ne récupère pas tous les groupes?

J'utilise directoryEntry.Invoke ("groups", null) pour retourner les groupes dont un utilisateur spécifié est membre. Cela renvoie les groupes MOST. La chose étrange est que je peux trouver n'importe quel groupe et énumérer ses membres, même si c'est l'un des groupes manquants quand j'utilise la requête d'invocation sur un de ses membres.

La plupart des groupes qui présentent ce comportement sont compatibles avec Exchange. La plupart des comptes d'utilisateurs problématiques concernent les utilisateurs d'un domaine fédéré qui utilisent un serveur Exchange dans le domaine interrogé. Je n'essaie pas d'interroger des objets dans le domaine fédéré.

Mes théories à ce jour:

  • certaines restrictions de sécurité ne permet pas tous les groupes par l'énumération Invoke(), même si je peux interroger les groupes manquants et d'énumérer leurs membres.

  • invoke a des problèmes avec certains sous-groupes de groupes. La méthode invoke ne récupère pas tous les groupes car les comptes "fédérés" (créés dans le cadre de leur configuration du compte Exchange) sont différents des comptes de domaine habituels. au-delà de la cartographie Sid retour à leur domaine de connexion.

Répondre

5

Il y a deux problèmes connus à l'utilisation des « groupes » propriété sur un DirectoryEntry:

  • il ne sera pas vous montrer le « groupe par défaut » un utilisateur est (généralement « Utilisateurs »)
  • il ne sera pas vous montrer groupe imbriqué appartenances

donc, si un utilisateur est membre d'un groupe a, et ce groupe à son tour est membre du groupe B, puis sous Windows, cela signifie que l'utilisateur est également membre de Groupe B. Toutefois, DirectoryEntry ne vous montrera pas cette appartenance à un groupe imbriqué.

Ce sont les deux seules restrictions que je connais pour Active Directory direct (sans Exchange).

Obtenir le groupe par défaut est un peu impliqué, mais j'ai un échantillon de code pour cela.

private string GetPrimaryGroup(DirectoryEntry aEntry, DirectoryEntry aDomainEntry) 
{ 
    int primaryGroupID = (int)aEntry.Properties["primaryGroupID"].Value; 
    byte[] objectSid = (byte[])aEntry.Properties["objectSid"].Value; 

    StringBuilder escapedGroupSid = new StringBuilder(); 

    // Copy over everything but the last four bytes(sub-authority) 
    // Doing so gives us the RID of the domain 
    for(uint i = 0; i < objectSid.Length - 4; i++) 
    { 
     escapedGroupSid.AppendFormat("\\{0:x2}", objectSid[i]); 
    } 

    //Add the primaryGroupID to the escape string to build the SID of the primaryGroup 
    for(uint i = 0; i < 4; i++) 
    { 
     escapedGroupSid.AppendFormat("\\{0:x2}", (primaryGroupID & 0xFF)); 
     primaryGroupID >>= 8; 
    } 

    //Search the directory for a group with this SID 
    DirectorySearcher searcher = new DirectorySearcher(); 
    if(aDomainEntry != null) 
    { 
     searcher.SearchRoot = aDomainEntry; 
    } 

    searcher.Filter = "(&(objectCategory=Group)(objectSID=" + escapedGroupSid.ToString() + "))"; 
    searcher.PropertiesToLoad.Add("distinguishedName"); 

    return searcher.FindOne().Properties["distinguishedName"][0].ToString(); 
} 

Obtenir les groupes imbriqués prend également quelques pas et je vais devoir chasser pour une solution à celui-là, si c'est le problème.

Marc

PS: comme une note de côté - pourquoi diable fais-tu un "DirectoryEntry.Invoke (" groupes "null)" appel? Pourquoi ne pas simplement énumérer la propriété DirectoryEntry.Properties ["memberOf"] qui est multi-valuée (contient plusieurs valeurs) et a le DN (nom distinctif) du groupe dedans?

foreach(string groupDN in myUser.Properties["memberOf"]) 
{ 
    string groupName = groupDN; 
} 

ou si vous êtes sur .NET 3.5, vous pouvez utiliser de la nouvelle sécurité classes principales dans S.DS.AccountManagement.L'un d'eux est un "UserPrincipal", qui a une méthode appelée "GetAuthorizationGroups()" qui fait tout ce dur travail pour vous - gratuitement, fondamentalement!

Voir un excellent MSDN article qui décrit ces nouvelles fonctionnalités .NET 3.5 S.DS pour vous.

+0

Ces sont de bonnes suggestions et vous avez raison sur l'article MSDN, j'aurais dû lire cela avant de commencer. En ce qui concerne les raisons pour lesquelles j'ai utilisé la méthode invoke, dans ce cas, tout ce dont j'avais besoin était les noms des groupes, et cela semblait être un moyen efficace d'obtenir l'information. Je n'ai pas fait beaucoup de programmation sur Active Directory, donc j'apprends toujours la meilleure façon de procéder. Il est intéressant combien .NET a évolué dans ce domaine depuis 1.1! – HeathenWorld

+0

Pas de problème du tout - juste curieux si vous aviez une raison particulière d'utiliser l'approche Invoke(). Et bon - c'est ce que propose StackOverflow - vous aider lorsque vous ne voyez pas la forêt pour les arbres :-) –

+0

+1 pour l'article MSDN lié, beaucoup plus facile dans 3.5 – tbone

0

Je pense que marc_s est correct. Si vous voulez que tous les groupes, vous pouvez utiliser l'extrait suivant:

using (DirectoryEntry obj = new DirectoryEntry("LDAP://" + dn)) 
{ 
    obj.RefreshCache(new string[] { "tokenGroups" }); 
    string[] sids = new string[obj.Properties["tokenGroups"].Count]; 
    int i = 0; 
    foreach (byte[] bytes in obj.Properties["tokenGroups"]) 
    { 
     sids[i] = _ConvertSidToString(bytes); 
     ++i; 
    } 
    obj.Close(); 
    return sids; 
} 

Notez que le calcul des groupes imbriqués est une opération coûteuse, donc RefreshCache peut prendre beaucoup de temps.

0

Sur Freund,

Je suis en train d'utiliser votre code et ne pas obtenir très loin. J'ai mis à jour le chemin d'accès au répertoire "LDAP: // DC = monDomaine, DC = co, DC = Royaume-Uni" mais je n'obtiens aucun résultat (obj.Properties ["tokenGroups"]. Count = 0)

Je ne sais pas comment l'utilisateur à la liste de groupe est spécifié.

Pourriez-vous me diriger dans la bonne direction?

Merci

EDIT:

Je l'ai trié à la fin. L'entrée de répertoire pour obtenir les groupes de jeton doit être une entrée utilisateur ... si cela fait sens ...

J'ai inclus un code au cas où quelqu'un d'autre a la même requête:

Dim directoryEntry As DirectoryEntry = _ 
     New DirectoryEntry("LDAP://CN=users,DC=domanName,DC=com") 
Dim directorySearcher As DirectorySearcher = _ 
     New DirectorySearcher(directoryEntry, "(sAMAccountName=" & UserName & ")") 
Dim searchResult As SearchResult = directorySearcher.FindOne() 

If Not searchResult Is Nothing Then 
    Dim userDirectoryEntry As DirectoryEntry = searchResult.GetDirectoryEntry 
    userDirectoryEntry.RefreshCache(New String() {"tokenGroups"}) 
    ... etc ... 
End If 
Questions connexes