Interface JAVA et C d'acces a LDAP
LDAP
1. Présentation
LDAP (Lightweight Directory Access Protocol, traduisez Protocole d'accès aux annuaires léger) est un protocole standard permettant de gérer des annuaires, c'est-à-dire d'accéder à des bases d'informations sur les utilisateurs d'un réseau par l'intermédiaire de protocoles TCP/IP.
Les bases d'informations sont généralement relatives à des utilisateurs, mais elles sont parfois utilisées à d'autres fins comme pour gérer du matériel dans une entreprise.
Le protocole LDAP, développé en 1993 par l'université du Michigan, avait pour but de supplanter le protocole DAP (servant à accéder au service d'annuaire X.500 de l'OSI), en l'intégrant à la suite TCP/IP.
Le service d'annuaire X.500 était un standard conçu en 1988 par les opérateurs télécoms prévu pour interconnecter tout type d'annuaire dans un but de normalisation. Celui-ci définit :
- des règles de nommages pour les éléments qu'il contient
- des protocoles d'accès à l'annuaire (dont DAP)
- des moyens d'authentification de l'utilisateur
Toutefois, la norme X500 était basée sur les protocoles ISO et impliquait donc une mise en place très lourde. Ainsi, en 1993 l'université du Michigan a adapté le protocole DAP de la norme X.500 au protocole TCP/IP et mis au point LDAP.
A partir de 1995, LDAP est devenu un annuaire natif (standalone LDAP), afin de ne plus servir uniquement à accéder à des annuaires de type X500, c'est-à-dire en gérant sa propre base de données. LDAP est ainsi une version allégée du protocole DAP, d'où son nom de Lightweight Directory Access Protocol prévu pour fonctionner avec les protocoles TCP/IP.
Le protocole LDAP
1. Introduction
Le protocole LDAP est uniquement prévu pour gérer l'interfaçage avec les annuaires. Plus exactement il s'agit d'une norme définissant la façon suivant laquelle les informations sont échangées entre le client et le serveur LDAP ainsi que la manière de laquelle les données sont représentées. Ainsi ce protocole se conforme à quatre modèles de base :
- un modèle d'information : définissant le type d'information stocké dans l'annuaire
- un modèle de nommage (parfois appelé modèle de désignation) : définissant la façon de laquelle les informations sont organisées dans l'annuaire et leur désignation
- un modèle fonctionnel (parfois appelé modèle de services) : définissant la manière d'accéder aux informations et éventuellement de les modifier, c'est-à-dire les services offerts par l'annuaire.
- un modèle de sécurité : définissant les mécanismes d'authentification et de droits d'accès des utilisateurs à l'annuaire.
De plus, LDAP définit la communication entre
- Le client et le serveur, c'est-à-dire les commandes de connexion et de déconnexion au serveur, de recherche ou de modification des entrées
- Les serveurs eux-mêmes, pour définir d'une part le service de réplication (replication service), c'est-à-dire un échange de contenu entre serveurs et synchronisation, d'autre part pour créer des liens entre les annuaires (on parle de referral service).
Le format des données dans le protocole LDAP n'est pas le format ASCII comme c'est le cas pour la plupart des protocoles mais une version allégée du Basic Encoding Rules (BER) appelée Lightweight Basic Encoding Rules (LBER).
D'autre part, LDAP fournit un format d'échange (LDIF, Lightweight Data Interchange Format) permettant d'importer et d'exporter les données d'un annuaire avec un simple fichier texte.
Enfin il existe un certain nombre d'API (Application Programming Interface, c'est-à-dire des interfaces de programmation) permettant de développer des applications clientes permettant de se connecter à des serveurs LDAP avec différents langages Ainsi LDAP fournit à l'utilisateur des méthodes lui permettant de:
- se connecter
- se déconnecter
- rechercher des informations
- comparer des informations
- insérer des entrées
- modifier des entrées
- supprimer des entrées
D'autre part le protocole LDAP (dans sa version 3) propose des mécanismes de chiffrement (SSL, ...) et d'authentification (SASL) permettant de sécuriser l'accès aux informations stockées dans la base.
De plus, contrairement à la plupart des protocoles, LDAP permet d'effectuer plusieurs requêtes sur le serveur d'annuaire à l'aide d'une seule connexion. en effet, le protocole HTTP ne permet d'effectuer qu'une et une seule requête à chaque connexion au serveur.
Les opérations
- Abandon
- Abandonne l'opération précédemment envoyées au serveur
- Add
- Ajoute une entrée au répertoire
- Bind
- Initie une nouvelle session sur le serveur LDAP
- Compare
- Compare les entrées d'un répertoire selon des critères
- Delete
- Supprime une entrée d'un répertoire
- Extended
- Effectue des opérations étendues
- Rename
- Modifie le nom d'une entrée
- Search
- Recherche des entrées d'un répertoire
- Unbind
- Termine une session sur le serveur LDAP
Les serveurs
Gratuits
- OpenLDAP
- JavaLDAP
Payants
- Computer Associate eTrust
- Novell NDS eDirectory
- Netscape Directory Server
- Microsoft Active Directory
- Sun ONE Directory Server
- Oracle Internet Directory
- IBM Directory Server
- ...
Réferences
Réferences LDAP
Réferences API C
Réferences API Java
Réferences RFC
API C : Les Fonctions
il existe deux modes de communication avec le serveur ldap (synchrone et asynchrone). dans le premier, le client attend la reponse du serveur. dans le second, il n'est pas obligé d'attendre et il pourra aller chercher la reponse quand il le souhaitera.
i. pré-requis
¨Pour utiliser les fonctions d'accès aux annuaires ldap, il faut inclure ldap.h.
#include <ldap.h>
ii. initialiser la librairie
Avant de pouvoir utiliser la librairie, il faut l'initialiser.
Cette fonction prend en paramètre le serveur et le port sur lequel on veut se connecter.
cette fonction n'établit pas de connexion.
ldap * ldap_init (char * machine , int port)
cette fonction retourne une stucture ldap qui contient les paramètres de connexion.
iii. annuler la dernière opération
Cette fonction permet d'annuler une requete asynchrone.
Cette fonction prend en paramettre les paramètres de connexion (ld) et le numero d'identification de la requete que l'on souhaite annuler.
int ldap_abandon (ldap *ld, int msgid)
iv. se connecter au serveur ldap
cette fonction, en mode asynchrone, permet d'établir la connexion.
int ldap_bind (ldap *ld, const char *who, const char *cred, int method)
Cette fonction est l'équivalent en mode synchrone.
int ldap_bind_s (ldap *ld, const char *who, const char *cred, int method)
v. se connecter au serveur ldap (authentification simple)
Cette fonction, en mode asynchrone, permet d'établir la connexion avec une authentification simplifiée.
int ldap_simple_bind (ldap *ld, const char *who, const char *passwd)
Cette fonction est l'équivalent en mode synchrone.
int ldap_simple_bind_s (LDAP *ld, const char *who, const char *passwd)
VI. Se déconnecter du serveur LDAP
Cette fonction, en mode asynchrone, permet de fermer la connexion.
int ldap_unbind (LDAP *ld)
Cette fonction est l'équivalent en mode synchrone.
int ldap_unbind_s (LDAP *ld)
VII. Rechercher
Cette fonction, en mode asynchrone, permet d'effectuer une recherche.
int ldap_search (LDAP *ld, char *base, int scope, char *filter,*attrs[], int attrsonly)
Cette fonction est l'équivalent en mode synchrone.
int ldap_search_s ( LDAP *ld, char *base, int scope, char *filter,*attrs[], int attrsonly , LDAPMessage ** res)
Cette fonction est l'équivalent en mode synchrone avec un temps maximal d'attente.
int ldap_search_st ( LDAP *ld, char *base, int scope, char *filter,*attrs[], int attrsonly , struct timeval * timeout, LDAPMessage ** res)
VIII. Attendre le résultat d'une opération asynchrone
Cette fonction permet d'attendre la reponse d'une requete asynchrone.
int ldap_result (LDAP *ld, int msgid, int all, s tv *timeout, LDAPMessage ** res)
IX. Ajouter une entrée
Cette fonction, en mode asynchrone, permet d'ajouter une entrée dans l'annuaire.
int ldap_add (LDAP *ld, const char *dn, LDAPMod * attrs[])
Cette fonction est l'équivalent en mode synchrone.
int ldap_add_s (LDAP *ld, const char *dn, LDAPMod * attrs[])
X. Supprimer une entrée
Cette fonction, en mode asynchrone, permet de supprimer une entrée de l'annuaire.
int ldap_delete (LDAP *ld, char *dn)
Cette fonction est l'équivalent en mode synchrone.
int ldap_delete_s (LDAP *ld, char *dn)
XI. Comparer
Cette fonction, en mode asynchrone, permet d'effectuer des comparaisons des entrées de l'annuaire.
int ldap_compare (LDAP *ld , char *dn , char *attr , char *value)
Cette fonction est l'équivalent en mode synchrone.
int ldap_compare_s (LDAP *ld , char *dn , char *attr , char *value)
XII. Parcours des attributs
Ces fonctions permettent de parcourir les attributs d'une entrée.
Cette fonction renvoit le permier attribut.
char *ldap_first_attribute(LDAP *ld, LDAPMessage entry, BerElement **ber)
Cette fonction permet de récupérer les attributs suivants.
char *ldap_next_attribute(LDAP *ld, LDAPMessage entry, BerElement *ber)
XIII. Parcours des entrées
Ces fonctions permettent de parcourir les entrées d'une reponse.
Cette fonction renvoit la première entrée.
LDAPMessage *ldap_first_entry (LDAP *ld, LDAPMessage *result)
Cette fonction permet de récupérer les entrées suivantes.
LDAPMessage *ldap_next_entry (LDAP *ld, LDAPMessage *result)
Cette fonction renvoit le nombre d'entrée dans la reponse.
int ldap_count_entries (LDAP *ld, LDAPMessage *entry)
XIV. Récupérer des informations
Cette fonction permet de récupérer les valeurs d'un attribut d'une entrée.
char **ldap_get_values(LDAP *ld, LDAPMessage *entry, char* attr)
XV. Modifier des informations
Cette fonction, en mode asynchrone, permet de modifier une entrée de l'annuaire.
int ldap_modify (LDAP *ld,char *dn, LDAPMod *mods[])
Cette fonction est l'équivalent en mode synchrone.
int ldap_modify_s (LDAP *ld,char *dn, LDAPMod *mods[])
XVI. Trier
Cette fonction permet de trier les entrées.
ldap_sort_entries (LDAP *ld,LDAPMessage **chain,char *attr, int (*cmp)())
Cette fonction permet de trier les valeurs.
ldap_sort_values (LDAP *ld,char **vals, int (*cmp)())
API C : Les Exemples
I. Connexion
/* $Novell: bind.c,v 1.8 2003/05/12 12:14:11 $ */
/**************************************************************************
* Novell Software Developer Kit
*
* Copyright (C) 2002-2003 Novell, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
* USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE AGREEMENT
* ACCOMPANYING THE SOFTWARE DEVELOPER KIT (SDK) THAT CONTAINS THIS WORK.
* PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS TO DEVELOPER A
* ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S SAMPLE CODE IN ITS
* PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION RIGHTS TO MARKET,
* DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT OF DEVELOPER'S
* PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR DEVELOPER'S
* CUSTOMERS WITH RESPECT TO THIS CODE.
*
***************************************************************************
bind.c
***************************************************************************
Description: The bind.c sample demonstrates both an anonymous and simple
LDAP v3 bind to an LDAP server.
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <ldap.h>
#if defined(N_PLAT_NLM) && defined(LIBC)
#include <screen.h>
#endif
static char usage[] =
"\nUsage: bind <host name> <port number> <login dn> <password>"
"\nExample: bind Acme.com 389 cn=admin,o=Acme secret\n";
int main( int argc, char **argv)
{
int rc, ldapPort, version;
char *ldapHost, *loginDN, *password;
LDAP *ld;
struct timeval timeOut = {10,0}; /* 10 second connection timeout */
#if defined(N_PLAT_NLM) && defined(LIBC)
setscreenmode(SCR_NO_MODE); /* Don't clear screen on exit */
#endif
if (argc != 5)
{
printf("%s", usage);
return (1);
}
ldapHost = argv[1];
ldapPort = atoi(argv[2]);
loginDN = argv[3];
password = argv[4];
/*
* Set LDAP version to 3.
* Using a NULL session handle sets the global options.
* All subsequent LDAP sessions created in this process will be version 3.
* Also set the connection timeout.
*/
version = LDAP_VERSION3;
ldap_set_option( NULL, LDAP_OPT_PROTOCOL_VERSION, &version);
ldap_set_option( NULL, LDAP_OPT_NETWORK_TIMEOUT, &timeOut);
/*
* Initialize the LDAP session
*/
if (( ld = ldap_init( ldapHost, ldapPort )) == NULL)
{
printf ( "\n\tLDAP session initialization failed\n");
return( 1 );
}
printf ( "\n\tLDAP session initialized\n");
/*
* Bind to the server anonymously
*/
if(( rc = ldap_simple_bind_s( ld, NULL, NULL )) != LDAP_SUCCESS )
{
printf("\n\tldap_simple_bind_s: %s\n", ldap_err2string( rc ));
ldap_unbind_s( ld );
return ( 1 );
}
printf("\n\tAnonymous bind successful\n");
ldap_unbind_s( ld );
/*
* Initialize a new LDAP session
*/
if (( ld = ldap_init( ldapHost, ldapPort )) == NULL)
{
printf ( "\n\tLDAP session initialization failed\n");
return( 1 );
}
printf ( "\n\tNew LDAP session initialized\n");
/*
* Simple bind to the server
*/
if ((rc = ldap_simple_bind_s( ld, loginDN, password )) != LDAP_SUCCESS )
{
printf("\n\tldap_simple_bind_s: %s\n", ldap_err2string( rc ));
ldap_unbind_s( ld );
return ( 1 );
}
printf("\n\tBind and authentication to the server successful\n");
ldap_unbind_s( ld );
return ( 0 );
}
II. Listage des informations
/* $Novell: list.c,v 1.7 2003/05/12 12:22:09 $ */
/**************************************************************************
* Novell Software Developer Kit
*
* Copyright (C) 2002-2003 Novell, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
* USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE AGREEMENT
* ACCOMPANYING THE SOFTWARE DEVELOPER KIT (SDK) THAT CONTAINS THIS WORK.
* PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS TO DEVELOPER A
* ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S SAMPLE CODE IN ITS
* PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION RIGHTS TO MARKET,
* DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT OF DEVELOPER'S
* PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR DEVELOPER'S
* CUSTOMERS WITH RESPECT TO THIS CODE.
*
***************************************************************************
list.c
***************************************************************************
Description: The list.c sample lists all objects in a container.
No attributes are read.
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <ldap.h>
#if defined(N_PLAT_NLM) && defined(LIBC)
#include <screen.h>
#endif
static char usage[] =
"\n Usage: list <host name> <port number> <login dn> <password>"
"\n <search base>\n"
"\n Example: list Acme.com 389 cn=admin,o=Acme secret ou=Sales,o=Acme\n";
int main( int argc, char **argv)
{
int version, ldapPort, rc;
char *ldapHost, *loginDN, *password, *searchBase;
char *dn;
LDAP *ld;
LDAPMessage *searchResult, *entry;
char *attrs[] = { LDAP_NO_ATTRS, NULL };
struct timeval timeOut = {10,0}; /* 10 second connection/search timeout */
#if defined(N_PLAT_NLM) && defined(LIBC)
setscreenmode(SCR_NO_MODE); /* Don't clear screen on exit */
#endif
if (argc != 6)
{
printf("%s", usage);
return (1);
}
ldapHost = argv[1];
ldapPort = atoi(argv[2]);
loginDN = argv[3];
password = argv[4];
searchBase = argv[5];
/* Set LDAP version to 3 and set connection timeout. */
version = LDAP_VERSION3;
ldap_set_option( NULL, LDAP_OPT_PROTOCOL_VERSION, &version);
ldap_set_option( NULL, LDAP_OPT_NETWORK_TIMEOUT, &timeOut);
/* Initialize the LDAP session */
if (( ld = ldap_init( ldapHost, ldapPort )) == NULL)
{
printf ( "\n LDAP session initialization failed\n");
return( 1 );
}
printf ( "\n LDAP session initialized\n");
/* Bind to the server */
rc = ldap_simple_bind_s( ld, loginDN, password );
if (rc != LDAP_SUCCESS )
{
printf("ldap_simple_bind_s: %s\n", ldap_err2string( rc ));
ldap_unbind_s ( ld );
return( 1 );
}
printf(" Bind successful\n\n");
/* Search the directory */
rc = ldap_search_ext_s(
ld, /* LDAP session handle */
searchBase, /* container to search */
LDAP_SCOPE_ONELEVEL, /* search scope */
"(objectclass=*)", /* search filter */
attrs, /* "1.1" returns entry names only*/
0, /* no attributes are returned */
NULL, /* server controls */
NULL, /* client controls */
&timeOut, /* search timeout */
LDAP_NO_LIMIT, /* no size limit */
&searchResult ); /* returned results */
if ( rc != LDAP_SUCCESS )
{
printf("ldap_search_ext_s: %s\n", ldap_err2string( rc ));
ldap_msgfree( searchResult );
ldap_unbind_s( ld );
return ( 1 );
}
/* Go through the search results by checking entries */
for ( entry = ldap_first_entry( ld, searchResult );
entry != NULL;
entry = ldap_next_entry( ld, entry ) )
{
if (( dn = ldap_get_dn( ld, entry )) != NULL )
{
printf(" dn: %s\n", dn );
ldap_memfree( dn );
}
}
ldap_msgfree( searchResult );
ldap_unbind_s( ld );
return( 0 );
}
III. Recherche
/* $Novell: search.c,v 1.14 2003/05/12 13:02:50 $ */
/**************************************************************************
* Novell Software Developer Kit
*
* Copyright (C) 2002-2003 Novell, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
* USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE AGREEMENT
* ACCOMPANYING THE SOFTWARE DEVELOPER KIT (SDK) THAT CONTAINS THIS WORK.
* PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS TO DEVELOPER A
* ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S SAMPLE CODE IN ITS
* PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION RIGHTS TO MARKET,
* DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT OF DEVELOPER'S
* PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR DEVELOPER'S
* CUSTOMERS WITH RESPECT TO THIS CODE.
*
***************************************************************************
search.c
***************************************************************************
Description: The search.c sample searches the directory, sorts the
results by the sn attribute, and prints the results.
Note: For simplicity, this sample prints all values as
if they were strings. See the searchBinary.c sample program
for an example of handling both string and binary values.
***************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ldap.h>
#if defined(N_PLAT_NLM) && defined(LIBC)
#include <screen.h>
#endif
static char usage[] =
"\n Usage: search <host name> <port number> <login dn> <password>"
"\n <search base>\n"
"\n Example: search Acme.com 389 cn=admin,o=Acme secret ou=Sales,o=Acme\n";
int main( int argc, char **argv )
{
int version, ldapPort, i, rc, entryCount;
char *ldapHost, *loginDN, *password, *searchBase;
char *attribute, *dn, **values, *sortAttribute = "sn";
BerElement *ber;
LDAP *ld;
LDAPMessage *searchResult, *entry;
struct timeval timeOut = {10,0}; /* 10 second connection/search timeout */
#if defined(N_PLAT_NLM) && defined(LIBC)
setscreenmode(SCR_NO_MODE); /* Don't clear screen on exit */
#endif
if (argc != 6)
{
printf("%s", usage);
return (1);
}
ldapHost = argv[1];
ldapPort = atoi(argv[2]);
loginDN = argv[3];
password = argv[4];
searchBase = argv[5];
/* Set LDAP version to 3 and set connection timeout. */
version = LDAP_VERSION3;
ldap_set_option( NULL, LDAP_OPT_PROTOCOL_VERSION, &version);
ldap_set_option( NULL, LDAP_OPT_NETWORK_TIMEOUT, &timeOut);
/* Initialize the LDAP session */
if (( ld = ldap_init( ldapHost, ldapPort )) == NULL)
{
printf ( "\n LDAP session initialization failed\n");
return( 1 );
}
printf ( "\n LDAP session initialized\n");
/* Bind to the server */
rc = ldap_simple_bind_s( ld, loginDN, password );
if (rc != LDAP_SUCCESS )
{
printf("ldap_simple_bind_s: %s\n", ldap_err2string( rc ));
ldap_unbind_s ( ld );
return( 1 );
}
printf("\n Bind successful\n");
/* Search the directory */
rc = ldap_search_ext_s(
ld, /* LDAP session handle */
searchBase, /* container to search */
LDAP_SCOPE_ONELEVEL, /* search scope */
"(objectclass=*)", /* search filter */
NULL, /* return all attributes */
0, /* return attributes and values */
NULL, /* server controls */
NULL, /* client controls */
&timeOut, /* search timeout */
LDAP_NO_LIMIT, /* no size limit */
&searchResult ); /* returned results */
if ( rc != LDAP_SUCCESS )
{
printf("ldap_search_ext_s: %s\n", ldap_err2string( rc ));
ldap_msgfree( searchResult );
ldap_unbind_s( ld );
return ( 1 );
}
/* client-sort */
ldap_sort_entries( ld, &searchResult, sortAttribute, strcmp );
/* Go through the search results by checking entries */
for ( entry = ldap_first_entry( ld, searchResult );
entry != NULL;
entry = ldap_next_entry( ld, entry ) )
{
if (( dn = ldap_get_dn( ld, entry )) != NULL )
{
printf("\n dn: %s\n", dn );
ldap_memfree( dn );
}
for ( attribute = ldap_first_attribute( ld, entry, &ber );
attribute != NULL;
attribute = ldap_next_attribute( ld, entry, ber ) )
{
/* Get values and print. Assumes all values are strings. */
if (( values = ldap_get_values( ld, entry, attribute)) != NULL )
{
for ( i = 0; values[i] != NULL; i++ )
printf(" %s: %s\n", attribute, values[i] );
ldap_value_free( values );
}
ldap_memfree( attribute );
}
ber_free(ber, 0);
}
entryCount = ldap_count_entries( ld, searchResult );
printf("\n Search completed successfully.\n Entries returned: %d\n",
entryCount);
ldap_msgfree( searchResult );
ldap_unbind_s( ld );
return( 0 );
}
IV. Recherche Asynchrone
/* $Novell: searchAsynch.c,v 1.8 2003/05/12 13:03:33 $ */
/**************************************************************************
* Novell Software Developer Kit
*
* Copyright (C) 2002-2003 Novell, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
* USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE AGREEMENT
* ACCOMPANYING THE SOFTWARE DEVELOPER KIT (SDK) THAT CONTAINS THIS WORK.
* PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS TO DEVELOPER A
* ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S SAMPLE CODE IN ITS
* PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION RIGHTS TO MARKET,
* DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT OF DEVELOPER'S
* PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR DEVELOPER'S
* CUSTOMERS WITH RESPECT TO THIS CODE.
*
***************************************************************************
searchAsynch.c
***************************************************************************
Description: This sample performs an asynchronous search operation,
reading and displaying entries as they are sent back
from the server.
Note: For simplicity, this sample prints all values as
if they were strings. See the searchBinary.c sample program
for an example of handling both string and binary values.
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <ldap.h>
#if defined(N_PLAT_NLM) && defined(LIBC)
#include <screen.h>
#endif
static char usage[] =
"\n Usage: searchAsynch <host name> <port number> <login dn> <password>"
"\n <search base>\n"
"\n Example: searchAsynch acme.com 389 cn=admin,o=acme secret"
"\n ou=Sales,o=Acme\n\n";
int main( int argc, char **argv)
{
int i, version, ldapPort, prc, messageID;
int rc, done = 0, entryCount = 0, errorCode;
char *ldapHost, *loginDN, *password, *searchBase,*attribute;
char *dn, *errorMessage = NULL, *matchedDN, **values;
LDAP *ld;
BerElement *ber;
LDAPMessage *searchResult, *entry;
struct timeval timeOut = {10,0}; /* 10 second connection/search timeout */
#if defined(N_PLAT_NLM) && defined(LIBC)
setscreenmode(SCR_NO_MODE); /* Don't clear screen on exit */
#endif
if (argc != 6)
{
printf("%s", usage);
return(1);
}
ldapHost = argv[1];
ldapPort = atoi(argv[2]);
loginDN = argv[3];
password = argv[4];
searchBase = argv[5];
/* Set LDAP version to 3 and set connection timeout. */
version = LDAP_VERSION3;
ldap_set_option( NULL, LDAP_OPT_PROTOCOL_VERSION, &version);
ldap_set_option( NULL, LDAP_OPT_NETWORK_TIMEOUT, &timeOut);
/* Initialize the LDAP session */
if (( ld = ldap_init( ldapHost, ldapPort )) == NULL)
{
printf ( "\n\tLDAP session initialization failed\n");
return( 1 );
}
printf ( "\n\tLDAP session initialized\n");
/* Bind to the server */
rc = ldap_simple_bind_s( ld, loginDN, password );
if (rc != LDAP_SUCCESS )
{
printf("ldap_simple_bind_s: %s\n", ldap_err2string( rc ));
ldap_unbind_s ( ld );
return( 1 );
}
printf("\n\tBind successful\n");
/* Perform the search operation. */
rc = ldap_search_ext( ld, /* LDAP session handle */
searchBase, /* container to search */
LDAP_SCOPE_ONELEVEL, /* search scope */
"(objectclass=*)", /* search filter */
NULL, /* return all attributes */
0, /* attributes and values */
NULL, /* server controls */
NULL, /* client controls */
&timeOut, /* search timeout */
LDAP_NO_LIMIT, /* no size limit */
&messageID ); /* ID of this operation */
if ( rc != LDAP_SUCCESS )
{
printf("\n\tldap_search_ext: %s\n", ldap_err2string( rc ) );
ldap_unbind_s( ld );
return( 1 );
}
printf("\n\tAsynchronous search initiated ... \n");
/* Poll the server for results */
while ( !done )
{
rc = ldap_result( ld, /* LDAP session handle */
LDAP_RES_ANY, /* any result is to be returned */
LDAP_MSG_ONE, /* one message at a time */
&timeOut, /* time out */
&searchResult );
switch ( rc )
{
case -1:
/* An error occur */
ldap_get_option( ld, LDAP_OPT_RESULT_CODE, &errorCode);
printf("\n\tldap_result: %s\n",
ldap_err2string( errorCode ) );
ldap_unbind_s( ld );
return( 1 );
case 0:
/* Time out */
printf("\n\tTimed out.");
ldap_unbind_s( ld );
return(1);
case LDAP_RES_SEARCH_ENTRY:
/* Its an entry, print out it's dn, attributes ans values */
entryCount++;
if (( dn = ldap_get_dn( ld, searchResult )) != NULL )
{
printf("\n\tdn: %s\n", dn );
ldap_memfree( dn );
}
entry = ldap_first_entry( ld, searchResult );
for ( attribute = ldap_first_attribute( ld,entry,&ber );
attribute != NULL;
attribute = ldap_next_attribute( ld, entry,ber))
{
/* Get values and print. Assumes all values are strings. */
if (( values = ldap_get_values( ld, entry, attribute))
!= NULL )
{
for ( i = 0; values[ i ] != NULL; i++ )
printf("\t\t%s: %s\n", attribute, values[ i ] );
ldap_value_free( values );
}
ldap_memfree( attribute );
}
ber_free(ber, 0);
ldap_msgfree( searchResult );
break;
/* It's the final result, check status and print it out */
case LDAP_RES_SEARCH_RESULT:
done = 1;
prc = ldap_parse_result(ld, /* LDAP session handle */
searchResult, /* search result */
&errorCode, /* error code */
&matchedDN, /* matched dn */
&errorMessage, /* error message */
NULL, /* referrals */
NULL, /* server controls */
1 ); /* free search result */
if ( prc != LDAP_SUCCESS )
printf("\n\tUnknown error");
else
printf("\n\tldap_search_ext: %s\n", ldap_err2string(errorCode));
if ( matchedDN != NULL && *matchedDN != 0)
{
printf("\n\tMatched dn: %s\n", matchedDN );
ldap_memfree( matchedDN );
}
break;
default:
printf("\n\tReturn code : %d\n", rc );
break;
}
/* Print a message while waiting. */
if ( !done )
printf("\n\tWaiting for the next search result ...\n");
}
printf("\n\tSearch completed.");
printf("\n\tEntries found: %d\n", entryCount);
ldap_memfree( matchedDN );
ldap_memfree( errorMessage );
ldap_unbind_s( ld );
return( 0 );
}
API Java : Les Classes
JNDI
La librairie JNDI offre un accès aux annuaires LDAP.
La liste des classes et la documentation sont disponible sur le site de sun.
Voici la liste des principales classes utiles:
- DirContext , InitialDirContext
- SearchControls , SearchResult
- Attributes
- NamingEnumeration
- ...
API Java : Les Exemples
I. Configuration
package st.fr.cuellar.ldaptest;
public class Env {
/*
* Contexte inital
*/
public final static String INITCTX = "com.sun.jndi.ldap.LdapCtxFactory";
/*
* Machine + port du serveur LDAP
*/
public final static String HOST = "ldap://donald.duc.auburn.ed:389";
}
II. Connexion
package st.fr.cuellar.ldaptest;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
public class Bind {
public static void main(String [] args){
// Configuration Contexte + serveur + port
Hashtable env = new Hashtable(5, 0.75f);
env.put(Context.INITIAL_CONTEXT_FACTORY, Env.INITCTX);
env.put(Context.PROVIDER_URL, Env.HOST);
try {
// Initialisation du contexte et connexion au serveur
DirContext ctx = new InitialDirContext(env);
} catch (NamingException e) {
System.out.println("Connexion impossible");
e.printStackTrace();
}
System.out.println("Connexion reussi");
}
}
III. Recherche
package st.fr.cuellar.ldaptest;
import java.util.Enumeration;
import java.util.Hashtable;
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;
public class Search {
public static void main(String [] args){
// Configuration Contexte + serveur + port
Hashtable env = new Hashtable(5, 0.75f);
env.put(Context.INITIAL_CONTEXT_FACTORY, Env.INITCTX);
env.put(Context.PROVIDER_URL, Env.HOST);
try {
// Initialisation du contexte et connexion au serveur
DirContext ctx = new InitialDirContext(env);
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration results = ctx.search("o=univ-mlv, c=fr","(uid=gcuellar)", constraints);
while (results != null && results.hasMore()) {
SearchResult si = (SearchResult)results.next();
System.out.println("name: " + si.getName());
Attributes attrs = si.getAttributes();
if (attrs == null) {
System.out.println("No attributes");
} else {
for (NamingEnumeration ae = attrs.getAll();
ae.hasMoreElements();) {
Attribute attr = (Attribute)ae.next();
String attrId = attr.getID();
for (Enumeration vals = attr.getAll();
vals.hasMoreElements();
System.out.println(attrId + ": " + vals.nextElement()))
;
}
}
System.out.println();
}
} catch (NamingException e) {
e.printStackTrace();
}
}
}
IV. Comparaison
package st.fr.cuellar.ldaptest;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
public class Compare {
public static void main(String [] args){
// Configuration Contexte + serveur + port
Hashtable env = new Hashtable(5, 0.75f);
env.put(Context.INITIAL_CONTEXT_FACTORY, Env.INITCTX);
env.put(Context.PROVIDER_URL, Env.HOST);
SearchControls ctls = new SearchControls();
ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
ctls.setReturningAttributes(new String[0]);
try {
// Initialisation du contexte et connexion au serveur
DirContext ctx = new InitialDirContext(env);
// Recherche
NamingEnumeration results =ctx.search("cn=gcuellar, ou=Group, o=univ-mlv, c=fr", "objectclass=person", ctls);
if (results != null && results.hasMoreElements()) {
System.out.println("The value \"person\" is contained in the objectclass attribute.");
} else {
System.out.println("The value \"person\" is not contained in the objectclass attribute." );
}
} catch (NamingException e) {
e.printStackTrace();
}
}
}
V. Lecture des attributs
package st.fr.cuellar.ldaptest;
import java.util.Hashtable;
import javax.naming.*;
import javax.naming.directory.*;
public class ReadEntry {
public static void main(String [] args){
// Configuration Contexte + serveur + port
Hashtable env = new Hashtable(5, 0.75f);
env.put(Context.INITIAL_CONTEXT_FACTORY, Env.INITCTX);
env.put(Context.PROVIDER_URL, Env.HOST);
try {
// Initialisation du contexte et connexion au serveur
DirContext ctx = new InitialDirContext(env);
// Recuperation des attributs
Attributes attrs = ctx.getAttributes("cn=gcuellar, ou=Group, o=univ-mlv, c=fr");
if (attrs == null) {
System.out.println("cn=gcuellar, ou=Group, o=univ-mlv, c=fr" + "has no attributes");
} else {
// Parcours des attributs
for (NamingEnumeration ae = attrs.getAll();ae.hasMoreElements();) {
Attribute attr = (Attribute)ae.next();
String attrId = attr.getID();
// Parcours des valeurs
for (NamingEnumeration vals = attr.getAll();
vals.hasMoreElements();
System.out.println(attrId + ": " + vals.nextElement()))
;
}
}
} catch (NamingException e) {
e.printStackTrace();
}
}
}