MSMVPS.COM
The Ultimate Destination for Blogs by Current and Former Microsoft Most Valuable Professionals.

Accediendo al directorio activo de la organización desde .NET (IV)

El blog de Lluis Franco

Syndication

homer1Buscar

Hoy vamos a buscar. Buscar elementos en el AD dentro de nuestra organización, y como lo más habitual es buscar usuarios o grupos he creado algunas funciones para facilitar esta tarea dentro de la clase LDAPServices (os dejo para vosotros ampliarlas para buscar equipos, por ejemplo).

También veremos cómo extraer los nombres de las propiedades de un objetos del AD, ya que en ocasiones queremos filtrar o devolver el valor de una propiedad de un objeto y no sabemos cómo se llama esta propiedad. Por ejemplo, para devolver el teléfono de un usuario en el AD hay que preguntar por el valor de la propiedad 'telephoneNumber'.

Tal vez más adelante (si tengo tiempo) lo ampliemos un poco. Me gustaría realizar un post acerca de cómo realizar un mapeador de propiedades para asignar los valores de las propiedades de objetos LDAP a objetos de nuestra aplicación. Esto podría ser muy útil por ejemplo, para importar los valores de nuestros usuarios de AD a una tabla de empleados.

Antes de empezar quiero comentaros que para poder realizar todo esto va a ser necesario agregar una referencia a System.DirectoryServices a nuestro proyecto. Pero vamos ya con estos nuevos métodos de LDAPServices:

getLDAPFilterString - Devuelve una cadena de consulta en formato LDAP query, que permite filtrar los objetos que deseamos devolver. Esta función filtra aquellos carácteres no deseados para evitar posible inyección de código LDAP por parte de un usuario (aunque es muy mejorable, estoy seguro que mi JoseMariCariño sería capaz de sacar información de aquí, casi me apuesto algo).

public enum LDAPFilterType
{
    UsersAndGroups,
    OnlyUsers,
    OnlyGroups
}
 
public static string 
    getLDAPFilterString(LDAPFilterType Type, string Filter)
{
    Filter = Filter.Replace("&","");
    Filter = Filter.Replace("|","");
    Filter = Filter.Replace("*", "");
    string FilterByName = "(samAccountName=*{0}*)";
    string f = string.Empty;
    switch (Type)
    {
        case LDAPFilterType.OnlyUsers:
            f = "(&(objectCategory=person)(objectClass=user){0})";
            break;
        case LDAPFilterType.OnlyGroups:
            f = "(&(objectCategory=Group){0})";
            break;
        case LDAPFilterType.UsersAndGroups:
            f = "(|(&(objectCategory=person)(objectClass=user){0})(&(objectCategory=Group){0}))";
            break;
    }
    if (Filter == string.Empty)
    {
        return string.Format(f, string.Empty);
    }
    else
    {
        return string.Format(f, string.Format(FilterByName, Filter));
    }
} 

getItemsInLDAP - Basándose en el método anterior, realiza la consulta al AD y devuelve una lista con los objetos coincidentes. Su funcionamiento se basa en un objeto DirectoryEntry, que apunta al AD que se le ha pasado como aergumento. Y en un objeto DirectorySearcher, que es el que realmente se encarga de buscar las entradas coincidentes con el filtro en el DirectoryEntry.

public static List<string> 
    getItemsInLDAP(string LDAPURL, LDAPFilterType type, string criteria)
{
    List<string> items = new List<string>();
    DirectoryEntry entries = new DirectoryEntry(LDAPURL);
    string filter = getLDAPFilterString(type, criteria);
    DirectorySearcher searcher = new DirectorySearcher(
        entries, filter);
    try
    {
        foreach (SearchResult result in searcher.FindAll())
        {
            items.Add((string)result.Properties["samAccountName"][0]);
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
    return items;
}

Para probar esta funcionalidad basta con tener un TextBox en el que introducir el criterio de búsqueda y un ComboBox en el que especificar que objetos deseamos buscar. Así cómo un CommandButon para lanzar la consulta y un ListBox en el que mostrar los resultados:

LDAPSearchInLDAP

El código es muy sencillo. Basta con asignar el valor devuelto por la función getItemsInLDAP al DataSource de la lista.

private void cmbSearch_Click(object sender, EventArgs e)
{
    try
    {
        string dcName = LDAPServices.getLDAPDomainName(txtDomain.Text);
        List<string> items = LDAPServices.getItemsInLDAP(dcName, 
            (LDAPServices.LDAPFilterType) cmbType.SelectedIndex, txtCriteria.Text);
        lstItems.DataSource = items;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message,
             Application.ProductName,
             MessageBoxButtons.OK,
             MessageBoxIcon.Exclamation);
    }
}

getUserLDAPProperties - Devuelve una lista de cadenas con los nombres de las propiedades de un objeto User dentro del AD. Cabe observar que el esquema del AD es variable, con lo que las propiedades devueltas pueden cambiar. Por ejemplo, productos que se integran fuertemente con AD como Exchange agregan propiedades a los objetos usuario y grupo.

public static List<string> 
    getUserLDAPProperties(string LDAPURL)
{
    List<string> properties =new List<string>();
    DirectoryEntry entries = new DirectoryEntry(LDAPURL);
    DirectorySearcher searcher = new DirectorySearcher(
        entries, "(&(objectCategory=person)(objectClass=user))");
    try
    {
        foreach (SearchResult result in searcher.FindAll())
        {
            foreach (string property in
                result.GetDirectoryEntry().Properties.PropertyNames)
            {
                properties.Add(property);
            }
            break;
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
    return properties;
}

LDAPBrowseUserProperties

De este modo podemos saber las propiedades de un objeto dentro de nuestro AD. Esto es más importante de lo que parece, ya que cuando buscamos elementos dentro del AD, no se devuelven todas las propiedades de forma predeterminada. Para agregar el valor de una propiedad a los resultados de la búsqueda ésta debe añadirse explícitamente mediante la colección PropertiesToLoad:

searcher.PropertiesToLoad.Add("telephoneNumber");

Y luego comprobar si existe valor devuelto, ya que es posible que no exista o no devuelva valor:

if (r.Properties("telephoneNumber").Count > 0)
{
    //
}

Y hasta aquí el cuarto capítulo de esta serie. Espero que os sea útil, recordar que en esta ocasión el código completo lo publiqué en el post anterior.

Nos vemos pronto!
Un saludo desde Andorra,

** crossposting desde el blog de Lluís Franco en geeks.ms **

Posted Jul 08 2008, 01:27 PM by lfranco

Add a Comment

(required)  
(optional)
(required)  
Remember Me?


Copyright © is the original authors. Blog site is an independent site not sponsored by Microsoft. The Yoda blog server and the Brianna SQL server would like to thank www.ownwebnow.com and www.exchangedefender.com. They wouldn't be here and broadcasting without the generosity of Vlad Mazek and his companies.

Powered by Community Server (Commercial Edition), by Telligent Systems