seguridad para instalar gratis crear como certificado autofirmado ssl active-directory ldap directoryservices edirectory

instalar - ¿Establecer devolución de llamada para System.DirectoryServices.DirectoryEntry para manejar certificado SSL autofirmado?



instalar certificado ssl apache windows (3)

Tengo una aplicación que replica los datos de un servicio de directorio utilizando el código típico System.DirectoryServices.DirectoryEntry. Ahora tengo un requerimiento para replicar desde Novell eDirectory usando SSL con un certificado autofirmado. Sospecho que el código existente funcionaría con un certificado válido que podría verificarse, o quizás si el certificado autofirmado se agrega al almacén de claves de la máquina local. Sin embargo, para que funcione sin problemas con un certificado autofirmado, la única solución que puedo encontrar es utilizar el espacio de nombres System.DirectoryServices.Protocols y la clase LdapConnection, mediante el cual puedo conectar un callback VerifyServerCertificate. No encuentro ninguna forma de aplicar el mismo concepto a una instancia de DirectoryEntry, o de conectar con una instancia de LdapConnection y de alguna manera "convertirla" a una instancia de DirectoryEntry. Tal vez no sea posible, solo me gustaría confirmarlo realmente. Cualquier otro pensamiento bienvenido.

El único vínculo pertinente que he encontrado está en: http://www.codeproject.com/Articles/19097/eDirectory-Authentication-using-LdapConnection-and


He usado el código a continuación para conectarme con ldaps usando DirectoryEntry.

Lo que entendí en mi scenerio es que directoryEntry no funciona cuando se especifica ldaps en la ruta del servidor o el tipo de autenticación se menciona como "AuthenticationTypes.SecureSocketsLayer", pero si solo se menciona el puerto ldaps al final del nombre del servidor, funciona. Después de echar un vistazo al registro de wireshark, puedo ver que el apretón de manos se lleva a cabo como se menciona en la publicación anterior.

Apretón de manos:

Código:

public static SearchResultCollection GetADUsers() { try { List<Users> lstADUsers = new List<Users>(); DirectoryEntry searchRoot = new DirectoryEntry("LDAP://adserver.local:636", "username", "password"); DirectorySearcher search = new DirectorySearcher(searchRoot); search.PropertiesToLoad.Add("samaccountname"); SearchResult result; SearchResultCollection resultCol = search.FindAll(); Console.WriteLine("Record count " + resultCol.Count); return resultCol; } catch (Exception ex) { Console.WriteLine("exception" + ex.Message); return null; } }


Esta es una pregunta fenomenal.

He estado luchando contra este mismo problema durante unos días y finalmente tengo una prueba definitiva de por qué el objeto DirectoryEntry no funcionará en este escenario.

Este servidor Ldap en particular (que se ejecuta en LDAPS 636) también emite su propio certificado autofirmado. Utilizando LdapConnection (y monitoreando el tráfico a través de Wireshark), noté un apretón de manos que no se produce al usar DirectoryEntry:

La primera secuencia es la del servidor ldap seguro, la segunda secuencia es de mi máquina. El código que solicita la segunda secuencia es:

ldapConnection.SessionOptions.VerifyServerCertificate += delegate { return true; };

Hay otras formas de "falsificar" la devolución de llamada, pero esto es lo que he estado usando.

Desafortunadamente, DirectoryEntry no tiene una opción o método para verificar un certificado autofirmado, por lo que la aceptación del certificado nunca ocurre (segunda secuencia) y la conexión no se inicializa.

La única manera factible de lograr esto es mediante el uso de LdapConnection, junto con una SearchRequest y SearchResponse. Esto es lo que tengo hasta ahora:

LdapConnection ldapConnection = new LdapConnection("xxx.xxx.xxx:636"); var networkCredential = new NetworkCredential("Hey", "There", "Guy"); ldapConnection.SessionOptions.SecureSocketLayer = true; ldapConnection.SessionOptions.VerifyServerCertificate += delegate { return true; }; ldapConnection.AuthType = AuthType.Negotiate; ldapConnection.Bind(networkCredential); SearchRequest request = new SearchRequest("DC=xxx,DC=xxx,DC=xxx", "(sAMAccountName=3074861)", SearchScope.Subtree); SearchResponse response = (SearchResponse)ldapConnection.SendRequest(request); if(response.Entries.Count == 1) {SearchResultEntry entry = response.Entries[0]; string DN = entry.DistinguishedName;}

Desde allí, puede recopilar las propiedades de AD desde SearchResponse y procesarlas en consecuencia. Aunque esto es un fastidio total, porque SearchRequest parece ser mucho más lento que usar DirectoryEntry.

¡Espero que esto ayude!


Lo prometo, esta será mi última publicación en esta pregunta en particular. :)

Después de otra semana de investigación y desarrollo, tengo una buena solución para esto, y hasta ahora ha funcionado muy bien para mí.

El enfoque es algo diferente a mi primera respuesta, pero, en general, es el mismo concepto; utilizando LdapConnection para forzar la validación del certificado.

//I set my Domain, Filter, and Root-AutoDiscovery variables from the config file string Domain = config.LdapAuth.LdapDomain; string Filter = config.LdapAuth.LdapFilter; bool AutoRootDiscovery = Convert.ToBoolean(config.LdapAuth.LdapAutoRootDiscovery); //I start off by defining a string array for the attributes I want //to retrieve for the user, this is also defined in a config file. string[] AttributeList = config.LdapAuth.LdapPropertyList.Split(''|''); //Delcare your Network Credential with Username, Password, and the Domain var credentials = new NetworkCredential(Username, Password, Domain); //Here I create my directory identifier and connection, since I''m working //with a host address, I set the 3rd parameter (IsFQDNS) to false var ldapidentifier = new LdapDirectoryIdentifier(ServerName, Port, false, false); var ldapconn = new LdapConnection(ldapidentifier, credentials); //This is still very important if the server has a self signed cert, a certificate //that has an invalid cert path, or hasn''t been issued by a root certificate authority. ldapconn.SessionOptions.VerifyServerCertificate += delegate { return true; }; //I use a boolean to toggle weather or not I want to automatically find and query the absolute root. //If not, I''ll just use the Domain value we already have from the config. if (AutoRootDiscovery) { var getRootRequest = new SearchRequest(string.Empty, "objectClass=*", SearchScope.Base, "rootDomainNamingContext"); var rootResponse = (SearchResponse)ldapconn.SendRequest(getRootRequest); Domain = rootResponse.Entries[0].Attributes["rootDomainNamingContext"][0].ToString(); } //This is the filter I''ve been using : (&(objectCategory=person)(objectClass=user)(&(sAMAccountName={{UserName}}))) string ldapFilter = Filter.Replace("{{UserName}}", UserName); //Now we can start building our search request var getUserRequest = new SearchRequest(Domain, ldapFilter, SearchScope.Subtree, AttributeList); //I only want one entry, so I set the size limit to one getUserRequest.SizeLimit = 1; //This is absolutely crucial in getting the request speed we need (milliseconds), as //setting the DomainScope will suppress any refferal creation from happening during the search SearchOptionsControl SearchControl = new SearchOptionsControl(SearchOption.DomainScope); getUserRequest.Controls.Add(SearchControl); //This happens incredibly fast, even with massive Active Directory structures var userResponse = (SearchResponse)ldapconn.SendRequest(getUserRequest); //Now, I have an object that operates very similarly to DirectoryEntry, mission accomplished SearchResultEntry ResultEntry = userResponse.Entries[0];

La otra cosa que quería señalar aquí es que SearchResultEntry devolverá "atributos" de usuario en lugar de "propiedades".

Los atributos se devuelven como matrices de bytes, por lo que debe codificarlos para obtener la representación de cadena. Afortunadamente, System.Text.Encoding contiene una clase ASCIIEncoding nativa que puede manejar esto muy fácilmente.

string PropValue = ASCIIEncoding.ASCII.GetString(PropertyValueByteArray);

¡Y eso es todo! Muy feliz de finalmente tener esto resuelto.

¡Aclamaciones!