Tomcat e OpenLDAP, dalla configurazione all’applicazione
In questo articolo di Darren Duke vediamo come poter utilizzare OpenLDAP insieme al container Tomcat. Viene anche fornito il codice d’esempio per poter utilizzare subito OpenLDAP nella nostra webapplication.
Introduzione
Quasi tutte le applicazioni web Java richiedono un certo tipo di accesso sicuro e ciò solitamente avviene tramite una directory Lightweight Directory Access Protocol (LDAP). Come sviluppatore, è conveniente avere una directory locale OpenLDAP e un web container per aumentare la produttività.
La configurazione di Tomcat per collegarlo ad una directory di OpenLDAP è relativamente semplice se viene compreso il metodo. Questo articolo dettaglia questo processo ed esamina il progetto Apache Jakarta (taglib) per mostrare una maniera facile per verificare i meccanismi di sicurezza.
Che cosa è LDAP?
LDAP è molte cose per molta gente. Per gli scopi di questo articolo, è semplicemente un protocollo comune per permettere che un utente sia autenticato via un contrassegno e una parola d’accesso. Cioè fornisce l’autenticazione. Inoltre permette che un utente sia autorizzato per l’accesso a specifiche aree dell’applicazione. Questo è un classico processo di autorizzazione.
C’è una chiara distinzione fra l’autenticazione e l’autorizzazione. Non sono la stessa cosa. Le directory di LDAP sono, in teoria, intercambiabili. Tuttavia, ci sono dei cambiamenti di configurazione da considerare. Una directory di LDAP è organizzata in una gerarchia ad albero che consiste di alcuni dei seguenti livelli:
- La radice (dell’albero)
- Paesi
- Organizzazioni
- Unità organizzative (divisioni, reparti, zone, ecc)
- Individui.
Si possono importare ed esportare directory LDAP attraverso il formato di file Lightweight Directory Interchange Format (LDIF). LDIF è un formato di file testuale che può essere usato per scambiare le informazioni fra le directory LDAP, o per questo caso, per configurare inizialmente una directory. Vista la sua natura opensource, OpenLDAP viene scelto come directory server da molti sviluppatori.
Setup e configurazione di OpenLDAP
Dopo aver scaricato e installato OpenLDAP , il file slapd.conf che si trova nella directory dell’installazione richiede alcuni cambiamenti piuttosto importanti. Si comincia includendo lo schema di InetOrgPerson. Questo schema ha molti attributi utili predefiniti per gli utenti della rete, compreso l’attributo del uid per l’identificazione specifica di inizio attività dell’utente.
ucdata-path C:/openldap/ucdata include C:/openldap/etc/schema/core.schema include C:/openldap/etc/schema/cosine.schema include C:/openldap/etc/schema/inetorgperson.schema ......... snip ....... database bdb suffix dc="mycompany",dc="com" rootdn "cn=Manager,dc=mycompany,dc=com" rootpw secret directory C:/openldap/var/openldap-data index objectClass eq
Come viene riportato, bisogna dire a OpenLDAP quale tipo di database deve usare e quali sono username e password. Una volta che tutti i cambiamenti sono stati fatti al file slapd.conf, è tempo di far partire OpenLDAP. Aprite un prompt dei comandi e andate nella directory dell’installazione (c:\openldap di default). Lanciate il comando
.slapd -d 1
e il server dovrebbe partire come in figura
Se viene riportato un errore e il server riesce a partire, controllate che le entry dello schema (sopra) siano state aggiunte al file slapd.conf. Inoltre, se OpenLDAP non fosse installato nella directory di default, bisogna verificare che i percorsi siano corretti. Una volta che il server sta funzionando, possiamo verificare l’installazione. Apriamo un altro prompt dei comandi e lanciamo il comando
ldapsearch -x -b "dc=mycompany, dc=com" "(objectclass =*)"
Quello che ci viene restituito dovebbre somigliare a quello che vedete in figura 2.
Per popolare la directory sarà importato un file LDIF. Il formato non è molto semplice, proprio per questo c’è un file LDIF disponibile per il download. Per importare il file bisogna usare un prompt dei comandi ed eseguire
ldapadd -x -D "cn=Manager,dc=mycompany,dc=com" -W -f setup.ldif
e vi dovrebbe essere richiesta la vostra parola d’accesso, come configurato nel file di slapd.conf. Una volta che la parola d’accesso è stata digitata, i risultati dovrebbero essere uguali a quelli di figura 3
Tutto ciò è molto gradevole, ma che cosa abbiamo fatto??? Bene, il comando ldapadd ha aggiunto due unità organizzative (la gente e ruoli), tre ruoli dell’utente (sotto i ruoli OU) e tre utenti (sotto le persone OU).
Questi utenti inoltre sono stati assegnati a ruoli differenti. Segue quindi la gerarchia che è generata importando l’LDIF :
- com
-
- mycompany
-
- people
-
- admin
- jbloggs
- sspecial
- roles
-
- Admin Users
-
- uid=admin/ou=people/…
- Special Users
-
- uid=sspecial/ou=people/…
- Test Users
-
- uid=sspecial/ou=people/…
- uid=jbloggs/ou=people/…
- uid=admin/ou=people/…
Se ora effettuiamo la ricerca precedente con il comando ldapsearch l’output dovrebbero contenere una descrizione più espressiva (come gli attributi dell’utente e gli insiemi dei membri di ruolo).
Tutti questi comandi dal prompt sono sufficienti, ma può aiutare anche un browser LDAP Java Swing opensource chiamato JXplorer.
JXplorer: Visual LDAP
JXplorer è un LDAP browser. Può essere usato per vedere, aggiungere, cambiare e cancellare ogni elemento o attributo dentro la directory LDAP. Può essere anche usato per cambiare le password, se necessario. Installate JXplorer e fate partire il comando jxplorer.bat o jxplorer.sh (Windows o Linux).
Una volta che è stato avviato, connettetevi alla vostra directory locale di OpenLDAP usando username e password di root, come mostrato in Figura 4
JXplorer può essere usato per navigare dentro la directory e cambiare ogni valore. Fate attenzione quando cambiate gli attributi dell’utente, almeno fino a quando non avete preso confidenza con LDAP. Guardate la figura 5 per un esempio
Configurazione di Tomcat per OpenLDAP
La specifica 2.3 delle Servlet permette che un application server usi la sicurezza gestita dal container, collegandosi ad un repository di utenti per l’autenticazione e l’autorizzazione. Tuttavia non esiste una maniera standard di fare ciò fra container diversi. Ogni container può implementare (e solitamente lo fa) la sicurezza in una maniera differente.
Tomcat usa la nozione di Realm (regno) per questo tipo di sicurezza. Un Realm può essere descritto come “deposito” dei nomi e delle parole d’accesso dell’utente che identifica univocamente gli utenti validi per una web application. Ci sono quattro tipologie di Realm in Tomcat 4 ed ogni tipo immagazzina e richiama i dati e le parole d’accesso dell’utente in un tipo differente di repository.
- JDBCRealm usa una base di dati relazionale.
- DataSourceRealm usa una base di dati relazionale attraverso un collegamento JNDI
- JNDIRealm usa un collegamento JNDI, solitamente una directory LDAP
- MemoryRealm usa un file in memoria, solitamente tomcat-users.xml
Il Realm di default di Tomcat è MemoryRealm, che è configurato con il file tomcat-users.xml. Tomcat deve essere configurato affinchè un JNDIRealm permetta l’autenticazione attraverso una directory LDAP. Ci sono diversi passi necessari per configurare Tomcat con JNDIRealm.
- Creare il Realm nel file server.xml
- Creare una form di login JSP
- Setup della protezione delle risorse nel file web.xml
- Setup della form di login nel file web.xml
- Setup di tutti i mapping nel file web.xml
Configurazione Server Tomcat
Ogni applicazione può avere il setup del Realm all’interno del proprio tag <Context>; in questo modo il Realm è disponibile solo a quella applicazione. Tuttavia il Realm può essere anche settato a livello di <Engine> o di <Host>. Ognuno di questi diversi settaggi ha un impatto sui comportamenti e finalità del Realm. Questo permette una facile condivisione del Realm con diverse applicazioni.
Qui di seguito trovate un server.xml di un Realm che permetterà ad un applicazione di connettersi a OpenLDAP.
<Realm className="org.apache.catalina.realm.JNDIRealm" debug="99" connectionName="cn=Manager,dc=mycompany,dc=com" connectionPassword="secret" connectionURL="ldap://localhost:389" roleBase="ou=roles,dc=mycompany,dc=com" roleName="cn" roleSearch="(uniqueMember={0})" roleSubtree="false" userSearch="(uid={0})" userPassword="userPassword" userPattern="uid={0},ou=people,dc=mycompany,dc=com" />
I valori degli attributi userSearch e userPattern sono il punto di maggior confusione e d’errore quando si configura un LDAP in questo modo. Prestate particolare attenzione a questi attributi se state usando qualcosa al di fuori di OpenLDAP.
Configurazione della Web Application
Per completare la configurazione di OpenLDAP per Tomcat deve essere aggiornato il file web.xml. L’applicazione che potete scaricare (link alla fine dell’articolo) consiste di 6 pagine JSP, 3 delle quali sono protette per i vari ruoli configurati nella directory LDAP.
L’applicazione deve essere configurata per permettere un autenticazione form-based e deve conoscere quali ruoli esistono. Quando usate l’autenticazione form-based la JSP di login potrebbe essere come quella riportata nel seguente codice
<body> <form method="POST" action="j_security_check"> <input type="text" name="j_username"> <br> <input type="password" name="j_password"> <br> <input type="submit"> </form> </body>
Il file web.xml ha bisogno di essere aggiornato per riferirsi al nuovo Realm OpenLDAP e per utilizzare i ruoli configurati in esso. L’applicazione ha bisogno di permettere un accesso pubblico alla pagina login.jsp, altrimenti nessun utente potrebbe mai loggarsi.
Per informare l’applicazione per quanto riguarda le risorse che possono essere accedute in base ai ruoli vengono usati dei semplici URL mapping (o vincoli di sicurezza). Questi mapping possono essere sia un nome di file (/admin.jsp) o un path (/jsp/* proteggerà ogni cosa nella cartella jsp).
Il seguente XML indica che entrambi i file .jsp non devono essere protetti
<security-constraint> <web-resource-collection> <web-resource-name>Public Area</web-resource-name> <!-- Define the context-relative URL(s) to be protected --> <url-pattern>/index.jsp</url-pattern> <url-pattern>/login.jsp</url-pattern> </web-resource-collection> </security-constraint>
In che modo questo codice segnala che le pagine non sono protette? Ciò è dovuto a qualcosa che manca, visto che se non viene riportato un ruolo nel tag security-coinstraint, le risorse elencate sono disponibili per qualsiasi utente.
Lo snippet di web.xml qui sotto indica invece che la risorsa user.jsp è protetta e quali ruoli possono visualizzarla
<security-constraint> <web-resource-collection> <web-resource-name>Protected Area</web-resource-name> <!-- Define the context-relative URL(s) to be protected --> <url-pattern>/user.jsp</url-pattern> </web-resource-collection> <auth-constraint> <!-- Anyone with one of the listed roles may access this area --> <role-name>Test Users</role-name> <role-name>Special Users</role-name> <role-name>Admin Users</role-name> </auth-constraint> </security-constraint>
La risorsa protetta ha un’altra sezione, che specifica quali ruoli di applicazione possono accedere alla risorsa. Se è presente, le risorse sono sicure. Se non è presente, sono pubblici. A meno che l’intera applicazione sia protetta (cioè,/), il vincolo pubblico di sicurezza è ridondante.
Per configurare il file web.xml, per abilitare l’accesso pubblico al file login.jsp , aggiungete quanto segue al file web.xml
<!-- uses form-based authentication --> <login-config> <auth-method>FORM</auth-method> <form-login-config> <form-login-page>/login.jsp</form-login-page> <form-error-page>/fail_login.html</form-error-page> </form-login-config> </login-config>
Rimane un altro cosa da fare su web.xml: l’applicazione ha bisogno di sapere quali ruoli si stanno usando
<!-- Security roles referenced by this web application --> <security-role> <role-name>Test Users</role-name> </security-role> <security-role> <role-name>Special Users</role-name> </security-role> <security-role> <role-name>Admin Users</role-name> </security-role>
Tomcat ora è stato configurato per usare OpenLDAP e la nostra applicazione è stata configurata correttamente nel web.xml.
La prima volta che un utente naviga su una risorsa elencata nel <security-constraint> (tranne quelle pubbliche), il server visualizzerà automaticamente il login.jsp affinchè l’utente si autentichi. Se l’utente non riesce ad autenticarsi con successo, la pagina specificata nel tag <form-error-page> verrà visualizzata.
Se un utente è autenticato con successo, ma non è autorizzato per l’accesso alla risorsa (se non fa parte ad esempio di un ruolo specifico), il server restituisce una pagina d’errore HTTP 403. Le pagine d’errore possono essere gestite nel web.xml, usando l’elemento <error-code>.
Si noti che il web.xml ha un ordine specifico per gli elementi (definiti da un DTD), dovreste dare un’occhiata al web.xml completo disponibile nel codice dell’esempio (nella sezione delle risorse alla fine dell’articolo). Ciò è particolarmente vero per le sezioni <login-config> e <security-role>.
Un utente può ora entrare, ma cosa possiamo fare quando un utente effettua il logout? Il codice potrebbe essere scritto per invalidare la sessione degli utenti, o potremmo usare la taglib per la sessione fornita da Apache Jakarta.
Jakarta TagLibs
Aggiungendo logout.jsp all’applicazione e usando la taglib session di Jakarta, possiamo invalidare il nostro utente senza il bisogno di nessun codice particolare (in un’applicazione del mondo reale voi potreste aver bisogno di una maggiore pulizia delle sessioni utente, in questo caso questo codice potrebbe non bastare).
<body> <sess:invalidate/> You are now logged out<br> <a href="index.jsp">Return to index</a> </body>
Una volta che la pagina JSP con il tag è stata visualizzata, la sessione dell’utente è stata rimossa e l’utente si è effettivamente sloggato. Mettere un link alla pagina logout.jsp è sufficiente per questa semplice applicazione.
Oltre alla taglib session, possiamo anche utilizzare la taglib request per customizzare il contenuto della JSP, basandola
sul ruolo/i dell’utente.
<req:isUserInRole role="Admin Users"> The remote user is in role "Admin Users".<br /> </req:isUserInRole>
In questo caso verrà visualizzato il testo contenuto nel tag, soltanto se l’utente ha il ruolo riportato. Per verificare il comportamento del ruolo di sicurezza, JXplorer può essere usato per aggiungere e rimuovere velocemente utenti dai ruoli.
Conclusione
Avere una directory LDAP su una macchina locale può essere una risorsa preziosa per uno sviluppatore. Non c’è più bisogno di richiedere qualcosa per l’accesso agli amministratori della rete, o per creare degli account di test per la vostra applicazione.
Tutte queste cose possono essere fatte in pochi secondi invece che giorni o settimane. Questo non significa che LDAP è
semplice. E’ un sistema potente e complesso. Ma con pò di know-how e i giusti tool è abbastanza semplice configurarlo. Grazie alla natura cross-platform di Tomcat e OpenLDAP, CruiseControl, Anthill etc. etc. tutto ciò può essere tenuto separato da ogni sistema d’esercizio. Questo tipo di disaccoppiamento ha dei vantaggi per tutti.
E’ da notare il fatto che non tutti i server LDAP sono uguali. Per esempio, OpenLDAP non supporta l’attributo memberOf per l’insieme dei membri di ruolo che controlla. Il Realm di OpenLDAP per Tomcat ad esempio non funzionerà necessariamente se cambiate i server di Directory ed i valori collegati.
Risorse
- Codice d’esempio per questo articolo
- OpenLDAP w32 binary
- JXplorer
- Jakarta Taglib home page
- Jakarta Tomcat 4 Realms
- Sun Servlet Specification homepage
Autore originale: Darren Duke
Link all’articolo originale
Traduzione a cura di Federico Paparoni
Il copyright di questo articolo rimane dell’autore originale, il quale deve essere interpellato per eventuali modifiche/traduzione/ripubblicazioni di questo e del suo materiale.
Commenti recenti