Vous êtes sur la page 1sur 41

Acceso a OpenLDAP mediante

Netscape Directory SDK para Java


vía JNDI en una aplicación web con
Apache Tomcat

Irenio Luis Chagua Aduviri


http://www.nspsac.com/ichagua/
ichagua@nspsac.com
Versión 1.0, 04 Mayo 2007

NETSOLUTIONS PERU S.A.C.

Copyright
Copyright (c) 2007, Irenio Luis Chagua Aduviri. Este documento puede ser distribuido solo bajo los términos y
condiciones de la licencia de Documentación de javaHispano v1.0 o posterior (la última versión se encuentra en
http://www.javahispano.org/licencias/).
Para cualquier comentario, duda, consulta sobre este tutorial dirigirse a ichagua@nspsac.com.
Contenido del Artículo

Introducción ............................................................................................ 1
1. LDAP (Lightweight Directory Access Protocol) ............................. 3
Utilidades de LDAP ............................................................................... 3
Características de LDAP ....................................................................... 4
Estructura del Arbol LDAP ................................................................... 4
Entradas.............................................................................................. 4
Atributos............................................................................................. 4
Tipos de Atributos ............................................................................. 5
Clase de Objetos ................................................................................ 6
LDIF .................................................................................................... 6
Modelo de Nombres LDAP ................................................................ 6
2. Directorio LDAP............................................................................... 8
3. Browser LDAP ............................................................................... 14
4. Librería para acceder a LDAP ....................................................... 14
API JNDI............................................................................................... 15
Configuración de Recursos JNDI ........................................................ 16
5. Creando las clases JavaBean......................................................... 18
6. Implementando las clases DAO ..................................................... 21
La interfaz DAO ................................................................................... 21
La clase DAO Factory ......................................................................... 22
Y la implementación de la interfaz DAO ............................................. 22
7. Directorio SDK para Java............................................................... 24
Búsqueda de una Entrada de Directorio............................................. 24
Autenticando Usuarios ........................................................................ 28
Creando y Manipulando entradas de directorio ................................. 29
Servlets, JSP y LDAP .......................................................................... 33
8. Directorios LDAP ........................................................................... 37
9. Clientes LDAP ................................................................................ 37
10. Librerías para LDAP ................................................................... 37
11. Referencias y Herramientas utilizadas....................................... 37
Introducción
Cuando se está desarrollando aplicaciones empresariales, muchas veces se tiene un
directorio de personas, objetos, que son necesarios tenerlos ordenado en un formato
estándar, uno de ellos es LDAP (Lightweight Directory Access Protocol), pero las
formas de acceso a este directorio son diversas, por eso se ha pensado en
implementar el acceso desde un directorio SDK para Java utilizando un servidor web
Apache Tomcat. El directorio LDAP utilizado es OpenLDAP, uno de los directorios
que está al alcance del mundo del software libre.

En este artículo se presenta el uso del directorio LDAP con la finalidad de conocer
con mayor profundidad, creando nuevas especificaciones de esquemas del directorio
y nuevas clases de objetos con sus respectivos atributos. El mismo directorio es
posible mostrar mediante un Browser LDAP en modo gráfico.

La aplicación desarrollada empieza con la creación de las entradas del directorio


LDAP, configuración de la librería Netscape Directory SDK para Java, configuración
de recursos JNDI con las clases JavaBean, implementación de las clases DAO para la
aplicación haciendo uso del mismo directorio SDK para la búsqueda, autenticación de
usuarios, creación y manipulación de las entradas de directorio y finalmente es
mostrado el acceso a LDAP mediante Servlets para enviar datos a una página web
haciendo uso de JSP.

Algunos de los pasos de la configuración de las herramientas se han obviado, en


caso de no concerlos pueden encontrar información básica en los distintos sitios
mencionados en la referencia.

1
1. LDAP (Lightweight Directory Access
Protocol)
LDAP (Lightweight Directory Access Protocol) o Protocolo de Acceso Ligero a
Directorio es un protocolo de comunicación que permite acceder y modificar
información almacenada en un directorio ordenado y distribuido en forma jerárquica,
actualmente está en la versión 3. LDAP permite almacenar información de cuentas de
usuario, contactos, ubicación de diversos recursos de la red, permisos de usuarios,
certificados, entre otros; éste directorio está optimizado para acceso de lectura en
forma eficiente y almacenar datos de poco tamaño, las modificaciones se presentan con
poca frecuencia como el caso de un correo electrónico.

El protocolo LDAP accede a la información contenida en un árbol de información de


directorio, las cuales están formados por un conjunto de atributos, indicando el nombre
y su respectivo valor. Este directorio es único en una organización y es posible acceder
de diversas aplicaciones.

Utilidades de LDAP
ƒ Directorios de información, por ejemplo datos de empleados organizados por
departamentos (siguiendo la estructura organizativa de la empresa) ó cualquier tipo
de páginas amarillas.
ƒ Sistemas de autenticación/autorización centralizada, sistemas donde se guarda gran
cantidad de registros y se requiere un uso constante de los mismos, por ejemplo,
gestión de cuentas de acceso a una red corporativa, sistema de autenticación para
páginas web, sistemas de control de entradas a edificios, oficinas, entre otros.
ƒ Sistemas de correo electrónico.
ƒ Sistemas de alojamiento de páginas web y FTP.
ƒ Sistemas de autenticación basados en RADIUS, para el control de accesos de los
usuarios a una red de conexión o ISP.
ƒ Servidores de certificados públicos y llaves de seguridad.
ƒ Autenticación única ó “single sign-on” para la personalización de aplicaciones.
ƒ Perfiles de usuarios centralizados, para permitir itinerancia ó “Roaming”.
ƒ Libretas de direcciones compartidas.

3
LDAP (Lightweight Directory Access Protocol)

Características de LDAP
ƒ Operaciones de lectura muy rápidas. Debido a la naturaleza de los datos
almacenados en los directorios las lecturas son más comunes que las escrituras.
ƒ Datos relativamente estáticos. Los datos almacenados en los directorios no suelen
actualizarse con mucha frecuencia.
ƒ Entorno distribuido, fácil replicación.
ƒ Estructura jerárquica. Los directorios almacenan la información de forma jerárquica
de forma nativa.
ƒ Orientadas a objetos. El directorio representa a elementos y a objetos. Los objetos
son creados como entradas, que representan a un conjunto de atributos.
ƒ Esquema estándar. Los directorios utilizan un sistema estándar que pueden usar
fácilmente diversas aplicaciones.
ƒ Atributos multi-valor. Los atributos pueden almacenar un valor único o varios.
ƒ Replicación multi-master. Muchos de los servidores LDAP permiten que se realicen
escrituras o actualizaciones en múltiples servidores.

Estructura del Árbol LDAP

Entradas
El modelo de información de LDAP está basado en entradas. Una entrada es un conjunto
de atributos que tienen un único Nombre Distintivo DN (Distinguished Name) y de forma
global. El DN se utiliza para referirse a una entrada sin ambigüedades. Cada atributo de
una entrada tiene un tipo y está asociado uno o más valores. Los tipos son normalmente
palabras nemotécnicas, como "cn" para common name, o "mail" para una dirección de
correo electrónico.

La sintaxis de los atributos depende del tipo de atributo. Por ejemplo, un atributo cn
puede tener el valor “Mariano Apaza Quispe”. Un atributo mail puede contener un valor
“mapaza@nspsac.com”. El atributo jpegPhoto contiene una fotografía en formato JPEG.

Atributos
Los datos del directorio son un conjunto de atributos y sus respectivos valores. Por
ejemplo el atributo commonName, o cn, se usa para representar el nombre de una persona.

Los datos de una persona que se registra en el directorio se definen mediante el


conjunto de atributos que están definidas en las especificaciones de esquemas, en este
caso la clase de objetos person.

En una entrada de directorio se presentan atributos obligatorios que deben estar


presentes en la clase de objetos y atributos opcionales que no es necesario que esté
presente en una entrada de clase de objetos.

Irenio Luis Chagua Aduviri


Acceso a OpenLDAP mediante Netscape Directory SDK

Tipos de Atributos
Una definición de tipo de atributo especifica la sintaxis de un atributo y cómo se
ordenan y comparan los atributos de ese tipo.

Los tipos de atributos en el directorio forman un árbol de clases. Por ejemplo, el tipo de
atributo "commonName" es una subclase del tipo de atributo "name". Hay atributos
obligatorios y opcionales que se muestran en la Tabla 1.1.

TABLA 1.1: RFC 2252: AttributeTypeDescription

Identificador de Descripción del Valor de Atributo


Atributo
NUMERICOID Identificador de Objeto Único (OID)
(obligatorio)
NAME Nombre del Atributo
DESC Descripción del Atributo
OBSOLETE "true" si es obsoleto; "false" o ausente si no lo es
SUP Nombre del tipo de atributo superior del que se deriva el tipo de
atributo
EQUALITY Nombre ó OID de la regla de correspondencia si la igualdad de
correspondencia está permitida; ausente si no lo está
ORDERING Nombre ó OID de la regla de correspondencia si está permitida la
ordenación; ausente si no lo está.
SUBSTRING Nombre ó OID de la regla de correspondencia si está permitida la
correspondencia de sub-string ausente si no lo está.
SYNTAX OID numérico de la sintaxis de los valores de este tipo
SINGLE-VALUE "true" si el atributo no es multi-valor; "false" o ausente si lo es
COLLECTIVE "true" si el atributo es colectivo; "false" o ausente si no lo es
NO-USER- "true" si el atributo no es modificable por el usuario; "false" o
MODIFICATION ausente si lo es
USAGE Descripción del uso del atributo

Irenio Luis Chagua Aduviri


LDAP (Lightweight Directory Access Protocol)

Clase de Objetos
En LDAP, una clase de objetos define el conjunto de atributos a ser usados para definir
una entrada. El estándar LDAP proporciona estos tipos básicos para las clases de
objetos:

1. Grupos en el directorio, entre ellos listas no ordenadas de objetos individuales o de


grupos de objetos.
2. Emplazamientos, como por ejemplo el nombre del país y su descripción.
3. Organizaciones que están en el directorio.
4. Personas que están en el directorio.

Una entrada determinada puede pertenecer a más de una clase de objetos. Por ejemplo,
la entrada para personas se define mediante la clase de objetos person, pero también
puede definirse mediante atributos en las clases de objetos inetOrgPerson, groupOfNames
y organization. La estructura de clases de objetos del servidor determina la lista total
de atributos requeridos y permitidos para una entrada concreta.

LDIF
El formato de intercambio de LDAP es un archivo de texto que almacena información de
entradas de objetos en forma jerárquica. Esto nos permite importar y exportar
información de directorio entre servidores de directorios basados en LDAP.

Modelo de Nombres LDAP


Cada entrada de directorio LDAP está organizada en un árbol de información de
directorio y para identificar a alguna entrada de directorio se accede mediante su
nombre distintivo (DN). Cada nombre distintivo puede estar formado por una secuencia
de nombres distintivos relativos RDN (Relative Distinguished Name), como uid=mapaza.
Cada nombre distintivo relativo en un DN corresponde a una rama del árbol de
información de directorio. Asimismo está formado por otros atributos que lo relacionan
con las jerarquías superiores como componentes de dominio DC (Domain Component),
así, dc=nspsac, dc=com. Después del nombre distintivo hay una serie de atributos que
definen las entradas.

Para comprender un poco sobre la estructura del directorio veamos el árbol de la


gráfica donde se describe a la empresa nspsac.com como principal y teniendo como
unidades organizacionales a Admin, People y Developer, de las cuales en cada unidad
organizacional es posible agregar directorios, en este caso una cuenta de usuario con
su información de datos de identificación, registro del empleado, datos de su jefe,
correo electrónico, teléfono fijo, teléfono celular, la dirección en la que vive, la clave de
identificación de la cuenta y la foto correspondiente del empleado.

Irenio Luis Chagua Aduviri


Acceso a OpenLDAP mediante Netscape Directory SDK

FIGURA 1.1 Árbol de Directorio LDAP

La información descrita anteriormente para que se encuentre registrado en el directorio


LDAP creamos un formato LDIF estándar, que es un archivo de texto que contiene
información de configuración LDAP y contenido de directorios, en este caso será
mapaza.ldif que se muestra a continuación:

dn: uid=mapaza,ou=People,dc=nspsac,dc=com
givenName: Mariano
sn: Apaza Quispe
mail: mapaza@nspsac.com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: contribuyente
uid: mapaza
cn: Mariano Apaza Quispe
dni: 01234567
ruc: 10012345675
employeeNumber: A214
manager: uid=jperez,ou=Admin,dc=nspsac,dc=com
telephoneNumber: 051505050
mobile: 0519797979
direccion: Jr. Los Incas Nro. 6548
st: Puno
l: Ilave
userPassword: abc
jpegPhoto:<file:///var/photo.jpg

Además al crear un directorio de entrada los atributos pertenecen a un conjunto de


clase de objetos que están definidos en una especificación de esquemas según el
estándar, en este caso pertenece a la clase de objetos person, organizationalPerson,
inetOrgPerson y contribuyente, de éste último veremos más adelante.

Irenio Luis Chagua Aduviri


Directorio LDAP

2. Directorio LDAP
Para almacenar estas descripciones de directorios es necesario el uso de un directorio
LDAP, hay varias implementaciones de estos directorios, de distintas empresas, para
distintos usos y para aplicaciones diferentes. Para el caso del presente artículo haremos
uso de OpenLDAP, un directorio LDAP a nuestro alcance en el mundo del software
libre.

Para descargar el instalador de OpenLDAP acceda a http://www.openldap.org/, ó si


desea OpenLDAP para Windows. Una vez descargado e instalado OpenLDAP es
necesario modificar el archivo de configuración slapd.conf, este archivo contiene
configuración de usuario, contraseña, sufijo, dn principal, especificaciones de esquemas,
entre otros. En este caso cambiaremos algunos valores de los atributos.

database bdb
suffix "dc=nspsac,dc=com"
rootdn "cn=root,dc=nspsac,dc=com"
rootpw abc
directory ./data

Se ha realizado el cambio del sufijo a "dc=nspsac,dc=com", y dn principal a


"cn=root,dc=nspsac,dc=com", luego la contraseña de la cuenta principal se ha cambiado
a abc, pero también es posible colocar una contraseña encriptada con {CRYPT}, {MD5},
{SMD5}, {SSHA}, y {SHA}, si usamos alguna de estas encriptaciones la contraseña de la
cuenta principal quedaría como el siguiente:

rootpw {SSHA}/Wg8V59/aoeKLn4PkkKWEsdvjyz6R+/E

Muchos de los atributos de la entrada de directorio descrito anteriormente no está


disponible en la configuración inicial, estos atributos están basados en unas
especificaciones de esquemas que delimitan su creación. Para esto quitaremos el
comentario ó agregaremos si no está descrito de las siguientes especificaciones de
esquemas:

include ./schema/core.schema
include ./schema/cosine.schema
include ./schema/inetorgperson.schema

Los atributos dni, ruc, y direccion no está definido en las especificaciones de


esquemas que acabamos de activarlas, estos atributos lo he agregado para fines de
conocer cómo se crea una nueva especificación de esquemas y por otro lado en mi país
(Perú) todo usuario de un sistema al menos tiene su documento nacional de identidad
(DNI), su registro único del contribuyente (RUC) y se agregó el atributo dirección por
comodidad, aunque el atributo dni y direccion no debiera estar definido en una clase
de objetos como la de contribuyente, más bien debería estar definido en la clase de
objetos person, para efectos de no complicar la configuración se ha añadido en la clase
de objeto contribuyente.

Irenio Luis Chagua Aduviri


Acceso a OpenLDAP mediante Netscape Directory SDK

En una especificación de esquema se definen clases de objetos válidos que indican qué
atributos debe contener en forma obligatoria y qué atributos son opcionales, así como el
tipo de dato (cadenas de texto, números) de un atributo. La clase de objetos y los
atributos deben estar definidos en forma global y único mediante cadenas de números
(OID), para esto es necesario obtener un OID que nos permitirá crear tantas
extensiones como se quiera del esquema.

Los tipos de clase de objetos que existen son tres: Structural. Una clase de objeto
estructural define las características básicas de un objeto. Auxiliary. Una clase de
objeto Auxiliar es adicional, complementa los atributos de una clase de objeto
estructural. Y por último Abstract. Esta clase de objeto abstracto es usado solamente
para definir modelo de datos LDAP básicos.

La sintaxis básica para crear una clase de objetos es la siguiente:

objectclass ( 1.1.2.2.2 NAME 'myPerson'


DESC 'Mi persona'
SUP inetOrgPerson
MUST ( myUniqueName $ givenName )
MAY myPhoto )

Donde:
1.1.2.2.2 es el identificador único global (OID).
NAME 'myPerson' es el nombre de la clase de objeto (alias para OID).
DESC 'Mi persona' la descripción para la clase de objeto.
SUP inetOrgPerson es el objeto del que hereda.
MUST(...) aquí se describen los atributos requeridos.
MAY(...) aquí se describen los atributos opcionales.

La sintaxis básica para crear un atributo es la siguiente:

attributetype ( 1.3.6.1.1.1.1.0 NAME 'uidNumber'


DESC 'Identifica en forma única a un usuario'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )

Donde:
1.3.6.1.1.1.1.0 es el identificador único global (OID).
NAME 'uidNumber' es el nombre del atributo (alias para OID).
DESC '...' la descripción para el atributo.
EQUALITY integerMatch calificador de plantilla de tipos.
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 es la sintaxis OID.
SINGLE-VALUE es un calificador, puede ser SINGLE-VALUE, COLLECTIVE y {LENGTH}.

Irenio Luis Chagua Aduviri


Directorio LDAP

La Sintaxis de los atributos se presenta en la Tabla 2.1.

TABLA 2.1: Sintaxis de los atributos

Tipo de Dato OID Descripción


Binary 1.3.6.1.4.1.1466.115.121.1.5 BER/DER data
Boolean 1.3.6.1.4.1.1466.115.121.1.7 boolean value
Distinguished Name 1.3.6.1.4.1.1466.115.121.1.12 DN
Directory String 1.3.6.1.4.1.1466.115.121.1.15 UTF-8 string
IA5String 1.3.6.1.4.1.1466.115.121.1.26 ASCII string
Integer 1.3.6.1.4.1.1466.115.121.1.27 Integer
Name and Optional UID 1.3.6.1.4.1.1466.115.121.1.34 DN plus UID
Numeric String 1.3.6.1.4.1.1466.115.121.1.36 Numeric String
OID 1.3.6.1.4.1.1466.115.121.1.38 Object Identifier
Octet String 1.3.6.1.4.1.1466.115.121.1.40 Arbitrary Octets
Printable String 1.3.6.1.4.1.1466.115.121.1.44 Printable String

Las Reglas de las plantillas de atributos se presenta en la Tabla 2.2.

TABLA 2.2: Reglas de plantillas de atributos

Nombre Contexto Descripción


booleanMatch equality Boolean
objectIdentiferMatch equality OID
distinguishedNameMatch equality DN
uniqueMemberMatch equality DN with optional UID
numericStringMatch equality numerical
numericStringOrdering ordering numerical
numericStringSubstringsMatch substrings numerical
caseIgnoreMatch equality case insensitive, space insensitive
caseIgnoreOrderingMatch ordering case insensitive, space insensitive
caseIgnoreSubstringsMatch substrings case insensitive, space insensitive
caseExactMatch equality case sensitive, space insensitive
caseExactOrderingMatch ordering case sensitive, space insensitive
caseExactSubstringsMatch substrings case sensitive, space insensitive
caseIgnoreIA5Match equality case insensitive, space insensitive
caseIgnoreIA5OrderingMatch ordering case insensitive, space insensitive
caseIgnoreIA5SubstringsMatch substrings case insensitive, space insensitive
caseExactIA5Match equality case sensitive, space insensitive
caseExactIA5OrderingMatch ordering case sensitive, space insensitive
caseExactIA5SubstringsMatch substrings case sensitive, space insensitive

Irenio Luis Chagua Aduviri


Acceso a OpenLDAP mediante Netscape Directory SDK

Regresando nuevamente a la clase de objeto contribuyente y con la base de los


conceptos para crear las clases de objetos y atributos en una especificación de
esquema, se define el esquema en el archivo de texto con el nombre
contribuyente.schema en el directorio schema de la ruta donde está instalado
OpenLDAP, con el siguiente contenido:

#
# OID prefix: 1.3.6.1.4.1.10018
#
# Attributes: 1.3.6.1.4.1.10018.1.1
#

attributetype ( 1.3.6.1.4.1.10018.1.1.1 NAME 'ruc'


DESC 'Registro Único del Contribuyente'
EQUALITY numericStringMatch
SUBSTR numericStringSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{11} )

attributetype ( 1.3.6.1.4.1.10018.1.1.2 NAME 'razonSocial'


DESC 'Razón Social del Contribuyente'
SUP name )

attributetype ( 1.3.6.1.4.1.10018.1.1.3 NAME 'dni'


DESC 'Documento Nacional de Identidad de la Persona'
EQUALITY numericStringMatch
SUBSTR numericStringSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{8} )

attributetype ( 1.3.6.1.4.1.10018.1.1.4 NAME 'dniRepLegal'


DESC 'Documento Nacional de Identidad del Representante Legal
del contribuyente'
EQUALITY numericStringMatch
SUBSTR numericStringSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{8} )

attributetype ( 1.3.6.1.4.1.10018.1.1.5 NAME 'estadoDomicilio'


DESC 'Estado del Domicilio del contribuyente'
SUP name )

attributetype ( 1.3.6.1.4.1.10018.1.1.6 NAME 'direccion'


DESC 'Domicilio de la Persona'
SUP name )

#
# Objects: 1.3.6.1.4.1.10018.1.2
#

objectclass ( 1.3.6.1.4.1.10018.1.2.1 NAME 'contribuyente'


DESC 'contribuyente'
SUP top AUXILIARY
MUST ( ruc $ dni )
MAY ( dniRepLegal $ estadoDomicilio $ razonSocial $
direccion) )

La especificación de esquema contribuyente debe ser agregado en el archivo de


configuración slapd.conf la siguiente línea.

include ./schema/contribuyente.schema

Irenio Luis Chagua Aduviri


Directorio LDAP

Una vez creado el archivo y guardado reiniciamos nuestro servicio de directorio


OpenLDAP.

Antes de continuar con agregar el directorio definido anteriormente en el fichero


mapaza.ldif es necesario crear las unidades organizacionales, tal como se ha visto en
el árbol LDAP del gráfico, sino creamos estas unidades organizacionales no es posible
agregar esta entrada de directorio. Para esto creamos un archivo de texto con el
nombre ounspsac.ldif con el siguiente contenido.

dn: ou=Admin,dc=nspsac,dc=com
objectClass: top
objectClass: organizationalUnit
ou: Admin

dn: ou=People,dc=nspsac,dc=com
objectClass: top
objectClass: organizationalUnit
ou: People

dn: ou=Developer,dc=nspsac,dc=com
objectClass: top
objectClass: organizationalUnit
ou: Developer

Para agregar un directorio de entrada LDAP en formato LDIF ejecutaremos el siguiente


comando.

slapadd -v -f slapd.conf -l ounspsac.ldif

De otra forma también es posible insertar los datos de entrada del directorio con el
siguiente comando.

ldapadd -x -D "cn=root,dc=nspsac,dc=com" -w abc -f ounspsac.ldif

De modo similar ahora añadimos al directorio LDAP lo que habíamos definido


inicialmente.

slapadd -v -f slapd.conf -l mapaza.ldif

Y así añadimos otras entradas de directorio LDAP, pero ahora la contraseña del usuario
será encriptado con {SSHA} y es de la siguiente manera.

Irenio Luis Chagua Aduviri


Acceso a OpenLDAP mediante Netscape Directory SDK

dn: uid=jmamani,ou=People,dc=nspsac,dc=com
givenName: Juan Antonio
sn: Mamani Choque
mail: jmamani@nspsac.com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: contribuyente
uid: jmamani
cn: Juan Antonio Mamani Choque
dni: 01847569
ruc: 10018475691
employeeNumber: 2097
mobile: 0519535353
direccion: Av. Titicaca Nro. 458
st: Puno
l: Juli
userPassword: {SSHA}IabIHNeVpLkbzDxCANEMj47OJ9QRh9Gj

Para generar una cadena de texto encriptada se hace uso del comando slappasswd que
trae OpenLDAP de la siguiente manera:

slappasswd -h {SSHA} -s abc

Y continuando con agregar una entrada de directorio LDAP.

slapadd -v -f slapd.conf -l jmamani.ldif

Como se ha visto se ha tenido que agregar en tres veces las entradas de directorio
LDAP definidos, pero no es necesario realizar para cada entrada de directorio, es
posible juntar las tres entradas de directorio en un solo formato LDIF denominado
nspsac.ldif.

Luego de haber insertado datos de entrada de directorio podemos hacer uso del
comando slapcat para mostrar todas las entradas de directorio que se encuentra en
nuestro directorio LDAP en formato LDIF, esto mismo nos puede servir para guardar
estas entradas para lo que sea necesario.

Si se desea realizar una búsqueda mediante un DN es mediante el comando ldapsearch.

ldapsearch -x -b "uid=jmamani,ou=People,dc=nspsac,dc=com"

Asimismo es posible eliminar entradas de directorio LDAP mediante el comando


ldapdelete.

ldapdelete -x -D "cn=root,dc=nspsac,dc=com" -w abc


"uid=jmamani,ou=People,dc=nspsac,dc=com"

Irenio Luis Chagua Aduviri


Browser LDAP

3. Browser LDAP
Hasta aquí hemos visto las operaciones de entradas de directorio OpenLDAP desde
líneas de comando, se puede utilizar en modo gráfico mediante un navegador de LDAP,
para esto utilizaremos LDAPBrowser que está basado en Java y ejecutamos la shell
lbe.bat y configuramos como la que se muestra en la figura. Con esto es posible
administrar un directorio LDAP en modo gráfico.

FIGURA 3.1 Configuración LDAP Browser

4. Librería para acceder a LDAP


Lo anterior ha sido una descripción breve sobre el manejo de un directorio LDAP, pero
cuando se quiere incluir el uso de directorios LDAP en aplicaciones empresariales es
necesario utilizar una librería para acceder a la información de los directorios, como un
lenguaje de programación. Para el presente artículo haremos uso de una librería
desarrollada por Netscape, un directorio SDK para Java que también está a nuestro
alcance en el mundo de software libre. Una vez descargado el código fuente y
compilado según las instrucciones de cómo generar la librería de Netscape, que también
pueden bajárselo una de las librerías que he compilado ldapjdk.jar será posible integrar
en las aplicaciones empresariales el acceso a un directorio LDAP.

Para realizar búsquedas y localizar información en diversos sistemas como directorios


LDAP es necesario una interfaz de múltiples servicios de directorio y de nombres como
JNDI (Java Naming Directory Interface). JNDI nos permitirá interactuar desde Java con
OpenLDAP, esto mediante un proveedor de servicios de interfaz SPI (Service Provider
Interface), que en este caso es el mismo Netscape que ha desarrollado junto a la
librería para el acceso a LDAP, con el nombre Service Provider LDAP que también
pueden bajárselo ldapsp.jar.

Los archivos generados, una vez compilado el código fuente, específicamente del
directorio packages, es necesario que los archivos JAR sean agregados a la variable de

Irenio Luis Chagua Aduviri


Acceso a OpenLDAP mediante Netscape Directory SDK

entorno CLASSPATH del sistema operativo, asumiendo que en windows se ha creado en


el directorio c:\netscape\ldapjava y en FreeBSD ó UNIX en el direcotorio
/usr/netscape/ldapjava, que lo llamaremos a esta ruta de directorio como
<LDAPSDKHOME>. Mediante los siguientes comandos agregamos a la variable de entorno.

En Linux
CLASSPATH=<LDAPSDKHOME>/packages/ldapjdk.jar:<LDAPSDKHOME>/
packages/ldapsp.jar:$CLASSPATH
export CLASSPATH

En FreeBSD, Unix
setenv CLASSPATH <LDAPSDKHOME>/packages/ldapjdk.jar:<LDAPSDKHOME>/
packages/ldapsp.jar:$CLASSPATH

En Windows
set CLASSPATH=<LDAPSDKHOME>/packages/ldapjdk.jar;<LDAPSDKHOME>/
packages/ldapsp.jar;%CLASSPATH%

API JNDI
Mediante el API de JNDI es posible escribir cualquier tipo de programa para acceder a
información en directorios LDAP, gestores de Base de datos relacionales, servicios
CORBA (COS, Corba Object Service), NDS de Novell, entre otras aplicaciones. Para que
un programa de Java busque información de cualquier tipo en un directorio LDAP debe
indicarse dentro del programa la ubicación del directorio LDAP mediante un Naming
Manager para la ubicación física del sistema. Esto es importante ya que en cualquier
momento es posible cambiar el servidor físico del directorio LDAP y no será necesario
la modificación de programa fuente para luego compilarlo, sino basta con cambiar los
parámetros de configuración.

FIGURA 4.1 API JNDI

Irenio Luis Chagua Aduviri


Librería para acceder a LDAP

Configuración de Recursos JNDI


Para realizar una consulta a una entrada de directorio LDAP mediante la librería
Netscape Directory SDK para Java, será necesario la configuración de JNDI en un
servidor web, para este artículo lo voy a desarrollar en una aplicación web con Apache
Tomcat. El cual trae una implementación JNDI InitialContext para cada instancia de
aplicación web que se encuentre ejecutando bajo este servidor. Para esto será
necesario que descarguen el instalador de Apache Tomcat y configuralo. El servidor
Tomcat es una aplicación web basada en Java creada para ejecutar servlets y páginas
JSP que nos ayudará para este propósito.

Para este caso se creará una aplicación web con una estructura de directorios básico, lo
nombraremos ldap que se encontrará en el directorio $CATALINA_HOME/webapps. Luego
es necesario incluir un descriptor de la aplicación que es el archivo web.xml que
contendrá la configuración de la aplicación web y estará dentro del directorio WEB-INF/
del directorio raíz de la aplicación creada, es decir $CATALINA_HOME/webapps/ldap/WEB-
INF/web.xml.

Las entradas InitialContext en una aplicación web son configurados en un elemento


<Context> que puede estar definido en $CATALINA_HOME/conf/server.xml ó de
preferencia el archivo XML del contexto de la aplicación dentro de META-
INF/context.xml

Los recursos definidos en estos elementos pueden estar referidos por los siguientes
elementos al utilizar la descripción de una aplicación web que se encuentra en /WEB-
INF/web.xml:

ƒ <env-entry> - Es la entrada del entorno de la aplicación, un parámetro de valor


simple, puede ser usado para configurar de cómo la aplicación funcionará.
ƒ <resource-ref> - Es la referencia del recurso de la aplicación, que es un objeto
Factory para recursos como JDBC DataSource, JavaMail Session ó un objeto Factory
personalizado.
ƒ <resource-env-ref> - Es el Recurso de referencia del entorno de aplicación, es una
nueva variación del elemento <resource-ref> añadido en Servlet 2.4 que es más
simple de configurar para recursos que no necesitan información de autenticación.

Irenio Luis Chagua Aduviri


Acceso a OpenLDAP mediante Netscape Directory SDK

Para el caso de nuestra aplicación definiremos el elemento <resource-env-ref> en el


descriptor de la aplicación web.xml con el siguiente contenido.

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
<resource-env-ref>
<description>
Objeto Factory para una instancia de BeanLDAPHost.
</description>
<resource-env-ref-name>
beanldaphost
</resource-env-ref-name>
<resource-env-ref-type>
com.nspsac.bean.BeanLDAPHost
</resource-env-ref-type>
</resource-env-ref>
</web-app>

Como habrán notado en este descriptor de la aplicación hacemos referencia a un


recurso de la aplicación con el nombre beanldaphost que es de tipo de clase JavaBean
com.nspsac.bean.BeanLDAPHost, que luego se implementará.

Cada recurso JNDI disponible es configurado en base a una inclusión de los siguientes
elementos dentro de un elemento <Context> ó un elemento <DefaultContext>:

ƒ <Environment> - Configura nombres y valores de entradas de entorno de aplicación


que estará en funcionamiento a través de JNDI InitialContext.
ƒ <Resource> - Configura el nombre y el tipo de dato de un recurso disponible para la
aplicación.
ƒ <ResourceLink> - Agrega un enlace a un recurso definido en el contexto JNDI
global.

Para configurar el recurso JNDI en nuestra aplicación agregamos el <Context> en el


archivo de configuración $CATALINA_HOME/conf/server.xml que es el recurso que
hacemos referencia con el nombre beanldaphost.

<Context path="ldap" docBase="ldap" reloadable="true" override="true">


<Resource name="beanldaphost" auth="Container"
type="com.nspsac.bean.BeanLDAPHost"
factory="com.nspsac.bean.BeanLDAPHostFactory"
iphost="localhost"
puerto="389"
dnbase="dc=nspsac,dc=com"
dnmgr="cn=root"
dnpwd="abc"
dnraiz="ou=People"
ctxfactory="com.netscape.jndi.ldap.LdapContextFactory"/>
</Context>

Irenio Luis Chagua Aduviri


Creando las clases JavaBean

En este recurso JNDI estará almacenado la información necesaria para acceder a un


directorio LDAP desde una aplicación web; como habrán notado, este recurso utiliza una
clase JavaBean y el Resource Factory que es una clase también JavaBean asociado
mediante el atributo factory con el valor com.nspsac.bean.BeanLDAPHostFactory, y los
demás atributos (iphost, puerto, dnbase, dnmgr, dnpwd y dnraiz) de este elemento
<Resource> son información que utilizaremos dentro de las clases JavaBean para
realizar la conexión hacia el directorio LDAP definido anteriormente. Adicionalmente,
podemos apreciar el atributo ctxfactory asociado a un proveedor de servicios de
interfaz (SPI) tal como habíamos indicado anteriormente.

En esta configuración el atributo factory hace referencia a un Resource Factory, pero


según la configuración de tomcat podemos incluir de la siguiente forma
"org.apache.naming.factory.BeanFactory", y por razones de personalizar nuestra
aplicación, se ha creado una clase JavaBean propio.

5. Creando las clases JavaBean


Según la configuración JNDI que se ha definido en el descriptor de la aplicación y en el
Resource Factory, ahora implementamos nuestra clase JavaBean con el nombre
BeanLDAPHost, esto será llamado cada vez que la aplicación se ejecute asociado a
Resource Factory.

package com.nspsac.bean;

import java.io.Serializable;
import java.util.Hashtable;

public class BeanLDAPHost implements Serializable


{
private Hashtable htLdap;

public BeanLDAPHost(String iphost, int puerto,


String dnmgr, String dnpwd,
String dnbase, String dnraiz,
String ctxfactory)
{
this(iphost, Integer.toString(puerto),
dnmgr, dnpwd, dnbase, dnraiz, ctxfactory);
}

public BeanLDAPHost(String iphost, String puerto,


String dnmgr, String dnpwd,
String dnbase, String dnraiz,
String ctxfactory)
{
htLdap = new Hashtable();
htLdap.put("ldap_iphost", iphost);
htLdap.put("ldap_puerto", puerto);
htLdap.put("ldap_dnmgr", dnmgr);
htLdap.put("ldap_dnpwd", dnpwd);
htLdap.put("ldap_dnbase", dnbase);
htLdap.put("ldap_dnraiz", dnraiz);
htLdap.put("ldap_ctxfactory", ctxfactory);
}

Irenio Luis Chagua Aduviri


Acceso a OpenLDAP mediante Netscape Directory SDK

public String getAttribute(String name) throws Exception


{
if(name == null || name.equals(""))
throw new Exception();
else
return (String)htLdap.get(name);
}
}

El Resource Factory predeterminado de Apache a veces puede resultarnos limitado para


ciertas operaciones, por tal razón creamos nuestro Resource Factory propio para luego
integrarlo en Tomcat, la clase JavaBean Resource Factory personalizado le hemos dado
el nombre de BeanLDAPHostFactory.

Para escribir la clase Resource Factory se debe implementar la interfaz del proveedor
de servicio JNDI javax.naming.spi.ObjectFactory. Cada vez que la aplicación web
llama al método lookup() en una entrada del contexto que está asociado a este
Factory, el método getObjectInstance() es invocado con los siguientes argumentos:

ƒ Object obj – El objeto que contiene la localización ó referencia de la información


que puede ser usado en la creación del objeto.
ƒ Name name – Es el nombre al que este Factory está relacionado a nameCtx, ó null si
el nombre no está especificado.
ƒ Context nameCtx – El contexto relacionado al que el nombre del parámetro es
especificado, ó null si el nombre está relacionado al contexto inicial por defecto.
ƒ Hashtable environment – Es el entorno que es utilizado en la creación de este
objeto.

package com.nspsac.bean;

import java.util.Enumeration;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;

public class BeanLDAPHostFactory implements ObjectFactory {

public Object getObjectInstance(Object obj, Name name,


Context nameCtx, Hashtable environment)
throws NamingException
{

BeanLDAPHost bean = null;

Reference ref = (Reference) obj;


Enumeration addrs = ref.getAll();

String iphost = null;


int puerto = -1;
String dnbase = null;
String dnmgr = null;
String dnpwd = null;
String dnraiz = null;
String ctxfactory = null;

Irenio Luis Chagua Aduviri


Creando las clases JavaBean

while (addrs.hasMoreElements()) {
RefAddr addr = (RefAddr) addrs.nextElement();
String nombre = addr.getType();
String value = (String) addr.getContent();
if (nombre.equals("iphost")) {
iphost = value;
} else if (nombre.equals("puerto")) {
try {
puerto = Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new NamingException("Invalid 'port' value " + value);
}
} else if(nombre.equals("dnbase")){
dnbase = value;
} else if(nombre.equals("dnmgr")){
dnmgr = value;
} else if(nombre.equals("dnpwd")){
dnpwd = value;
} else if(nombre.equals("dnraiz")){
dnraiz = value;
} else if(nombre.equals("ctxfactory")){
ctxfactory = value;
}
}

bean = new BeanLDAPHost(iphost,puerto,dnmgr,dnpwd,


dnbase,dnraiz,ctxfactory);

return (bean);

}
}

Para compilar las clases JavaBean que hemos creado es necesario que la librería que
estamos utilizando del proveedor de servicios de interfaz de Netscape Directory SDK
para Java ldapsp.jar esté incluido dentro del directorio de librerías de Tomcat que es
$CATALINA_HOME/common/lib. Adicionalmente la librería SDK ldapjdk.jar también deberá
estar incluido en este directorio de librerías de Tomcat para que funcione nuestros
ejemplos de este artículo.

Irenio Luis Chagua Aduviri


Acceso a OpenLDAP mediante Netscape Directory SDK

6. Implementando las clases DAO


Para implementar los accesos a un directorio LDAP mediante una aplicación web
utilizaremos el modelo DAO, que es utilizado para separar las operaciones de los datos
de bajo nivel desde un nivel más alto de la lógica de negocio. Una aplicación DAO tiene
los siguientes componentes:
ƒ Una clase DAO factory
ƒ Una interfaz DAO
ƒ Una clase concreta que implemente la interfaz DAO
ƒ Transferencia de objetos de datos

La interfaz DAO
package com.nspsac.seguridad.ldap;

import java.util.HashMap;
import javax.naming.NamingException;

import com.nspsac.utils.exception.IncompleteConversationalState;

public interface AccesoLDAP{

static final String DIR_IMGS = "../webapps/ldap/imgs/";

static final String[] ATTRS = {"dn","mail","uid","cn",


"dni","ruc","employeeNumber","jpegPhoto","manager","givenName",
"telephoneNumber","mobile","direccion","sn","st","l"};

static final String OBECT_CLASS[] = {


"top", "person", "organizationalPerson",
"inetOrgPerson", "contribuyente"};

public void getInstance() throws NamingException;

public void cambiarClave(String uid, String claveanterior, String clave)


throws NamingException;

public void addEntry(String uid, HashMap attrs);

public void renameEntry(String uid, String newUid);

public void renameEntry(String uid, String newUid, String newGroup);

public void deleteEntry(String uid);

public void addAttribute(String uid, String nameAttr, String valAttr)


throws NamingException;

public void modifyAttribute(String uid, String nameAttr, String valAttr)


throws NamingException;

public void deleteAttribute(String uid, String nameAttr)


throws NamingException;

public HashMap findByEmployeeNumber(String codPers)


throws IncompleteConversationalState;

Irenio Luis Chagua Aduviri


Implementando las clases DAO

public HashMap findByUID(String uid)


throws IncompleteConversationalState;

public HashMap autenticar(String uid, String pwd)


throws NamingException, IncompleteConversationalState;
}

La clase DAO Factory


package com.nspsac.seguridad.ldap;

import javax.naming.NamingException;

import com.nspsac.seguridad.ldap.AccesoLDAP;
import com.nspsac.seguridad.ldap.AccesoLDAPImpl;

public class AccesoLDAPFactory {


public static AccesoLDAP create() throws NamingException {
return new AccesoLDAPImpl();
}
}

Y la implementación de la interfaz DAO


La clase InitialContext es configurado como una aplicación web que es desplegado
inicialmente, y está disponible para los componentes de la aplicación web (para acceso
de solo lectura). Todas las entradas y recursos configurados están asociados al espacio
de nombre JNDI java:comp/env para su acceso a un recurso. Para el caso de nuestra
clase JavaBean estaría configurado como la que se muestra en el código siguiente.

package com.nspsac.seguridad.ldap;

import java.io.*;
import java.util.*;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;

import netscape.ldap.LDAPAttribute;
import netscape.ldap.LDAPAttributeSet;
import netscape.ldap.LDAPConnection;
import netscape.ldap.LDAPEntry;
import netscape.ldap.LDAPException;
import netscape.ldap.LDAPSearchConstraints;
import netscape.ldap.LDAPSearchResults;
import netscape.ldap.LDAPv3;

import com.nspsac.bean.BeanLDAPHost;
import com.nspsac.utils.exception.IncompleteConversationalState;

public class AccesoLDAPImpl implements AccesoLDAP{

private Hashtable htEnv;

Irenio Luis Chagua Aduviri


Acceso a OpenLDAP mediante Netscape Directory SDK

private DirContext nspsacCtx;

public InitialDirContext getInitialDirContext() throws NamingException {


return (InitialDirContext)nspsacCtx;
}

public void getInstance() throws NamingException {


htEnv = getEnvironment();
Hashtable htJndi = new Hashtable();
htJndi.put("java.naming.factory.initial", (String)htEnv.get("DN_CTX"));
htJndi.put("java.naming.provider.url", (String)htEnv.get("DN_HOST_PORT"));
htJndi.put("java.naming.security.principal", (String)htEnv.get("DN_MGR"));
htJndi.put("java.naming.security.credentials", (String)htEnv.get("DN_PWD"));
nspsacCtx = new InitialDirContext(htJndi);
}

public Hashtable getEnvironment() throws NamingException {


InitialContext initCtx = null;
Hashtable htEnv = new Hashtable();
try {
initCtx = new InitialContext();
Context ctx = (Context)initCtx.lookup("java:comp/env");
BeanLDAPHost beanldaphost = (BeanLDAPHost)ctx.lookup("beanldaphost");

String host_port = new StringBuffer("ldap://").append(


beanldaphost.getAttribute("ldap_iphost")).append(":").append(
beanldaphost.getAttribute("ldap_puerto")).toString();

htEnv.put("DN_HOST", beanldaphost.getAttribute("ldap_iphost"));
htEnv.put("DN_PORT", beanldaphost.getAttribute("ldap_puerto"));
htEnv.put("DN_HOST_PORT", host_port);
htEnv.put("DN_MGR", beanldaphost.getAttribute("ldap_dnmgr")+","
+beanldaphost.getAttribute("ldap_dnbase"));
htEnv.put("DN_PWD", beanldaphost.getAttribute("ldap_dnpwd"));
htEnv.put("DN_BASE", beanldaphost.getAttribute("ldap_dnbase"));
htEnv.put("DN_RAIZ", beanldaphost.getAttribute("ldap_dnraiz"));
htEnv.put("DN_CTX", beanldaphost.getAttribute("ldap_ctxfactory"));
ctx.close();
}
catch(Exception e) {
e.printStackTrace();
}

finally {
if(initCtx != null)
initCtx.close();
}

return htEnv;
}
}

El método getEnvironment recogerá los valores que habíamos definido en nuestra


configuración JNDI que son información acerca del directorio LDAP, esto almacenado en
un tipo de dato Collection de Java que es Hashtable, para luego estar disponible la
conexión hacia el directorio LDAP, el que prepara los datos de conexión hacia este
directorio es el método getInstance que tendrá los datos recogidos en dos variables
globales de la clase de tipo private para que pueda ser utilizado en otros métodos de la
clase.

Irenio Luis Chagua Aduviri


Directorio SDK para Java

7. Directorio SDK para Java


Como se ha mencionado anteriormente acerca del acceso a un directorio LDAP desde
una aplicación empresarial, aquí implementaremos los métodos para el acceso, tales
como autenticación de cuentas de usuario, cambio de atributos, agregar atributos, quitar
atributos, buscar mediante un RDN, entre otros.

Un directorio SDK para Java tiene las siguientes funcionalidades:

ƒ Libertad para el manejo de protocolos


ƒ El uso de objetos estándares para devolver y procesar los datos
ƒ Utilidad de clases para el manejo de las entidades específicas de LDAP
ƒ Acceso completo para todos los servicios LDAP
ƒ Modelos de autenticación flexibles
ƒ La habilidad de ejecutar en cualquier parte una vez se haya escrito el código
ƒ Funcionalidad multicapa
ƒ Una plataforma de aplicaciones para directorios

Búsqueda de una Entrada de Directorio


Debido a que la facilidad de un directorio LDAP es su habilidad de mostrar resultados
de las consultas en forma rápida, para esto empezaremos con realizar una búsqueda
para obtener una entrada de nombre y sus atributos con sus respectivos valores.

Antes de realizar una búsqueda en un directorio LDAP, es necesario tener en cuenta la


siguiente información:

ƒ Nombre de Servidor donde está instalado el directorio LDAP, también puede ser la
dirección IP del servidor, se usa "localhost" cuando se realizan las pruebas en una
sola máquina.
ƒ Número de puerto del directorio LDAP, que es el puerto TCP de la máquina donde el
servidor de directorio es escuchado por las conexiones LDAP, el puerto estándar
para LDAP es 389 para las conexiones no SSL. Para las conexiones basados en SSL
es el puerto 636.
ƒ DN base del árbol de directorio administrado por el servidor, es el nombre base
como raíz por donde empezará a realizar la búsqueda, por ejemplo
ou=People,dc=nspsac,dc=com.
ƒ Alcance de la búsqueda (Scope), es el punto de partida de una búsqueda y la
profundidad a la que realiza la búsqueda en un árbol de directorio, hay tres opciones
para este alcance:
o BASE, representado por la constante LDAPConnection.SCOPE_BASE, es usado
solo para búsquedas de DN base.
o ONE, representado por la constante LDAPConnection.SCOPE_ONE, es usado para
indicar que realice la búsqueda de todas las entradas debajo de DN base,
pero no incluye el DN base.

Irenio Luis Chagua Aduviri


Acceso a OpenLDAP mediante Netscape Directory SDK

o SUBTREE, representado por la constante LDAPConnection.SCOPE_SUB, es


usado para indicar que realice la búsqueda de todas las entradas debajo e
incluso el DN base.

"(&(objectclass=person)(uid=" + uid + "))"

ƒ Filtros de búsqueda, es la consulta que se realiza, es usado para filtrar las entradas
de directorios y devolver cierta cantidad de registros. Los filtros son usados
mediante los paréntesis y combinaciones de los símbolos ‘&’, ‘|’ y ‘!’ que
representan ‘And’, ‘Or’ y ‘Not’ respectivamente. Si se quiere ubicar a todas las
personas que sus apellidos (representado mediante el atributo sn) empiecen con
“Mamani" se realiza mediante el siguiente filtro:

(&(objectclass=person)(sn=Mamani*))

ƒ Los atributos que se quieren mostrar en la búsqueda, puede que a veces solo se
requiere algunos atributos y no todos los atributos presentes en una entrada de
directorio. Si no se quiere recuperar ningún atributo se puede usar la constante
LDAPConnection.NO_ATTRS. Si se desea recibir todos los atributos del usuario se
puede usar la constante LDAPConnection.ALL_USER_ATTRS, ó en otro caso puede usar
un array de cadenas de caracteres indicando los atributos que se quiere recuperar.
ƒ Opcionalemente las preferencias de búsqueda, estas preferencias incluyen la
cantidad de tiempo que se desea permitir para la búsqueda, máximo número de
registros que se aceptará, y si la búsqueda debe esperar hasta que todos los datos
son recibidos. Las preferencias de búsqueda son especificados usando la clase
LDAPSearchConstraints. Los métodos usados en esta clase son las siguientes:
o setBatchSize especifica cómo deben ser devueltos los resultados de la
búsqueda. El valor cero ‘0’ indica que debe esperar hasta que todos los
resultados sean devueltos, el valor uno ‘1’ devuelve cada resultado como
esté disponible.
o setHopLimit especifica cuántas veces deben ser devueltas en una búsqueda
de una entrada.
o setMaxResults especifica el número máximo de resultados que deben ser
devueltas desde una búsqueda. Se usa el valor cero ‘0’ para resultados
ilimitados.
o setReferrals especifica si el SDK debe ó no seguir las referencias
automáticamente.
o setServerTimeLimit especifica el número máximo de segundos que debe
tardar en entregar los resultados de la búsqueda.

Una vez repasado sobre los conceptos para el acceso a un directorio LDAP, ahora
definimos el método que realizará la búsqueda en un directorio mediante un filtro que le
pasaremos como parámetro, este filtro será de tipo “atributo=valor”, que nos puede
servir para realizar búsquedas por los atributos uid, employeeNumber, ruc, dni, mail,
cn, sn y de los demás atributos, siempre y cuando el atributo sea de tipo cadena de
texto. El método tiene el nombre de buscarEnLDAP(String uid).

Para la búsqueda, ya contamos con información del nombre del servidor, el puerto del
servidor, el DN base, los atributos que están definidos en la variable ATTRS, y las
preferencias de búsqueda se ha establecido a un número máximo de registro igual a 1,
ya que la búsqueda está pensado para los atributos como nombres distintivos relativos y

Irenio Luis Chagua Aduviri


Directorio SDK para Java

para obtener un conjunto de registros habría que cambiar estas preferencias de


búsqueda.

Los resultados de una búsqueda son devueltos como un objeto LDAPSearchResults. Hay
dos métodos para realizar el recorrido: nextElement y next, ambos métodos devuelven
un objeto que puede ser LDAPEntry, LDAPReferralException ó LDAPException. Para este
caso usaremos el método next.

El método next() de LDAPSearchResults devuelve un objeto LDAPEntry. La clase


LDAPEntry contiene los siguientes cuatro métodos:
ƒ getDN que devuelve el nombre distintivo completo de una entrada como una cadena
de texto (por ejemplo, uid=jmamani, ou=People, dc=nspsac, dc=com).
ƒ getAttribute(String name) en este caso el argumento es el nombre del atributo, del
que se quiere es su valor respectivo, es devuelto del tipo LDAPAttribute.
ƒ getAttributeSet devuelve un objeto LDAPAttributeSet que representa todos los
atributos en esta entrada.
ƒ toString devuelve la entrada completa, incluye los atributos obtenidos como una
cadena de texto.

Una vez que se tiene los atributos de una entrada, se puede obtener los valores de
estos atributos. La clase LDAPAttribute tiene varios métodos obtener el valor de los
atributos. Los métodos que normalmente se utilizan en la mayoría de los casos son los
siguientes:

ƒ getStringValues devuelve de tipo Enumeration los valores para un atributo de tipo


cadena de texto.
ƒ getByteValues devuelve de tipo Enumeration los valores para un atributo de tipo
binario, como el caso de las fotos.
ƒ getName devuelve el nombre del atributo.

private HashMap buscarEnLDAP(String uid)


throws IncompleteConversationalState {

HashMap hMap = new HashMap();


LDAPConnection ldap = new LDAPConnection();

try {
ldap.connect(3, (String)htEnv.get("DN_HOST"),
Integer.parseInt((String)htEnv.get("DN_PORT")),
(String)htEnv.get("DN_MGR"), (String)htEnv.get("DN_PWD"));

LDAPSearchConstraints mySearchConstraints = ldap.getSearchConstraints();


mySearchConstraints.setMaxResults(1);
LDAPSearchResults myResults = null;

myResults = ldap.search( new StringBuffer(


(String)htEnv.get("DN_RAIZ")).append(", ").append(
(String)htEnv.get("DN_BASE")).toString(),
LDAPv3.SCOPE_SUB,
"(&(objectclass=person)(" + uid + "))",
ATTRS, false, mySearchConstraints);

if (myResults.hasMoreElements()) {
LDAPEntry myEntry = myResults.next();
hMap.put("dn", myEntry.getDN());

Irenio Luis Chagua Aduviri


Acceso a OpenLDAP mediante Netscape Directory SDK

LDAPAttributeSet entryAttrs = myEntry.getAttributeSet();


Enumeration attrsInSet = entryAttrs.getAttributes();
String namePhoto = ((String)myEntry.getAttribute("uid").
getStringValues().nextElement()).concat(".jpg");

while (attrsInSet.hasMoreElements()) {
LDAPAttribute nextAttr = (LDAPAttribute) attrsInSet.nextElement();
String attrName = nextAttr.getName();
if (attrName.trim().equalsIgnoreCase("jpegPhoto")) {
Enumeration valsInAttr = nextAttr.getByteValues();
if (valsInAttr.hasMoreElements()) {
if(savePhoto(namePhoto, (byte[])valsInAttr.nextElement())){
hMap.put(attrName.trim(), namePhoto);
}
else {
hMap = new HashMap();
hMap.put("Mensaje","Error al recuperar Foto");
break;
}
}
}
else{
Enumeration valsInAttr = nextAttr.getStringValues();
if (valsInAttr.hasMoreElements()) {
hMap.put(attrName.trim(), valsInAttr.nextElement());
}
}
}
}
else{
hMap.put("Mensaje","El Usuario indicado no se encuentra registrado.");
}
}
catch (LDAPException e) {
e.printStackTrace();
hMap.put("Mensaje","ERROR:"
+e.getLDAPResultCode()
+"->"
+LDAPException.errorCodeToString(e.getLDAPResultCode()));
}
catch (NumberFormatException e) {
e.printStackTrace();
hMap.put("Mensaje",
"HA OCURRIDO UN PROBLEMA EN LOS PARAMETROS DEL SERVIDOR:"
+ e.getMessage());
}

finally {
try {
if (ldap.isConnected()) {
ldap.disconnect();
}
}
catch (LDAPException ex) {
throw new IncompleteConversationalState(
"NO SE PUDO CERRAR EL ENLACE:"
+ ex.getLDAPResultCode()
+ "->"
+ LDAPException.errorCodeToString(ex.getLDAPResultCode()));
}
}
return hMap;
}

Irenio Luis Chagua Aduviri


Directorio SDK para Java

private boolean savePhoto(String namePhoto, byte[] thePhoto){


boolean saved = false;
try{
OutputStream outputStream = new FileOutputStream(DIR_IMGS+namePhoto);
outputStream.write(thePhoto);
outputStream.flush();
outputStream.close();
saved = true;
}
catch (FileNotFoundException e){
e.printStackTrace();
}
catch (IOException e){
e.printStackTrace();
}
return saved;
}

Autenticando Usuarios
Hasta aquí no hemos visto el tema de autenticación a un directorio LDAP. Las
conexiones hasta aquí han sido utilizando la cuenta por defecto configurado en el mismo
directorio LDAP, más no hemos utilizado la cuenta de usuario y su contraseña. Por
ejemplo es posible que en un directorio se quiera restringir el acceso a ciertos
atributos, no permitiendo el acceso a algunos atributos como la fotografía de un
empleado, que solamente puede tener acceso personal autorizado. Para realizar
cambios tales como agregar, modificar, consultar ó eliminar ciertos atributos de una
entrada de directorio LDAP, por lo general se debe autenticar.

El protocolo LDAP proporciona una operación para permitir conectar a los clientes para
autenticar al servidor. El método más simple de autenticación soportado por el
protocolo es un método que al cliente le permite enviar un DN y contraseña al servidor.
Para usar el método de autenticación simple, se puede usar mediante el método
LDAPConnection.authenticate ó un método LDAPConnection.connect variante que toma una
autenticación pasando como parámetros a DN y contraseña. Algunas de las excepciones
que se pueden producir son las siguientes:

ƒ LDAPException.NO_SUCH_OBJECT. Esta excepción es lanzada si el DN especificado no


corresponde a una entrada del directorio.
ƒ LDAPException.INVALID_CREDENTIALS. Esta excepción es lanzada si la contraseña
especificado no es correcta.

public HashMap autenticar(String uid, String pwd)


throws NamingException, IncompleteConversationalState {

HashMap hMap = new HashMap();


LDAPConnection ldap = new LDAPConnection();

try {
ldap.connect(3, (String)htEnv.get("DN_HOST"),
Integer.parseInt((String)htEnv.get("DN_PORT")),
(String)htEnv.get("DN_MGR"),
(String)htEnv.get("DN_PWD"));

hMap = buscarEnLDAP("uid=" + uid);


if(hMap.get("dn") != null){
ldap.authenticate( (String) hMap.get("dn"), pwd);

Irenio Luis Chagua Aduviri


Acceso a OpenLDAP mediante Netscape Directory SDK

}
if(hMap.get("Mensaje") == null){
hMap.put("Mensaje","Usuario ".concat(uid).concat(" autenticado"));
}
}
catch (LDAPException e) {
e.printStackTrace();
hMap = new HashMap();
switch (e.getLDAPResultCode()) {
case LDAPException.NO_SUCH_OBJECT:
hMap.put("Mensaje",uid.concat(": El usuario indicado no existe"));
break;
case LDAPException.INVALID_CREDENTIALS:
hMap.put("Mensaje",uid.concat(": Password invalido"));
break;
default:
hMap.put("Mensaje",uid.concat(
": No se ha podido realizar la autenticacion, error:"
+ e.getLDAPResultCode()));
break;
}
}
catch (NumberFormatException e) {
e.printStackTrace();
hMap = new HashMap();
hMap.put("Mensaje",
"HA OCURRIDO UN PROBLEMA EN LOS PARAMETROS DEL SERVIDOR:"
+ e.getMessage());
}
finally {
try {
if (ldap.isConnected()) {
ldap.disconnect();
}
}
catch (LDAPException ex) {
throw new IncompleteConversationalState(
"NO SE PUDO CERRAR EL ENLACE:"
+ ex.getLDAPResultCode()
+ "->"
+ LDAPException.errorCodeToString(ex.getLDAPResultCode()) + "<br>"
+ ex.getMessage());
}
}
return hMap;
}

Creando y Manipulando entradas de directorio


En una entrada de directorio LDAP es posible realizar las modificaciones de una
entrada, tanto en crear una entrada, modificar una entrada con sus respectivos
atributos, y eliminar una entrada. En la modificación de entradas es posible el manejo de
los atributos como la de añadir atributos, modificar atributos y eliminar atributos. Estas
operaciones siempre estarán presentes en un manejo de entrada de directorios LDAP.

Irenio Luis Chagua Aduviri


Directorio SDK para Java

Para agregar una nueva entrada de directorio es necesario definir un nombre distintivo
DN para la entrada y los atributos para esta entrada. Para agregar una nueva entrada es
necesario tener en cuenta los siguientes pasos:

1. Crear un objeto LDAPAttribute para cada atributo que forma la entrada.


2. Crear un objeto LDAPAttributeSet y utilizar el método add para agregar cada objeto
LDAPAttribute del paso 1.
3. Crear un objeto LDAPEntry que especifica el nuevo DN y el LDAPAttributeSet del
paso 2.
4. Invocar al método LDAPConnection.add con el objeto LDAPEntry del paso 3.

Con estos pasos se ha creado el método addEntry que recibe dos parámetros, el primero
es el nombre distintivo identificador de usuario y el segundo un conjunto de atributos en
un Collection HashMap.

public void addEntry(String uid, HashMap attrs) {


LDAPAttributeSet entryAttrs = new LDAPAttributeSet();
LDAPConnection ldap = new LDAPConnection();
try{
ldap.connect(3, (String)htEnv.get("DN_HOST"),
Integer.parseInt((String)htEnv.get("DN_PORT")),
(String)htEnv.get("DN_MGR"), (String)htEnv.get("DN_PWD"));

String dn = new StringBuffer("uid=").append(uid).append(", ").append(


(String)htEnv.get("DN_RAIZ")).append(", ").append(
(String)htEnv.get("DN_BASE")).toString();

for(Iterator it = attrs.keySet().iterator(); it.hasNext(); ){


String name = (String)it.next();
entryAttrs.add( new LDAPAttribute( name, (String)attrs.get(name)));
}

entryAttrs.add( new LDAPAttribute("objectClass", OBECT_CLASS) );


LDAPEntry myEntry = new LDAPEntry( dn, entryAttrs );
ldap.add(myEntry);
}
catch (LDAPException e) {
e.printStackTrace();
}
}

La otra operación con las entradas es la modificación de sus atributos. Para modificar
un atributo de una entrada, se ha utilizado el método modifyAttributes del objeto
DirContext, también es posible modificar un atributo con el uso del objeto
LDAPModification y luego invocando al método modify de LDAPConnection. Para modificar
los atributos de una entrada es necesario tener en cuenta los siguientes pasos:

1. Crear un objeto Attribute para un atributo que se desea modificar.


2. Crear un conjunto de objetos ModificationItem, puede ser uno solo, especificando
DirContext.ADD_ATTRIBUTE, REPLACE_ATTRIBUTE ó REMOVE_ATTRIBUTE para cada objeto
Attribute del paso 1.
3. Invocar al método modifyAttributes con el DN y el ModificationItem.

Irenio Luis Chagua Aduviri


Acceso a OpenLDAP mediante Netscape Directory SDK

public void addAttribute(String uid, String nameAttr, String valAttr)


throws NamingException {

ModificationItem[] mods = new ModificationItem[1];


Attribute mod = new BasicAttribute(nameAttr, valAttr);
mods[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, mod);

String dn = new StringBuffer("uid=").append(uid).append(", ").append(


htEnv.get("DN_RAIZ")).append(",").append(
htEnv.get("DN_BASE")).toString();

nspsacCtx.modifyAttributes(dn, mods);
}

public void modifyAttribute(String uid, String nameAttr, String valAttr)


throws NamingException {

ModificationItem[] mods = new ModificationItem[1];


Attribute mod = new BasicAttribute(nameAttr, valAttr);
mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, mod);

String dn = new StringBuffer("uid=").append(uid).append(", ").append(


htEnv.get("DN_RAIZ")).append(",").append(
htEnv.get("DN_BASE")).toString();

nspsacCtx.modifyAttributes(dn, mods);
}

public void deleteAttribute(String uid, String nameAttr)


throws NamingException {

ModificationItem[] mods = new ModificationItem[1];


Attribute mod = new BasicAttribute(nameAttr);
mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, mod);

String dn = new StringBuffer("uid=").append(uid).append(", ").append(


htEnv.get("DN_RAIZ")).append(",").append(
htEnv.get("DN_BASE")).toString();

nspsacCtx.modifyAttributes(dn, mods);
}

Los datos de una entrada deben estar bien guardados en un directorio LDAP. Pero llega
un momento en que será necesario borrar una entrada LDAP. Para esto quitar una
entrada de un directorio es muy simple. Solamente se debe especificar qué DN se debe
quitar e invocar al método LDAPConnection.delete.

public void deleteEntry(String uid) {


LDAPConnection ldap = new LDAPConnection();
try{
ldap.connect(3, (String)htEnv.get("DN_HOST"),
Integer.parseInt((String)htEnv.get("DN_PORT")),
(String)htEnv.get("DN_MGR"), (String)htEnv.get("DN_PWD"));

String dn = new StringBuffer("uid=").append(uid).append(", ").append(


(String)htEnv.get("DN_RAIZ")).append(", ").append(
(String)htEnv.get("DN_BASE")).toString();

ldap.delete(dn);
}
catch (LDAPException e) {
e.printStackTrace();
}
}

Irenio Luis Chagua Aduviri


Directorio SDK para Java

Por último, la operación en una entrada es el renombramiento, es decir modificando el


RDN de una entrada de directorio LDAP. Por ejemplo se puede cambiar uid=pcarrillo
del DN ou=People,dc=nspsac,dc=com para tener el uid=pedro.carrillo del DN
ou=People,dc=nspsac,dc=com. El método LDAPConnection.rename invoca la operación LDAP
para cambiar el RDN de la entrada.

No solamente es posible cambiar el RDN en un mismo nivel del árbol del directorio
LDAP, hay la posibilidad de mover ó copiar a un RDN a una parte diferente del árbol del
directorio LDAP. Como ejemplo veamos al RDN uid=jmamani del DN
ou=People,dc=nspsac,dc=com lo movemos ó lo copiamos a otra parte del árbol como RDN
uid= juan.mamani y DN ou=Admin,dc=nspsac,dc=com.

public void renameEntry(String uid, String newUid) {


LDAPConnection ldap = new LDAPConnection();
try{
ldap.connect(3, (String)htEnv.get("DN_HOST"),
Integer.parseInt((String)htEnv.get("DN_PORT")),
(String)htEnv.get("DN_MGR"), (String)htEnv.get("DN_PWD"));

String dn = new StringBuffer("uid=").append(uid).append(", ").append(


(String)htEnv.get("DN_RAIZ")).append(", ").append(
(String)htEnv.get("DN_BASE")).toString();

String newRDN = new StringBuffer("uid=").append(newUid).toString();

ldap.rename(dn, newRDN, true);


}
catch (LDAPException e) {
e.printStackTrace();
}
}

public void renameEntry(String uid, String newUid, String newGroup) {


LDAPConnection ldap = new LDAPConnection();
try{
ldap.connect(3, (String)htEnv.get("DN_HOST"),
Integer.parseInt((String)htEnv.get("DN_PORT")),
(String)htEnv.get("DN_MGR"), (String)htEnv.get("DN_PWD"));

String dn = new StringBuffer("uid=").append(uid).append(", ").append(


(String)htEnv.get("DN_RAIZ")).append(", ").append(
(String)htEnv.get("DN_BASE")).toString();

String newRDN = new StringBuffer("uid=").append(newUid).toString();

String newParentDN = new StringBuffer("ou=").append(newGroup).append(",


").append((String)htEnv.get("DN_BASE")).toString();

ldap.rename(dn, newRDN, newParentDN, true);


}
catch (LDAPException e) {
e.printStackTrace();
}
}

Irenio Luis Chagua Aduviri


Acceso a OpenLDAP mediante Netscape Directory SDK

Servlets, JSP y LDAP


Una vez que se ha realizado con la implementación de las clases para el acceso a un
directorio LDAP, será necesario mostrar el resultado del acceso mediante un Servlet
para enviar datos a una página web haciendo uso de JSP. Para esto creamos el Servlet
ServletGestionLDAP.

package com.nspsac.seguridad;

import java.util.HashMap;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.nspsac.seguridad.ldap.AccesoLDAP;
import com.nspsac.seguridad.ldap.AccesoLDAPFactory;
import com.nspsac.utils.exception.IncompleteConversationalState;

public class ServletGestionLDAP extends HttpServlet{

public void init(ServletConfig config) throws ServletException {


super.init(config);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException
{
HashMap hmAut = null;
HashMap hmSearch = null;
String cambioClave = null;

HttpSession session = request.getSession(true);

try{
String accion = request.getParameter("accion");
String opcion = request.getParameter("modo");
AccesoLDAP acceso = AccesoLDAPFactory.create();
acceso.getInstance();
String usuario = request.getParameter("user");

if(accion.equals("autenticacion")){
String clave = request.getParameter("pwd");
hmAut = acceso.autenticar(usuario,clave);
session.setAttribute("hmAut", hmAut);
session.removeAttribute("hmSearch");
session.removeAttribute("cambioClave");
}
else if(accion.equals("busqueda")){
hmSearch = acceso.findByUID(usuario);
session.setAttribute("hmSearch", hmSearch);
session.removeAttribute("hmAut");
session.removeAttribute("cambioClave");
}
else if(accion.equals("cambioclave")){
String claveanterior = request.getParameter("oldpwd");
String clavenueva = request.getParameter("newpwd");
String claveconfirma = request.getParameter("repwd");
cambioClave = usuario.concat(": Usuario indicado no existe.");
if(clavenueva.equals(claveconfirma)){
acceso.cambiarClave(usuario,claveanterior,clavenueva);
cambioClave = usuario.concat(": La clave ha sido clambiada

Irenio Luis Chagua Aduviri


Directorio SDK para Java

satisfactoriamente.");
}
else{
cambioClave = usuario.concat(": Clave nueva y su confirmaci&oacute;n
no concuerdan."+
"<br>Ingresar nuevamente las claves");
}
session.setAttribute("cambioClave", cambioClave);
session.removeAttribute("hmAut");
session.removeAttribute("hmSearch");
}
session.setAttribute("opcion", opcion);

HashMap hmAttrs = new HashMap();


hmAttrs.put("givenName", "Alberto");
hmAttrs.put("sn","Velasquez Prado");
hmAttrs.put("mail","avelasquez@nspsac.com");
hmAttrs.put("uid","avelasquez");
hmAttrs.put("cn","Alberto Velasquez Prado");
hmAttrs.put("dni","87654321");
hmAttrs.put("ruc","10876543218");
hmAttrs.put("employeeNumber","6825");
hmAttrs.put("telephoneNumber","051202020");
hmAttrs.put("direccion","Av. El Sol Nro. 560");
hmAttrs.put("st","Puno");
hmAttrs.put("l","Puno");
acceso.addEntry("avelasquez",hmAttrs);
acceso.addAttribute("avelasquez","userPassword","abc");
acceso.modifyAttribute("avelasquez","userPassword","abc1");
acceso.renameEntry("pcarrillo","pedro.carrillo");
acceso.renameEntry("jmamani","juan.mamani","Admin");
}
catch(NamingException ne){
ne.printStackTrace();
}
catch(IncompleteConversationalState ics){
ics.printStackTrace();
}
catch(Exception e){
e.printStackTrace();
}

try{

getServletConfig().getServletContext().getRequestDispatcher("/ldap").forward(req
uest, response);
}
catch(Exception e){
e.printStackTrace();
}
}
}

Irenio Luis Chagua Aduviri


Acceso a OpenLDAP mediante Netscape Directory SDK

FIGURA 7.1 Pantalla de Inicio

La página JSP que recoge valores enviados desde un servlet como los atributos de una
entrada de directorio, son definidos de la siguiente forma.

<%
HashMap hmAut = (HashMap)session.getAttribute("hmAut");
HashMap hmSearch = (HashMap)session.getAttribute("hmSearch");
String cambioClave = (String)session.getAttribute("cambioClave");
String opcion = (String)session.getAttribute("opcion");
%>
<%//... Para mostrar los datos de una entrada después de autenticar...%>
<%if(hmAut != null){
String uid = (String)hmAut.get("uid");
String sn = (String)hmAut.get("sn");
String givenName = (String)hmAut.get("givenName");
String cn = (String)hmAut.get("cn");
String employeeNumber = (String)hmAut.get("employeeNumber");
String dni = (String)hmAut.get("dni");
String ruc = (String)hmAut.get("ruc");
String direccion = (String)hmAut.get("direccion");
String mail = (String)hmAut.get("mail");
String telephoneNumber = (String)hmAut.get("telephoneNumber");
String mobile = (String)hmAut.get("mobile");
String jpegPhoto = (String)hmAut.get("jpegPhoto");
String msg = (String)hmAut.get("Mensaje");
if(msg != null){%>
<div class="titulo"><%=msg%></div>
<%}%>
<table>
<tr><td><b>Cuenta de Usuario :</b></td> <td><%=uid%></td></tr>
<tr><td><b>Apellidos :</b></td> <td><%=sn%></td></tr>
<tr><td><b>Nombres :</b></td> <td><%=givenName%></td></tr>
<tr><td><b>Nombre Completo :</b></td> <td><%=cn%></td></tr>
<tr><td><b>Registro Empleado :</b></td>
<td><%=(employeeNumber!=null?employeeNumber:"-")%></td></tr>
<tr><td><b>DNI :</b></td> <td><%=dni%></td></tr>
<tr><td><b>RUC :</b></td> <td><%=ruc%></td></tr>
<tr><td><b>Dirección :</b></td>
<td><%=direccion%> - <%=hmAut.get("l")%>,
<%=hmAut.get("st")%></td></tr>
<tr><td><b>Correo Electrónico :</b></td> <td><%=mail%></td></tr>
<tr><td><b>Teléfono :</b></td>
<td><%=(telephoneNumber!=null)?telephoneNumber:"-"%></td></tr>
<tr><td><b>Teléfono Móvil :</b></td> <td><%=(mobile!=null)?mobile:"-
"%></td></tr>
<tr>
<td valign="top"><b>Foto :</b></td>

Irenio Luis Chagua Aduviri


Directorio SDK para Java

<td>
<%if(jpegPhoto != null) {%>
<img src="imgs/<%=jpegPhoto%>" alt="" border="0" width="70"
height="80">
<% } else {%>
-
<% }%>
</td>
</tr>
</table>
<%}%>
<%//... Para mostrar datos de una entrada después de una búsqueda... %>
<%if(hmSearch != null){
String msg = (String)hmSearch.get("Mensaje");
if(msg != null){%>
<div class="titulo"><%=msg%></div>
<%
hmSearch.remove("Mensaje");
}
for (Iterator it = hmSearch.keySet().iterator(); it.hasNext();){
String name = (String)it.next();
String value = (String)hmSearch.get(name);
if(!name.equals("jpegPhoto")){%>
<%=name%>: <%=value%><br>
<%}
else{
%>
<%=name%>: <br><img src="imgs/<%=value%>" alt="" border="0"><br>
<%}
}
}%>

Y por último realizando las búsquedas de entradas de directorios mediante un RDN,


autenticando usuarios y cambiando clave de un usuario. Solamente se ha incluido en la
página web las funcionalidades mencionadas, las demás opciones ya los puede incluir
con los métodos desarrollados en el presente artículo.

FIGURA 7.2 Usuario Autenticado

Irenio Luis Chagua Aduviri


Acceso a OpenLDAP mediante Netscape Directory SDK

8. Directorios LDAP
ƒ Apache Directory Server
ƒ OpenLDAP
ƒ Novell eDirectory
ƒ Windows Server 2003 Active Directory
ƒ Oracle Internet Directory
ƒ Sun Java System Directory Server Enterprise Edition

9. Clientes LDAP
ƒ JXplorer (Java)
ƒ LDAP Browser/Editor (Java)
ƒ Luma (Unix)
ƒ Frood (Unix)
ƒ CoralDirectory LDAP Browser (Windows)
ƒ LDAP Exporter (Windows)
ƒ maX.500 Macintosh
ƒ phpLDAPadmin (web)

10. Librerías para LDAP


ƒ Java LDAP
ƒ JDBC-LDAP Bridge Driver
ƒ Sun (iPlanet) Directory Server Deployment Guide
ƒ PHP LDAP
ƒ .NET LDAP
ƒ Perl-LDAP
ƒ Ruby/LDAP
ƒ Mozilla LDAP C SDK
ƒ LDAP in Python

11. Referencias y Herramientas utilizadas


1. OpenLDAP 2.2.29. http://www.openldap.org/
2. Netscape Directory SDK 4.1 for Java. http://www.mozilla.org/
3. JavaTM Platform, Standard Edition 6 Development Kit. http://java.sun.com/
4. Apache Jakarta Tomcat 5.5.9. http://www.apache.org/
5. LDAP Browser\Editor 2.8.2. http://www.iit.edu/~gawojar/ldap/
6. LDAP en Español. http://www.ldap-es.org/
7. Fuente de este artículo. http://www.javahispano.org/download/articulos/ldap.zip

Irenio Luis Chagua Aduviri