5 Stimmen

DirectoryEntry.Invoke("groups",null) ruft nicht alle Gruppen ab?

Ich habe einen WCF-Webdienst erstellt, um Benutzer- und Gruppeninformationen aus Active Directory zurückzugeben. Er funktioniert für die meisten Gruppen und Benutzer.

Ich verwende directoryEntry.Invoke("groups",null), um die Gruppen zurückzugeben, in denen ein bestimmter Benutzer Mitglied ist. Dies gibt MOST Gruppen zurück. Das Seltsame ist, dass ich jede Gruppe finden und ihre Mitglieder aufzählen kann, auch wenn sie eine der Gruppen ist, die fehlt, wenn ich die Abfrage "Invoke" auf eines ihrer Mitglieder anwende.

Die meisten Gruppen, die dieses Verhalten zeigen, sind Exchange-aktiviert. Die meisten problematischen Benutzerkonten sind für Benutzer in einer Verbunddomäne, die einen Exchange-Server in der Domäne verwenden, die ich abfrage. Ich versuche nicht, Objekte in der Verbunddomäne abzufragen.

Meine bisherigen Theorien:

  • einige Sicherheitseinschränkungen erlauben es nicht, alle Gruppen über invoke() aufzuzählen, obwohl ich fehlende Gruppen abfragen und ihre Mitglieder aufzählen kann.

  • Aufruf hat Probleme mit einer Untergruppe von Gruppen. Vielleicht sind universelle, dynamische oder Exchange-aktivierte Eigenschaften im Spiel

  • Die Aufrufmethode erfasst nicht alle Gruppen, da sich die "föderierten" Konten (die im Rahmen der Einrichtung des Exchange-Kontos erstellt wurden) in gewisser Weise von normalen Domänenkonten unterscheiden, abgesehen von der sid-Zuordnung zu ihrer Anmeldedomäne.

7voto

marc_s Punkte 701497

Es gibt zwei bekannte Probleme bei der Verwendung der Eigenschaft "Gruppen" für einen DirectoryEntry:

  • die "Standardgruppe", in der sich ein Benutzer befindet (normalerweise "Benutzer"), wird nicht angezeigt
  • es werden keine verschachtelten Gruppenmitgliedschaften angezeigt

Wenn also ein Benutzer Mitglied einer Gruppe A ist und diese Gruppe wiederum Mitglied der Gruppe B ist, dann bedeutet dies in Windows, dass der Benutzer auch Mitglied der Gruppe B ist.

Das sind die beiden einzigen Einschränkungen, die ich für ein reines Active Directory (ohne Exchange) kenne.

Das Abrufen der Standardgruppe ist ein wenig kompliziert, aber ich habe ein Codebeispiel dafür.

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

Um die verschachtelten Gruppen zu erhalten, sind ebenfalls einige Schritte erforderlich, und ich werde nach einer Lösung für dieses Problem suchen müssen, falls es das ist.

Marc

PS: als Randbemerkung - warum in aller Welt machen Sie einen "DirectoryEntry.Invoke("groups", null)" Aufruf? Warum zählen Sie nicht einfach die Eigenschaft DirectoryEntry.Properties["memberOf"] auf, die mehrwertig ist (mehrere Werte enthält) und den DN (distinguished name) der Gruppe enthält?

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

ODER wenn Sie mit .NET 3.5 arbeiten, können Sie die neuen Sicherheitsprinzipal-Klassen in S.DS.AccountManagement verwenden. Eine davon ist ein "UserPrincipal", das eine Methode namens "GetAuthorizationGroups()" hat, die all diese harte Arbeit für Sie erledigt - im Grunde kostenlos!

Siehe eine ausgezeichnete MSDN-Artikel das diese neuen .NET 3.5 S.DS-Funktionen für Sie beschreibt.

0voto

On Freund Punkte 4346

Ich denke, marc_s hat Recht. Wenn Sie alle Gruppen wollen, können Sie das folgende Snippet verwenden:

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

Beachten Sie, dass die Berechnung von verschachtelten Gruppen ein kostspieliger Vorgang ist, so dass RefreshCache lange Zeit in Anspruch nehmen kann.

0voto

Über Freund,

Ich versuche, Ihren Code zu verwenden und komme nicht sehr weit. Ich habe den Verzeichniseintragspfad auf "LDAP://DC=myDomain,DC=co,DC=uk" aktualisiert, aber ich erhalte keine Ergebnisse (obj.Properties["tokenGroups"].Count = 0)

Ich verstehe nicht, wie der Benutzer, für den die Gruppe aufgelistet werden soll, angegeben wird.

Könnten Sie mir bitte die richtige Richtung weisen?

Gracias

EDIT:

Am Ende habe ich es hinbekommen. Der Verzeichniseintrag, aus dem die Token-Gruppen abgerufen werden, sollte ein Benutzereintrag sein... wenn das Sinn macht...

Ich habe etwas Code beigefügt, falls jemand die gleiche Frage hat:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X