Semplifica l'accesso alle directory con Spring LDAP

Spring LDAP è un framework basato su Spring che semplifica la programmazione LDAP sulla piattaforma Java. In questa guida passo passo all'uso di Spring LDAP imparerai come il framework gestisce la codifica di basso livello richiesta dalla maggior parte dei client LDAP, in modo che tu possa concentrarti sullo sviluppo della logica di business della tua applicazione. Potrai anche esercitarti con semplici operazioni CRUD utilizzando Spring LDAP e apprendere operazioni più avanzate come la creazione di filtri dinamici e la conversione di voci LDAP in Java bean.

Il Lightweight Directory Access Protocol è oggi un componente essenziale della maggior parte delle distribuzioni di applicazioni aziendali su larga scala. LDAP viene utilizzato principalmente per memorizzare le informazioni relative all'identità dell'utente, come il nome utente, la password e l'indirizzo e-mail di un utente. Viene anche utilizzato nelle implementazioni di sicurezza in cui è necessario memorizzare i diritti di accesso dell'utente per scopi di autenticazione e autorizzazione.

Java Naming and Directory Interface (JDNI) è l'API utilizzata per la programmazione LDAP sulla piattaforma Java. Definisce un'interfaccia standard che può essere utilizzata all'interno dell'applicazione per interagire con qualsiasi server LDAP. Sfortunatamente, l'utilizzo di JNDI in genere comporta la scrittura di molto codice ripetitivo e di basso livello. JNDI fa fin troppo lavoro di procedure semplici, come garantire che le risorse siano state aperte e chiuse correttamente. Inoltre, la maggior parte dei metodi JNDI genera eccezioni controllate, che richiedono molto tempo per essere gestite. Dopo un'attenta ispezione, sembra che dal 50 al 60 percento del tempo speso per programmare JNDI venga sprecato per la gestione di attività ripetitive.

Spring LDAP è una libreria Java open source progettata per semplificare la programmazione LDAP sulla piattaforma Java. Proprio come Spring Framework elimina gran parte della programmazione di basso livello dallo sviluppo di applicazioni aziendali Java, Spring LDAP ti libera dai dettagli infrastrutturali dell'utilizzo di LDAP. Invece di preoccuparti di se NamingExceptionricevere messaggi InitialContext, sei libero di concentrarti sulla logica di business della tua applicazione. Spring LDAP definisce anche una gerarchia di eccezioni non controllata completa e fornisce classi di supporto per la creazione di filtri LDAP e nomi distinti.

Spring LDAP e JNDI

Notare che il framework Spring LDAP non sostituisce JNDI. Piuttosto, fornisce wrapper e classi di utilità su JNDI per semplificare la programmazione LDAP sulla piattaforma Java.

In questo articolo, una guida per principianti all'uso di Spring LDAP, inizierò sviluppando un semplice programma JNDI per eseguire una ricerca LDAP. Dimostrerò quindi quanto sia più facile fare la stessa cosa usando il framework Spring LDAP. Ti mostrerò come utilizzare Spring LDAP AttributeMapperper mappare gli attributi LDAP ai bean Java e come utilizzare i suoi filtri dinamici per creare query. Infine, fornirò un'introduzione passo passo all'uso del framework Spring LDAP per aggiungere, eliminare e modificare i dati nel server LDAP.

Nota che questo articolo presume che tu abbia familiarità con i concetti e la terminologia di Spring Framework. Vedere la sezione Risorse per ulteriori informazioni su Spring Framework, LDAP e JNDI, nonché per scaricare l'applicazione di esempio.

Un semplice client JNDI

Il Listato 1 mostra un semplice programma JNDI che stamperà gli attributi cn di tutti gli Personoggetti di tipo sulla tua console.

Listato 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 prima cosa che ho fatto nel Listato 1 è creare un InitialDirContextoggetto, che viene quindi utilizzato come contesto per le seguenti operazioni sulle directory. Quando creo un nuovo Contextoggetto configuro proprietà come nome utente, password e meccanismo di autenticazione che possono essere utilizzati per connettersi al server LDAP. L'ho gestito creando un Hashtableoggetto, impostando tutte queste proprietà come coppie chiave / valore in Hashtablee passando il Hashtableal InitialDirContextcostruttore.

Il problema immediato con questo approccio è che ho codificato tutti i parametri di configurazione in un file .java. Funziona bene per il mio esempio, ma non per un'applicazione del mondo reale. In un'applicazione del mondo reale vorrei memorizzare le proprietà di connessione in un file jndi.properties e posizionare quel file nel classpath del mio progetto o nella sua cartella / lib. Dopo la creazione di un nuovo InitialDirContextoggetto, l'API JNDI cercherà in entrambe queste posizioni il file jndi.properties, quindi lo utilizzerà per creare una connessione al server LDAP.

Parametri di configurazione JNDI

Il Listato 2 mostra i parametri di configurazione JNDI per la connessione al mio server LDAP. Spiego il significato dei parametri di seguito.

Listato 2. Parametri di configurazione JNDI per 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) dovrebbe essere uguale al nome completo della classe che verrà utilizzato per creare un nuovo contesto iniziale. Se non viene specificato alcun valore, NoInitialContextExceptionviene generato il.
  2. Context.PROVIDER_URL ( java.naming.provider.url) dovrebbe essere uguale all'URL del server LDAP a cui desideri connetterti. Dovrebbe essere nel formato ldap://:.
  3. Context.SECURITY_AUTHENTICATION ( java.naming.security.authentication) rappresenta il tipo di meccanismo di autenticazione che desideri utilizzare. Ho usato un nome utente e una password per l'autenticazione nel mio esempio, quindi il valore di questa proprietà è semplice .
  4. Context.SECURITY_PRINCIPAL ( java.naming.security.principal) rappresenta il nome utente distinto (DN) da utilizzare per stabilire una connessione.
  5. Context.SECURITY_CREDENTIALS ( java.naming.security.credentials) rappresenta la password dell'utente.

Il codice client JNDI

Dopo aver ottenuto l' Contextoggetto, il passo successivo è creare un SearchControloggetto, che incapsuli i fattori che determinano l'ambito della mia ricerca e cosa verrà restituito. Voglio cercare l'intera sottostruttura radicata nel contesto, quindi ho impostato l'ambito di ricerca SUBTREE_SCOPEchiamando il setSearchScope()metodo di SearchControl, come mostrato in precedenza nel Listato 1.

Successivamente, chiamo il search()metodo di DirContext, passando (objectclass=person)come valore del filtro. Il search()metodo restituirà un NamingEnumerationoggetto contenente tutte le voci nella sottostruttura di Context, dove objectclassè uguale a person. Dopo aver ottenuto un NamingEnumerationoggetto come risultato, lo itero e stampo un attributo cn per ogni Personoggetto.

Questo completa la mia spiegazione del codice client JNDI. Guardando SimpleLDAPClient.java, mostrato nel Listato 1, puoi facilmente vedere che più della metà del codice serve per l'apertura e la chiusura delle risorse. Un altro problema con l'API JNDI è che la maggior parte dei suoi metodi lancerà una NamingExceptiono una delle sue sottoclassi in caso di errore. Poiché NamingExceptionè un'eccezione controllata, devi gestirla se viene lanciata, ma puoi davvero recuperare da un'eccezione se il tuo server LDAP è inattivo? No, non puoi.

La maggior parte degli sviluppatori aggira i JNDI NamingExceptionsemplicemente catturandoli e non facendo nulla. Il problema con questa soluzione è che può farti perdere informazioni importanti.