Autenticación Aplicación Java usando OpenDJ (ex OpenDS) LDAP Server

Es difícil encontrar un buen y completo ejemplo (o tutorial) de cómo validar (autenticar) un usuario mediante LDAP desde una aplicación Java, y es más difícil encontrar un tutorial en español.

En este ejemplo supondremos que el servidor LDAP es OpenDJ (antes OpenDS)

http://www.forgerock.com/opendj.html

Pero este tutorial aplica tanto para Oracle OpenDS como para ForgeRock OpenDJ, porque están basado en los mismos fuentes.

OpenDJ es un “Directory Server” Open Source, que implementa el protocolo LDAP.

Un “Directory Server” es una base de datos “optimizada” que puede guardar todo tipo de información, pero su uso se ha extendido principalmente como Base de Datos de perfilación, y de componentes de dominio.

Un “Directory Server” puede guardar todo tipo de información, maneja índices, filtros y mecanismos de búsqueda muy eficientes, las bases de datos relacionales están basadas en esta tecnología, podríamos decir que un “Directory Server” es equivalente al “Lenguaje C”, y una “Base de Datos Relacional” es equivalente a un lenguaje de alto nivel como “Java” (que se basa en C), en otras palabras si queremos manejar data en tiempo real y con alta carga, una opción adecuada puede ser usar Directory Server.

La información en LDAP se guarda en forma de árbol (tree) con subniveles “ilimitados” parecido a una estructura XML, maneja conceptos de atributos y clases de objetos (objectClass). Veremos una estructura básica de usuarios-organización:

Suponemos que la estructura anterior se implementó usando el “Control Panel” de OpenDJ

Existen algunos conceptos y  atributos básicos de LDAP

  • DN: “Distingished Name”, corresponde al path completo de atributos que referencian únicamente a un registro LDAP, en el ejemplo del árbol para el usuario “cn=juan perez” su DN es:

cn=juan perez,ou=depto_informatica,dc=soaagenda,dc=com

Haciendo una equivalencia con bases de datos relacionales, son los campos     llave con que se identifica únicamente un registro.

  • cn: “common name” corresponde al nombre común del elemento para un usuario su nombre y apellido.
  • ou: “organizational unit” nombre de un departamento de la organización, puede identificar una empresa, una sucursal, un departamento, o un área de la Organización. Tambien se usa para identificar un grupo de personas como “clientes”.
  • dc: “domain component” sire para identificar el dominio, se usar un par por ejemplo para www.soaagenda.com se define con “dc=soagenda, dc=com”.

Otros atributos de un usuario:

  • sn: “surname” es el apellido.
  • givenName: es el nombre de pila
  • uid: “user id” una identificación única más orientado a sistema, mientras que “common name” (cn) está más orientado a personas (nombre común), por ejemplo un uid puede ser un código numerico.
  • userPassword: password del usuario esta encriptada en SHA.

Para nuestro ejemplo:

  • cn= juan perez
  • uid=jperez
  • givenName=Juan
  • sn=Perez
  • mail=juan.perez@soaagenda.com
  • userPassword= claveY
  • telephoneNumber=5550000

Bueno, a lo que vinimos, este es el código de ejemplo para validar un usuario y obtener sus datos.

package com.soaagenda;

import java.util.Hashtable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

/**
 *
 * @author soaagenda.com
 */
public class UtilsLDAP {
   
    private String INITCTX = "com.sun.jndi.ldap.LdapCtxFactory";
    private String HOSTLDAP = "ldap://localhost:389";
    private String BASE = "DC=soaagenda,DC=com";

    public boolean validaUsuario(String userDN, String pass) {           
        Hashtable env = new Hashtable();
        if (pass.compareTo("") == 0 || userDN.compareTo("") == 0)
            return false;
        
        env.put(Context.INITIAL_CONTEXT_FACTORY,INITCTX);
        env.put(Context.PROVIDER_URL, HOSTLDAP);
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, new String(userDN));  
        env.put(Context.SECURITY_CREDENTIALS,new String(pass));
        
        DirContext ctx=null;
        try {
            ctx = new InitialDirContext(env);
        } catch (NamingException ex) {
            Logger.getLogger(UtilsLDAP.class.getName()).log(Level.SEVERE, null, ex);
            return false;
        }

        try {
            if (ctx!=null) ctx.close();
        } catch (NamingException ex) {
            Logger.getLogger(UtilsLDAP.class.getName()).log(Level.SEVERE, null, ex);
            return false;
        }        
        return true;   
    }    
    
   public String obtieneUsuario(String adminDN, String adminPass, String uidBuscar) {           
        Hashtable env = new Hashtable();
 
        env.put(Context.INITIAL_CONTEXT_FACTORY, INITCTX);  
        env.put(Context.PROVIDER_URL, HOSTLDAP);   
        env.put(Context.SECURITY_AUTHENTICATION, "simple");  
        env.put(Context.REFERRAL, "follow" );
        env.put(Context.SECURITY_PRINCIPAL, new String(adminDN));  
        env.put(Context.SECURITY_CREDENTIALS,new String(adminPass));  

       DirContext dctx=null;
       try {
            dctx = new InitialDirContext(env);

        
            String base = BASE;
            String filter = "(&(objectClass=organizationalPerson)(uid="+uidBuscar+"))";

            SearchControls controls = new SearchControls();

            String []strReturningAttr = {"member","uid","sn","cn","mail","userPassword"};

            controls.setReturningAttributes(strReturningAttr);
            controls.setSearchScope(SearchControls.SUBTREE_SCOPE);

            NamingEnumeration answer= null;
            try {
                answer = dctx.search(base, filter, controls);
            } catch (NamingException ex) {
                Logger.getLogger(UtilsLDAP.class.getName()).log(Level.SEVERE, null, ex);
                ex.printStackTrace();
                return "error";
            }

            while (answer.hasMoreElements()) {
                SearchResult sr;
                try {
                    sr = (SearchResult)answer.next();
                } catch (NamingException ex) {
                    Logger.getLogger(UtilsLDAP.class.getName()).log(Level.SEVERE, null, ex);
                    ex.printStackTrace();
                return "error";
                }

                Attributes attrs = sr.getAttributes();

                Attribute attr = attrs.get("mail");
                String mailX="";
                if (attr!=null) try {
                    mailX=(String) attr.get();
                } catch (NamingException ignoreX) {
                    Logger.getLogger(UtilsLDAP.class.getName()).log(Level.SEVERE, null, ignoreX);
                    ignoreX.printStackTrace();
                }

                attr = attrs.get("userPassword");
                Object passW=null;
                if (attr!=null) try {
                    passW= attr.get();
                } catch (NamingException ignoreX) {
                    Logger.getLogger(UtilsLDAP.class.getName()).log(Level.SEVERE, null, ignoreX);
                    ignoreX.printStackTrace();
                }
                
                return sr.getName()+"nmail="+mailX+"npassw="+passW.toString();    

            }//while

        }catch (NamingException e) {
            e.printStackTrace();
            return "error";
        }finally{
            try{
                if (dctx!=null) dctx.close();
            }catch (Exception ignore){}
        }        

        return "usuario no existe";   
    }
    
    public static void main(String[] argv) {
        UtilsLDAP utilX = new UtilsLDAP();

        if (utilX.validaUsuario("cn=Directory Manager","primeras")) 
               System.out.println("USUARIO ADMIN VALIDO");
        else
               System.out.println("USUARIO o PASSWORD ERRONEO PARA ADMIN");

        if (utilX.validaUsuario("cn=juan perez,ou=depto_informatica,dc=soaagenda,dc=com","claveY")) 
               System.out.println("USUARIO VALIDO");
        else
               System.out.println("USUARIO o PASSWORD ERRONEO");
        
        String usuarioX=  utilX.obtieneUsuario("cn=Directory Manager","primeras","jperez"); 
        System.out.println(usuarioX);
    }    
    
}

Lo principal en esta aplicación es que define al principio el servidor LDAP:

private String HOSTLDAP = “ldap://localhost:389”;

private String BASE = “DC=soaagenda,DC=com”;

Y la función de validación se basa en el DN y la password (userPassword)

validaUsuario(“cn=juan perez,ou=depto_informatica,dc=soaagenda,dc=com”,”claveY”)

La aplicación retorna el siguiente resultado (System Out)

USUARIO ADMIN VALIDO

USUARIO VALIDO

cn=juan perez,ou=depto_informatica

mail=juan.perez@soaagenda.com

passw=[B@174cc1f

Advertisements

One thought on “Autenticación Aplicación Java usando OpenDJ (ex OpenDS) LDAP Server

  1. administrador

    gfdfgd

    Like

Comments are closed.