Attributes

[HowTo] Obtener el valor de una propiedad de usuario en LDAP

Posted on Updated on

El motivo

A raíz de una pregunta que me lanzó ayer mi colega Ricardo, hoy vamos a ver cómo obtener el valor de una propiedad de un usuario del directorio activo de la organización. Esto de por si, no tiene ningún secreto, basta con utilizar las clases contenidas en el namespace System.DirectoryServices. Lo que sí tenemos que tener muy claro, es el nombre de esa propiedad dentro del esquema del LDAP de nuestra organización.

GetPropADUser

Por ejemplo, para obtener el mail, la propiedad a utilizar es mail, obvio, no? Sin embargo en otras ocasiones no siempre es así. Por ejemplo, el nombre de la propiedad que nos devuelve el teléfono de un usuario es telephoneNumber, el código postal es postalCode, pero por ejemplo la propiedad que nos devuelve los apellidos, no es surname, sino sn, o el nombre del usuario está definido como sAMAccountName. En resumen, muchas de las propiedades están definidas con unos nombres… como decirlo? Muy cachondos 😛

Obtener los atributos de una clase

A todo esto ¿Cómo podemos obtener los nombres de los atributos de un usuario del LDAP en tiempo de ejecución? Easy –> Buscando la definición de la clase user en el esquema de nuestro LDAP y obteniendo su catálogo de propiedades (básicas + extendidas):

public static List<string> GetUserLDAPProperties(string LDAPUrl)
{
    List<string> properties = new List<string>();
    ActiveDirectorySchema adSchema = ActiveDirectorySchema.GetCurrentSchema();
    ActiveDirectorySchemaClass userSchema =
        default(ActiveDirectorySchemaClass);
    ActiveDirectorySchemaPropertyCollection propertiesCollection =
        default(ActiveDirectorySchemaPropertyCollection);
    userSchema = adSchema.FindClass("user");
    propertiesCollection = userSchema.MandatoryProperties;
    foreach (ActiveDirectorySchemaProperty prop in propertiesCollection)
    {
        properties.Add(prop.Name);
    }
    propertiesCollection = userSchema.OptionalProperties;
    foreach (ActiveDirectorySchemaProperty prop in propertiesCollection)
    {
        properties.Add(prop.Name);
    }
    properties.Sort();
    return properties;
}

De este modo obtenemos los nombres de las propiedades, con lo que ya sabemos los nombres de los atributos de un usuario de nuestro LDAP. Así pues, a partir del nombre de la propiedad que deseamos obtener, del identificador de seguridad de un usuario, y del nombre del dominio, ahora si vamos a ser capaces de obtener el valor de ese atributo para un usuario de nuestro LDAP (siempre que tenga ese atributo definido, claro):

public static string GetNTAccountProperty(string sid, string domain, string propertyToLoad)
{
    if (string.IsNullOrEmpty(sid)) throw new ArgumentNullException();
    if (string.IsNullOrEmpty(domain)) throw new ArgumentNullException();
    if (string.IsNullOrEmpty(propertyToLoad)) throw new ArgumentNullException();
    string ldapDomainName = GetLDAPDomainName(domain);
    using (DirectoryEntry entries = new DirectoryEntry(ldapDomainName))
    {
        string filter = string.Format(
            "(&(objectCategory=person)(objectClass=user)(objectSID={0}))", sid);
        DirectorySearcher searcher = new DirectorySearcher(entries, filter);
        searcher.PropertiesToLoad.Add(propertyToLoad);
        searcher.PropertiesToLoad.Add("objectSID");
        SearchResult result = searcher.FindOne();
        if (!result.Properties.Contains(propertyToLoad))
            throw new ActiveDirectoryObjectNotFoundException(
                string.Format("Property '{0}' not found on NTAccount '{1}'",
                propertyToLoad, sid));
        return result.Properties[propertyToLoad][0].ToString();
    }
}

Métodos de apoyo

Muchas de éstos métodos utilizan el nombre de nuestro LDAP en el siguiente formato: LDAP://DC=local,DC=miempresa,DC=com

Así que aquí tenéis una función que lo obtiene a partir del nombre del dominio:

public static string GetLDAPDomainName(string domainName)
{
    StringBuilder sb = new StringBuilder();
    if (string.IsNullOrEmpty(domainName)) throw new ArgumentNullException();
    string[] dcItems = domainName.Split(".".ToCharArray());
    sb.Append("LDAP://");
    foreach (string item in dcItems)
    {
        sb.AppendFormat("DC={0},", item);
    }
    return sb.ToString().Substring(0, sb.ToString().Length - 1);
}

Que a su vez se obtiene de este otro método:

public static string GetDomainName()
{
    return IPGlobalProperties.GetIPGlobalProperties().DomainName;
}

Proyecto de ejemplo

Hay algunas cosillas más, como la obtención de los usuarios del LDAP que (para no hacer el post más ‘tocho’ :-P) no hemos visto en el post. Podéis descargar el proyecto de ejemplo completo desde skydrive en esta ubicación:

http://cid-f3a970280830b5fe.office.live.com/self.aspx/MSDN%20Samples/TestLDAP.zip 

Uffff… al final me ha salido un post más largo de lo que yo quería, pero bueno, espero que os sirva de algo 🙂

Saludos desde Andorra,

Anuncis