2010-09-30 5 views
10

Tengo una cadena que obtengo de LDAP para la membresía del grupo de Active Directory y necesito analizarla para verificar si el usuario es miembro del grupo de AD. ¿Hay alguna clase que pueda analizar esto por mí?¿Hay una clase .NET que pueda analizar cadenas CN = de LDAP?

Ejemplo:

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

Suena como que necesita una expresión regular - RegEx debe hacer el trabajo ... Ver –

+0

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

+0

No quiero usar RegEx porque no quiero incurrir en el costo de la prueba. Gracias por la sugerencia tú. –

Respuesta

4

Además, si se consulta el anuncio de un miembros del grupo, podrás ser capaz de comparar todas de distinguishedName los miembros directamente sin necesidad de analizar código a través de la clase DirectoryEntry del espacio de nombres System.DirectoryServices.

De lo contrario, simplemente no sé de una clase así en alguna parte. =)

Espero que esto ayude de todos modos de alguna manera!

editar # 1

Aquí hay un enlace desde el que he aprendido mucho trabajando con el AD y el System.DirectoryServices espacio de nombres: Howto: (Almost) Everything In Active Directory via C#

que se le proporcionará un código de ejemplo en unos pocos días, si aún lo requiere, donde usaré la clase de objeto System.DirectoryServices.DirectorySearcher para recuperar los miembros de un grupo.

¡Espero que este enlace te ayude como lo hizo por mí! =)

editar # 2

Aquí está el ejemplo de código que te hablé. Esto debería hacer que sea más eficiente consultar contra el AD sin tener que trabajar bakc y adelante el AD.

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; 

} 

Negación: Se proporciona este código como está. Lo probé en mi máquina local y funciona perfectamente bien. Pero debido a que tuve que volver a escribir aquí porque no pude copiarlo y pegarlo, tal vez cometí algunos errores al escribir, lo que desearía que no ocurriera.

+0

Esto funcionó bastante bien para mí, el problema es que el costo de ida y vuelta es bastante caro yendo y viniendo con AD. Intentando buscarlos de una vez. –

+0

Si usa .NET 3.5 o puede usar el espacio de nombres 'System.Linq', quizás le interese echarle un vistazo al proyecto LINQ to AD de Bart De Smet en Codeplex. Esto le permite usar LINQ para consultar contra el AD. De hecho, hay un poco de trabajo por hacer para completar la biblioteca, pero los aspectos más críticos están cubiertos dentro de su código fuente abierto. –

+0

Si desea miembros inmediatos de un grupo, llame a 'DirectorySearcher' contra el DN del grupo y obtenga su atributo' members' para obtener una lista de DN. Si desea miembros anidados de grupos dentro de un grupo, obtenga el atributo 'tokenGroups' para obtener una lista de SID de objetos. Escribí sobre esto hace un tiempo: http://explodingcoder.com/blog/content/how-query-active-directory-security-group-membership – spoulson

8

Si no desea agregar dependencias adicionales y sólo quiere analizar la cadena ..

Este tipo de cadena sencilla se puede analizar usando sólo string.split. Para obtener los valores CN, sería algo así como ...

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 Esto responde la pregunta y es una buena solución. –

+21

Para quienes lean nuevamente, esta solución no es suficiente para un entorno de producción: el [RFC] (http://www.rfc-archive.org/getrfc.php?rfc=4514) especifica que los valores pueden ser citados y también hay reglas de escape de personajes. Además, dividir la cadena por comas con este formato es * altamente * peligroso. –

6

Estos se llaman nombres completos.

CodeProject tiene un proyecto analizador que parece hacer lo que necesita: http://www.codeproject.com/KB/IP/dnparser.aspx

+0

También se ha incluido en un proyecto github y en un paquete nuget para facilitar el acceso. 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

Para responder a la pregunta de análisis, utilice PInvoke con DsGetRdnW. Para el código, vea mi respuesta a otra pregunta: https://stackoverflow.com/a/11091804/628981.

Pero parece que lo estás haciendo mal.Primero, obtenga el SID para su grupo objetivo:

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

Luego, depende de lo que tenga. Si el usuario está ejecutando su aplicación (o autenticada en su sitio web/servicio), enumere los SID en el token. Por ejemplo, en aplicaciones de escritorio, use WindowsIdentity.GetCurrent().Groups. De lo contrario, tendrá que obtener un DirectoryEntry para el usuario y luego obtener el atributo tokenAttributes como spoulson sugirió:

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

En caso de que necesita para obtener un DirectoryEntry de una SID, se puede obtener el texto que desea buscar :

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

Para analizar el DistinquishedName debe prestar atención a los caracteres de escape. Aquí hay un método que analizará la cadena correctamente y devolverá una lista de pares de valores clave.

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

Impresionante - gracias amigo! –

+2

Muy similar a este enfoque, aunque no elimina el espacio en blanco de los nombres de atributos, y tuve algunos problemas con los valores entrecomillados, como p. Ej. O = "VeriSign, Inc." - Así que modifiqué un poco las cosas https://gist.github.com/davetransom/e9c58b96afa46d4c75a0 –

Cuestiones relacionadas