Simplifiez l'accès aux répertoires avec Spring LDAP

Spring LDAP est un framework basé sur Spring qui simplifie la programmation LDAP sur la plate-forme Java. Dans ce guide étape par étape d'utilisation de Spring LDAP, vous apprendrez comment le framework gère le codage de bas niveau requis par la plupart des clients LDAP, afin que vous puissiez vous concentrer sur le développement de la logique métier de votre application. Vous pratiquerez également des opérations CRUD simples à l'aide de Spring LDAP et découvrirez des opérations plus avancées telles que la création de filtres dynamiques et la conversion d'entrées LDAP en beans Java.

Le protocole Lightweight Directory Access Protocol est aujourd'hui un composant essentiel de la plupart des déploiements d'applications d'entreprise à grande échelle. LDAP est principalement utilisé pour stocker des informations relatives à l'identité de l'utilisateur, telles que le nom d'utilisateur, le mot de passe et l'adresse e-mail d'un utilisateur. Il est également utilisé dans les implémentations de sécurité où il est nécessaire de stocker les droits d'accès des utilisateurs à des fins d'authentification et d'autorisation.

Java Naming and Directory Interface (JDNI) est l'API utilisée pour la programmation LDAP sur la plate-forme Java. Il définit une interface standard qui peut être utilisée dans votre application pour interagir avec n'importe quel serveur LDAP. Malheureusement, l'utilisation de JNDI implique généralement d'écrire beaucoup de code répétitif de bas niveau. JNDI fait beaucoup trop de travail avec des procédures simples, comme s'assurer que les ressources ont été correctement ouvertes et fermées. De plus, la plupart des méthodes JNDI lancent des exceptions vérifiées, qui prennent du temps à gérer. Après une inspection minutieuse, il semble que 50 à 60 pour cent du temps passé à programmer JNDI est gaspillé à gérer des tâches répétitives.

Spring LDAP est une bibliothèque Java open source conçue pour simplifier la programmation LDAP sur la plate-forme Java. Tout comme Spring Framework élimine une grande partie de la programmation de bas niveau du développement d'applications d'entreprise Java, Spring LDAP vous libère des détails d'infrastructure liés à l'utilisation de LDAP. Plutôt que de vous soucier des NamingExceptions et d'obtenir des InitialContexts, vous êtes libre de vous concentrer sur la logique métier de votre application. Spring LDAP définit également une hiérarchie d'exceptions non vérifiée complète et fournit des classes d'assistance pour la création de filtres LDAP et de noms distinctifs.

Spring LDAP et JNDI

Notez que le framework Spring LDAP ne remplace pas JNDI. Il fournit plutôt des classes wrapper et utilitaires sur JNDI pour simplifier la programmation LDAP sur la plate-forme Java.

Dans cet article, un guide du débutant sur l'utilisation de Spring LDAP, je commencerai par développer un programme JNDI simple pour exécuter une recherche LDAP. Je vais ensuite montrer à quel point il est plus facile de faire la même chose en utilisant le framework Spring LDAP. Je vais vous montrer comment utiliser les Spring LDAP AttributeMapperpour mapper des attributs LDAP sur des beans Java et comment utiliser ses filtres dynamiques pour créer des requêtes. Enfin, je vais vous fournir une introduction étape par étape à l'utilisation du framework Spring LDAP pour ajouter, supprimer et modifier des données dans votre serveur LDAP.

Notez que cet article suppose que vous connaissez les concepts et la terminologie de Spring Framework. Consultez la section Ressources pour en savoir plus sur Spring Framework, LDAP et JNDI ainsi que pour télécharger l'exemple d'application.

Un client JNDI simple

Le listing 1 montre un programme JNDI simple qui imprimera les attributs cn de tous les Personobjets de type sur votre console.

Liste 1. SimpleLDAPClient.java

public class SimpleLDAPClient { public static void main(String[] args) { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://localhost:10389/ou=system"); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system"); env.put(Context.SECURITY_CREDENTIALS, "secret"); DirContext ctx = null; NamingEnumeration results = null; try { ctx = new InitialDirContext(env); SearchControls controls = new SearchControls(); controls.setSearchScope(SearchControls.SUBTREE_SCOPE); results = ctx.search("", "(objectclass=person)", controls); while (results.hasMore()) { SearchResult searchResult = (SearchResult) results.next(); Attributes attributes = searchResult.getAttributes(); Attribute attr = attributes.get("cn"); String cn = (String) attr.get(); System.out.println(" Person Common Name = " + cn); } } catch (NamingException e) { throw new RuntimeException(e); } finally { if (results != null) { try { results.close(); } catch (Exception e) { } } if (ctx != null) { try { ctx.close(); } catch (Exception e) { } } } } }

La première chose que j'ai faite dans le listing 1 est de créer un InitialDirContextobjet, qui est ensuite utilisé comme contexte pour les opérations d'annuaire suivantes. Lors de la création d'un nouvel Contextobjet, je configure des propriétés telles que le nom d'utilisateur, le mot de passe et le mécanisme d'authentification qui peuvent être utilisés pour se connecter au serveur LDAP. J'ai réussi cela en créant un Hashtableobjet, en configurant toutes ces propriétés en tant que paires clé / valeur dans le Hashtableet en passant le Hashtableau InitialDirContextconstructeur.

Le problème immédiat avec cette approche est que j'ai codé en dur tous les paramètres de configuration dans un fichier .java. Cela fonctionne bien pour mon exemple, mais pas pour une application réelle. Dans une application du monde réel, je voudrais stocker les propriétés de connexion dans un fichier jndi.properties et placer ce fichier dans le chemin de classe de mon projet ou dans son dossier / lib. Lors de la création d'un nouvel InitialDirContextobjet, l'API JNDI recherchait dans ces deux endroits le fichier jndi.properties, puis l'utilisait pour créer une connexion au serveur LDAP.

Paramètres de configuration JNDI

Le listing 2 montre les paramètres de configuration JNDI pour la connexion à mon serveur LDAP. J'explique la signification des paramètres ci-dessous.

Listing 2. Paramètres de configuration JNDI pour LDAP

java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory java.naming.provider.url=ldap://localhost:10389/ou=system java.naming.security.authentication=simple java.naming.security.principal=uid=admin,ou=system java.naming.security.credentials=secret
  1. Context.INITIAL_CONTEXT_FACTORY ( java.naming.factory.initial) doit être égal au nom de classe pleinement qualifié qui sera utilisé pour créer un nouveau contexte initial. Si aucune valeur n'est spécifiée, le NoInitialContextExceptionest renvoyé.
  2. Context.PROVIDER_URL ( java.naming.provider.url) doit être égal à l'URL du serveur LDAP auquel vous souhaitez vous connecter. Il devrait être au format ldap://:.
  3. Context.SECURITY_AUTHENTICATION ( java.naming.security.authentication) représente le type de mécanisme d'authentification que vous souhaitez utiliser. J'ai utilisé un nom d'utilisateur et un mot de passe pour l'authentification dans mon exemple, donc la valeur de cette propriété est simple .
  4. Context.SECURITY_PRINCIPAL ( java.naming.security.principal) représente le nom d'utilisateur distinctif (DN) qui doit être utilisé pour établir une connexion.
  5. Context.SECURITY_CREDENTIALS ( java.naming.security.credentials) représente le mot de passe de l'utilisateur.

Le code client JNDI

Après avoir obtenu l' Contextobjet, ma prochaine étape consiste à créer un SearchControlobjet, qui encapsule les facteurs qui déterminent la portée de ma recherche et ce qui sera retourné. Je veux rechercher l'ensemble du sous-arbre enraciné dans le contexte, donc j'ai défini la portée de la recherche SUBTREE_SCOPEen appelant la setSearchScope()méthode de SearchControl, comme indiqué précédemment dans la liste 1.

Ensuite, j'appelle la search()méthode de DirContext, en passant (objectclass=person)comme valeur du filtre. La search()méthode retournera un NamingEnumerationobjet contenant toutes les entrées du sous-arbre de Context, où objectclassest égal à person. Après avoir obtenu un NamingEnumerationobjet comme résultat, je l'itère et j'imprime un attribut cn pour chaque Personobjet.

Cela termine mon explication du code client JNDI. En regardant SimpleLDAPClient.java, montré dans le listing 1, vous pouvez facilement voir que plus de la moitié du code sert à ouvrir et fermer des ressources. Un autre problème avec l'API JNDI est que la plupart de ses méthodes lèveront une NamingExceptionou une de ses sous-classes en cas d'erreur. Comme il NamingExceptions'agit d'une exception vérifiée, vous devez la gérer si elle est levée, mais pouvez-vous vraiment récupérer d'une exception si votre serveur LDAP est en panne? Non, tu ne peux pas.

La plupart des développeurs contournent les JNDI NamingExceptionen les attrapant simplement et en ne faisant rien. Le problème avec cette solution est qu'elle peut vous faire perdre des informations importantes.