Active Directory – c# Operaciones LDAP basicas con DirectoryServices

Active Directory csharp
Active Directory csharp

Para descargar el código haz clic acá.

 Consultar información de un usuario

using (var entryRoot = 
new DirectoryEntry("LDAP://localhost:389/OU=ADAM users,DC=prueba,DC=adam"))
{
    using (var buscadorDirectorio = new DirectorySearcher(entryRoot))
    {

        buscadorDirectorio.Filter = 
            string.Format("(&(objectCategory=person)(objectClass=user)(cn={0}))",nombreUsuario);

        //Agregar todos los campos que se desean traer
        buscadorDirectorio.PropertiesToLoad.Add("url");
        buscadorDirectorio.PropertiesToLoad.Add("mail");
        buscadorDirectorio.PropertiesToLoad.Add("name");
        buscadorDirectorio.PropertiesToLoad.Add("distinguishedName");

        SearchResult resultado = buscadorDirectorio.FindOne();

        Console.WriteLine("DistinguishedName: {0}", resultado.Properties["distinguishedName"][0]);
        Console.WriteLine("Url: {0}", resultado.Properties["url"][0]);
        Console.WriteLine("Mail: {0}", resultado.Properties["mail"][0]);
        Console.WriteLine("Name: {0}", resultado.Properties["name"][0]);
    }
}

En caso se use una conexión segura se debe cambiar el puerto de 389 a 636.

Autenticar un usuario

var tipoAutenticacion = 
    AuthenticationTypes.None | AuthenticationTypes.FastBind;
var identificador = 
    string.Format("CN={0},OU=ADAM users,DC=prueba,DC=adam",usuario);
using (var entry =
    new DirectoryEntry(
        "LDAP://localhost:389/OU=ADAM users,DC=prueba,DC=adam",
        identificador, 
        contrasena,
        tipoAutenticacion))
{
    object nativeObject = entry.NativeObject;
}

En caso se use una conexión segura se debe cambiar el puerto de 389 a 636 y se deberá cambiar el valor de la variable tipoAutenticacion por lo siguiente:

var tipoAutenticacion = 
    AuthenticationTypes.SecureSocketsLayer | AuthenticationTypes.Secure;

Si aparece este mensaje de error: “Additional information: El nombre de usuario o la contraseña no son correctos.” quiere decir que el usuario o la contraseña no son correctos y no se pudo autenticar.

El identificador del usuario puede tener cualquiera de estos formatos:

  • usuario@domino, ejemplo: laldazabal@nerv.com
  • distinguishedName, ejemplo: CN=laldazabal,OU=ADAM users,DC=prueba,DC=adam
  • dominio\usuario, ejemplo: nerv\laldazabal

En el caso en particular donde aplique este método tuve que usar el formato distinguishedName.

Cambiar la contraseña de un usuario

public void CambiarContrasena(string usuario, 
               string contrasenaAntigua, string contrasenaNueva)
{
    var identificador= 
        string.Format("LDAP://localhsot:389/CN={0},OU=ADAM users,DC=prueba,DC=adam", usuario);
    var tipoAutenticacion =
        AuthenticationTypes.Signing | AuthenticationTypes.Sealing 
        | AuthenticationTypes.Secure;
    using (var entry = 
    new DirectoryEntry(identificador, null, null, tipoAutenticacion))
    {
        entry.RefreshCache();

        entry.Options.PasswordPort = 389;
        entry.Options.PasswordEncoding = PasswordEncodingMethod.PasswordEncodingClear;

        entry.Invoke("ChangePassword", new object[] {contrasenaAntigua, contrasenaNueva});

        entry.CommitChanges();
    }
}

En caso se use una conexión segura se debe cambiar el puerto de 389 a 636 y se deberá cambiar el valor de la variable tipoAutenticacion por lo siguiente:

var tipoAutenticacion = 
    AuthenticationTypes.SecureSocketsLayer | AuthenticationTypes.Secure;

También se deberá cambiar el valor de la propiedad PasswordEncoding por el siguiente valor:

entry.Options.PasswordEncoding = PasswordEncodingMethod.PasswordEncodingSsl; 

Si aparece este mensaje de error: “-2147016672 00002077: SvcErr: DSID-03380715, problem 5012 (DIR_ERROR), data 8237 An operations error occurred. (Exception from HRESULT: 0x80072020L) puede ser que el tipo de autenticación usada no es la correcta. Hay que tener cuidado con este error ya que es muy genérico, en mi caso se solucionó  cambiando el tipo de autenticación.

Si aparece este mensaje de error: “-2147016657 00000056: AtrErr: DSID-033807A7, #1: 0: 00000056: DSID-033807A7, problem 1005 (CONSTRAINT_ATT_TYPE), data 2203, Att 9005a (unicodePwd) A constraint violation ocurred. (Excepción de HRESULT: 0x8007202F)” quiere decir que la contraseña anterior no es correcta.

Si aparece este mensaje de error: “-2147016657 0000052D: AtrErr: DSID-033807B1 #1: 0: 0000052D: DSID-033807B1, problem 1005 (CONSTRAINT_ATT_TYPE), data 2246, Att 9005a (unicodePwd) A constraint violation ocurred. (Excepción de HRESULT: 0x8007202F)” quiere decir que la nueva contraseña no cumple con las políticas de fortaleza de password que tiene el Active Directory.

Otra forma de enviar las opciones del password es la siguiente:

private const long OptionPasswordPortnumber = 6;
private const long OptionPasswordMethod = 7;

entry.Invoke("SetOption", OptionPasswordPortnumber, 389);
entry.Invoke("SetOption", OptionPasswordMethod, PasswordEncodingMethod.PasswordEncodingClear);

Resetear la contraseña de un usuario

public void ResetearContrasena(string usuario,string contrasenaNueva)
{
    var identificador= 
        string.Format("LDAP://localhsot:389/CN={0},OU=ADAM users,DC=prueba,DC=adam", usuario);
    var tipoAutenticacion =
        AuthenticationTypes.Signing | AuthenticationTypes.Sealing 
        | AuthenticationTypes.Secure;
    using (var entry = 
    new DirectoryEntry(identificador, null, null, tipoAutenticacion))
    {
        entry.RefreshCache();

        entry.Options.PasswordPort = 389;
        entry.Options.PasswordEncoding = PasswordEncodingMethod.PasswordEncodingClear;

        entry.Invoke("SetPassword", new object[] {contrasenaNueva});

        entry.CommitChanges();
    }
}

Nota: Tener en cuenta las mismas recomendaciones y errores  que suceden con el cambio de contraseña.

Diferencias entre ChangePassword y SetPassword

SetPassword
  • Requiere solo la nueva contraseña
  • No aplica las políticas de fortaleza de contraseña
ChangePassword
  • Requiere la nueva y la antigua contraseña
  • Aplica las políticas de fortaleza de contraseña

Para más información sobre las diferencias que existen entre estos dos comandos les recomiendo que lean este artículo.

Recomendaciones

Buscar sobre el Active Directory es una tarea muy costosa estas recomendaciones conseguirán que tus consultas se ejecuten más rápido:

1. Hacer las consultas sobre el contenedor que almacena los objetos que se desean buscar.

Bad: LDAP://localhost:389/DC=adam

Good: LDAP://localhsot:389/OU=ADAM users,DC=pacifico,DC=adam

2. Limitar el scope de una búsqueda.
Bad

using (var buscadorDirectorio = new DirectorySearcher(entryRoot))
{
    buscadorDirectorio.Filter = "(cn=testig)";
    SearchResult resultado = buscadorDirectorio.FindOne();
    //Codigo
}

 Good

using (var buscadorDirectorio = new DirectorySearcher(entryRoot))
{
    buscadorDirectorio.Filter = 
      "(&(objectCategory=person)(objectClass=user)(cn=testig))";
    SearchResult resultado = buscadorDirectorio.FindOne();
    //Codigo
}

3. Limitar la cantidad de campos que se desean traer.
Bad:

using (var entryRoot = new DirectoryEntry("LDAP://localhost:389/DC=adam"))
{
    using (var buscadorDirectorio = new DirectorySearcher(entryRoot))
    {
        buscadorDirectorio.Filter = "(cn=testig)";

        SearchResult resultado = buscadorDirectorio.FindOne();
        //Codigo
    }
}

Good:

using (var entryRoot = 
new DirectoryEntry("LDAP://localhost:389/OU=ADAM users,DC=prueba,DC=adam"))
{
    using (var buscadorDirectorio = new DirectorySearcher(entryRoot))
    {
        buscadorDirectorio.Filter = 
            "(&(objectCategory=person)(objectClass=user)(cn=testig))";

        //Agregar todos los campos que se desean traer
        buscadorDirectorio.PropertiesToLoad.Add("url"); 
        //Otros campos
        buscadorDirectorio.PropertiesToLoad.Add("distinguishedName");

        SearchResult resultado = buscadorDirectorio.FindOne();
        //Codigo
    }
}

Para descargar el código haz clic acá.

Conclusión:

Active Directory brinda la facilidad de hacer consultas y ejecutar comandos que permitan satisfacer la necesidad de un aplicativo. Primero, vimos la forma en que se debe hacer una consulta para recuperar los datos de un objeto. Luego, vimos el código necesario para autenticar a un usuario. A continuación, vimos los códigos para cambiar y resetear contraseña, aunque se ven parecidos en el fondo hay consideraciones que se deben tener en cuenta antes de usar cada uno. Finalmente, mencionamos algunas recomendaciones que se deben de tener en cuenta para que mejore el tiempo de respuesta de las consulta que realicemos sobre el Active Directory.

Referencias:
Metal Tip:

Este artículo lo escribí escuchando la canción My Hope, The Destroyer de la banda My Dying Bride de El Reunio Unido, les comparto el enlace.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s