Primi Passi con Spring Security (parte 2)

Proseguiamo la serie su Spring Security evolvendo la semplice applicazione web presentata nel precedente articolo Primi Passi con Spring Security (parte 1) in cui abbiamo visto come configurare il progetto al fine di implementare il processo di autenticazione.

Authentication Provider

Spring Security fornisce diverse opzioni per l’esecuzione del processo di autenticazione. Il più semplice è quello visto nell’esempio in cui gli utenti sono elencati nel file di contesto che definisce il security context, ma ovviamente non è l’approccio più sicuro e comunque non è consigliato per il rilascio produzione. Più probabilmente le informazioni utente vengono recuperate dal database applicativo o attraverso servizi di autenticazione tipo LDAP.

Custom Provider

Il primo caso che vediamo è quello di una implementazione del processo di autenticazione attraverso un bean che implementa l’interfaccia UserDetailsService di Spring implementando il metodo loadUserByUsername().

Input al metodo è la username inserita nella form di login mentre come output è restituito un oggetto che implementa l’interfaccia UserDatails, contenente le informazioni sull’utente “recuperato”. Nell’esempio è ritornato un oggetto User istanziato  con la username, la password ed i ruoli dell’utente, ma è anche possibile specificare se l’utente è abilitato, oppure se l’account o la password sono scaduti. Si noti infine che, secondo specifica, il metodo non deve restituire NULL il caso in cui l’utente non esista, ma sollevare l’eccezione UsernameNotFoundException.

Diversamente dal caso semplice visto nell’esempio originale, in questo caso è stata utilizzato un encoder per la password. Al solito è possibile implementare il proprio encoder estendendo l’interfaccia PasswordEncoder di Spring, e lo stesso framework ne fornisce diversi, tra cui ovviamente il NoOpPasswordEncoder che non esegue nessuna operazione. Nella classe UserService però abbiamo preferito utilizzare il BCryptPasswordEncoder fornito da Spring e che implementa l’algoritmo BCrypt.

La registrazione del provide UserService da noi implementato avviene sul file spring-security.xml utilizzando il tag <authentication-provider>:

Si noti che è possibile utilizzare più tag <authentication-provider> ciascuno con metodi di autenticazione (ed encoding) differenti.

Database Provider

Prima di procedere con gli esempi introduciamo nel progetto il database H2, inserendo la dipendenze necessarie nel file pom.xml:

Inoltre creiamo un file db-h2-config.xml nella cartella /spring in cui configuriamo il datasource, gli script per la creazione della base dati, secondo la struttura prevista dal framework, e gli script per l’inserimento degli utenti.

Per l’accesso alla base dati così definita per il recupero delle informazioni utente è possibile seguire due strade distinte. La prima è quella di definire esplicitamente un bean di tipo JdbcDaoImpl, classe Spring che estende UserDetailsService, e che utilizza il datasource specificato in configurazione per implementare il servizio loadUserByUsername().

La seconda strada è quella di utilizzare il tag <jdbc-user-service> che istanzia direttamente un bean che implementa UserDetailsService ed utilizzando un datasource per l’accesso alla base dati degli utenti.

Custom database

In generale è abbastanza improbabile che la nostra base dati sia conforme allo schema previsto dal Database Provider di Spring Security. Per tale motivo il tag <jdbc-user-service> prevede i seguenti attributi:

users-by-username-query Consente di definire la query SLQ per il recupero delle informazioni utente. La query di default è:
select username, password, enabled
from users where username = ?
authorities-by-username-query Consente di definire la query SLQ per il recupero dei ruoli dell’utente. La query di default è:
select username, authority
from authorities where username = ?

Codice Sorgente

Il codice sorgente completo degli esempi presentati è scaricabile qui spring-security.