2010-09-30 2 views
10

Ich habe eine Zeichenfolge, die ich aus LDAP für Active Directory-Gruppenmitgliedschaft abholen, und ich muss es analysieren, um zu überprüfen, ob der Benutzer ein Mitglied der AD-Gruppe ist. Gibt es eine Klasse, die das für mich analysieren kann?Gibt es eine .NET-Klasse, die CN = Strings aus LDAP parsen kann?

Beispiel:

CN=Foo Group Name,DC=mydomain,DC=com 
+0

Klingt wie Sie einen regulären Ausdruck benötigen - RegEx sollte die Arbeit machen ... –

+0

Siehe http://stackoverflow.com/questions/356480/c-extracting-a-name-from-a-string – nos

+0

Ich möchte RegEx nicht verwenden, weil ich die Testkosten nicht übernehmen möchte. Danke für die Anregung. –

Antwort

4

Außerdem, wenn Sie die AD für eine Gruppe Mitglieder abzufragen, können Sie direkt alle der Mitglieder distinguishedName der vergleichen, ohne Parsing Code durch die DirectoryEntry Klasse des System.DirectoryServices Namensraums.

Ansonsten weiß ich einfach nicht von einer solchen Klasse irgendwo. =)

Hoffe das hilft das irgendwie irgendwie!

EDIT # 1

Hier ist ein Link, von dem ich viel gelernt habe, mit dem AD arbeiten und dem System.DirectoryServices Namespace: Howto: (Almost) Everything In Active Directory via C#

Ich werde Sie mit einem Beispielcode in ein paar Tagen zur Verfügung stellen, wenn Sie es immer noch benötigen, wo ich die Objektklasse System.DirectoryServices.DirectorySearcher verwenden werde, um die Mitglieder einer Gruppe abzurufen.

Ich hoffe, dass dieser Link Ihnen helfen wird, wie es für mich getan hat! =)

EDIT # 2

Hier ist das Codebeispiel ich dir erzählt habe. Dies sollte es effizienter machen, gegen die AD zu recherchieren, ohne die AD bakken zu müssen.

public IList<string> GetMembers(string groupName) { 
    if (string.IsNullOrEmpty(groupName)) 
     throw new ArgumentNullException("groupName"); 

    IList<string> members = new List<string>(); 

    DirectoryEntry root = new DirectoryEntry(@"LDAP://my.domain.com"); 
    DirectorySearcher searcher = new DirectorySearcher(); 
    searcher.SearchRoot = root; 
    searcher.SearchScope = SearchScope.Subtree; 
    searcher.PropertiesToLoad.Add("member"); 

    searcher.Filter = string.Format("(&(objectClass=group)(sAMAccountName={0}))", groupName); 

    SearchResult result = searcher.FindOne(); 
    DirectoryEntry groupFound = result.GetDirectoryEntry(); 
    for (int index = 0; index < ((object[])groupFound.Properties["member"].Value).Length; ++index) 
     members.Add((string)((object[])groupFound.Properties["member"].Value)[index]); 

    return members; 

} 

Haftungsausschluss: Dieser Code versehen ist, wie sie ist. Ich habe es auf meinem lokalen Rechner getestet und es funktioniert einwandfrei. Aber da ich es hier nochmal tippen musste, weil ich es nicht einfach kopieren und einfügen konnte, habe ich vielleicht beim Tippen einige Fehler gemacht, die ich nicht wollte.

+0

Das funktionierte ziemlich gut für mich, Problem ist, dass es ziemlich teure Hin- und Rückreisekosten hin und her mit AD ist. Versuche einen Weg sie alle auf einmal zu holen. –

+0

Wenn Sie .NET 3.5 verwenden oder den Namespace 'System.Linq' verwenden, könnten Sie vielleicht daran interessiert sein, das LINQ to AD-Projekt von Bart De Smet auf Codeplex aus dem Auge zu verlieren. Auf diese Weise können Sie LINQ zum Abfragen des AD verwenden. In der Tat, es gibt ein bisschen Arbeit zu tun, um die Bibliothek zu vervollständigen, aber die kritischsten Aspekte sind in seinem Open-Source-Code abgedeckt. –

+0

Wenn Sie direkte Mitglieder einer Gruppe wünschen, rufen Sie 'DirectorySearcher' gegen den DN der Gruppe auf und rufen Sie ihr Attribut' members' für eine Liste von DNs ab. Wenn Sie verschachtelte Mitglieder von Gruppen innerhalb einer Gruppe möchten, rufen Sie das Attribut "tokenGroups" für eine Liste von Objekt-SIDs ab. Ich habe vor einer Weile darüber geschrieben: http://explodingcoder.com/blog/content/how-query-active-directory-security-group-membership – spoulson

8

Wenn Sie weitere Abhängigkeiten nicht hinzufügen möchten, und wollen einfach nur die Zeichenfolge analysieren ..

Diese Art der Zeichenfolge einfach nur String.split analysiert werden können. Um die CN-Werte zu erhalten, wäre etwas wie ..

string[] split = "CN=Foo Group Name,DC=mydomain,DC=com".Split(','); 
List<string> cnValues = new List<string>(); 
foreach(string pair in split){ 
    string[] keyValue=pair.Split('='); 
    if(keyValue[0]=="CN") 
     cnValues.Add(keyValue[1]); 
} 
+0

+1 Dies beantwortet die Frage und ist eine gute Lösung. –

+21

Für diejenigen, die zurücklesen, ist diese Lösung nicht genug für eine Produktionsumgebung - die [RFC] (http://www.rfc-archive.org/getrfc.php?rfc=4514) gibt an, dass Werte zitiert werden können und Es gibt auch Regeln für das Austreten von Charakteren. Das Teilen der Zeichenfolge durch Kommata mit diesem Format ist * hoch * gefährlich. –

6

Diese sind Distinguished Namen genannt.

Codeproject hat einen Parser-Projekt, das zu tun scheint, was Sie brauchen: http://www.codeproject.com/KB/IP/dnparser.aspx

+0

Es wurde auch in ein Github-Projekt und ein nugget-Paket für einfachen Zugriff verpackt. https://github.com/picrap/DNParser/blob/master/README.md –

2
Using System.DirectoryServices; 

namespace GetGroups 
{ 
    public string GetGroupName(string LDAPGroupEntry) 
    { 
     // LDAPGroupEntry is in the form "LDAP://CN=Foo Group Name,DC=mydomain,DC=com" 
     DirectoryEntry grp = new DirectoryEntry(LDAPGroupEntry); 
     return grp.Properties["Name"].Value.ToString(); 
    } 
} 
0

das Parsen Frage zu beantworten, verwenden PInvoke mit DsGetRdnW. Code finden Sie in meiner Antwort auf eine andere Frage: https://stackoverflow.com/a/11091804/628981.

Aber es klingt wie du es falsch machst.Zuerst erhalten Sie die SID für Ihre Zielgruppe:

string targetGroupName = //target group name; 
DirectorySearcher dsTargetGroup = new DirectorySearcher(); 
dsTargetGroup.Filter = string.Format("(sAMAccountName={0})", targetGroupName); 
SearchResult srTargetGroup = dsTargetGroup.FindOne(); 
DirectoryEntry deTargetGroup = srTargetGroup.GetDirectoryEntry(); 
byte[] byteSid = (byte[])deTargetGroup.Properties["objectSid"].Value; 
SecurityIdentifier targetGroupSid = new SecurityIdentifier(byteSid, 0); 

Dann hängt es davon ab, was Sie haben. Wenn der Benutzer Ihre App ausführt (oder an Ihrer Website/Ihrem Dienst authentifiziert ist), listen Sie die SIDs im Token auf. Verwenden Sie beispielsweise in Desktop-Apps WindowsIdentity.GetCurrent().Groups. Andernfalls müssen Sie ein Directory für den Benutzer zu erhalten und dann bekommen die tokenAttributes Attribute wie spoulson vorgeschlagen:

DirectoryEntry deTargetUser = //target user; 
DirectorySearcher dsTargetUser = new DirectorySearcher(deTargetUser); 
dsTargetUser.SearchScope = SearchScope.Base; //tokenGroups is a constructed attribute, so have to ask for it while performing a search 
dsTargetUser.Filter = "(objectClass=*)"; //this is closest thing I can find to an always true filter 
dsTargetUser.PropertiesToLoad.Add("tokenGroups"); 
SearchResult srTargetUser = dsTargetUser.FindOne(); 
foreach(byte[] byteGroupSid in srTargetUser.Properties["tokenGroups"]) 
{ 
    SecurityIdentifier groupSid = new SecurityIdentifier(byteGroupSid, 0); 
    if(groupSid == targetGroupSid) 
    { 
     //success 
    } 
} 

Gerade falls Sie eine Directory von einem SID erhalten müssen, können Sie den Suchbegriff erhalten, indem :

public static string GetSIDSearchFilter(SecurityIdentifier sid) 
{ 
    byte[] byteSid = new byte[sid.BinaryLength]; 
    sid.GetBinaryForm(byteSid, 0); 
    return string.Format("(objectSid={0})", BuildFilterOctetString(byteSid)); 
} 

public static string BuildFilterOctetString(byte[] bytes) 
{ 
    StringBuilder sb = new StringBuilder(); 
    for (int i = 0; i < bytes.Length; i++) 
    { 
     sb.AppendFormat("\\{0}", bytes[i].ToString("X2")); 
    } 
    return sb.ToString(); 
} 
3

Um den DistinquishedName zu parsen, müssen Sie auf die Escape-Zeichen achten. Hier ist eine Methode, die die Zeichenfolge korrekt analysiert und eine Liste von Schlüsselwertpaaren zurückgibt.

public static List<KeyValuePair<string, string>> ParseDistinguishedName(string input) 
    { 
     int i = 0; 
     int a = 0; 
     int v = 0; 
     var attribute = new char[50]; 
     var value = new char[200]; 
     var inAttribute = true; 
     string attributeString, valueString; 
     var names = new List<KeyValuePair<string, string>>(); 

     while (i < input.Length) 
     { 
      char ch = input[i++]; 
      switch(ch) 
      { 
       case '\\': 
        value[v++] = ch; 
        value[v++] = input[i++]; 
        break; 
       case '=': 
        inAttribute = false; 
        break; 
       case ',': 
        inAttribute = true; 
        attributeString = new string(attribute).Substring(0, a); 
        valueString = new string(value).Substring(0, v); 
        names.Add(new KeyValuePair<string, string>(attributeString, valueString)); 
        a = v = 0; 
        break; 
       default: 
        if (inAttribute) 
        { 
         attribute[a++] = ch; 
        } 
        else 
        { 
         value[v++] = ch; 
        } 
        break; 
      } 
     } 

     attributeString = new string(attribute).Substring(0, a); 
     valueString = new string(value).Substring(0, v); 
     names.Add(new KeyValuePair<string, string>(attributeString, valueString)); 
     return names; 
    } 

    static void Main(string[] args) 
    { 
     const string TestString = "CN=BY2STRAKRJOB2,OU=MSNStorage,OU=RESOURCE,OU=PRODUCTION,DC=phx,DC=gbl,STREET=street address,L=locality Name,C=Country Name,UID=user id,STUFF=\\,\\.\\+\"<>;\\=\\0A"; 

     var names = ParseDistinguishedName(TestString); 
     foreach (var pair in names) 
     { 
      Console.WriteLine("{0} = {1}", pair.Key, pair.Value); 
     } 
    } 
+0

Super - danke Alter! –

+2

Ganz wie dieser Ansatz - obwohl es Whitespace von Attributnamen nicht trimmt, und ich hatte einige Probleme mit zitierten Werten, z. O = "VeriSign, Inc." - also habe ich die Dinge ein wenig verändert https://gist.github.com/davetransom/e9c58b96afa46d4c75a0 –

Verwandte Themen