Configurare Spring Security 3.1

DOMANDA:

Che cosa significano i tag che scrivo negli xml quando configuro Spring Security 3.1? Quali sono le impostazioni minime?


RISPOSTA:

Configurare Spring Security 3.1 non è difficile, ma ci si può facilmente perdere per strada se non si ha il giusto approccio al problema e se non si conoscono almeno le funzionalità di base offerte.
Se cercate un'esecuzione al volo di codice funzionante, c'è un'altra mia risposta sempre su questo blog. In questo post spiego in maniera più curata i dettagli.

Visione di insieme di Spring Security 3.1:

Spring Security è un framework per Java EE che si occupa di mettere in sicurezza un progetto enterprise utilizzando come concetti di base l'autenticazione, le autorizzazioni ed eventuale crittografia della password.
Per poterlo utilizzare c'è però bisogno di configurarlo in maniera opportuna e seguire delle linee guida.

Questa discussione dà per scontato e ragiona su un progetto completo e funzionante. Se non ne avete uno potete costruirvelo in 5 minuti leggendo quest'altro mio post e vediamo di capire cosa facciamo.



File di configurazione:
web.xml - dispatcher-servlet.xml - spring-security.xml

Veniamo alla configurazione degli XML.
Se desideriamo usare le annotation @PreAuthorize aggiungiamo la libreria esterna CGLIB al progetto e scriviamo dentro dispatcher-servlet.xml:

xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security
  http://www.springframework.org/schema/security/spring-security-3.1.xsd"
...
<security:global-method-security pre-post-annotations="enabled">

Le librerie CGLIB org.springframework.aop riguardano la programmazione orientata agli aspetti, e non agli oggetti. Ed è proprio questa  considerazione che risponde a diverse persone che dicono che Spring agisca "usando la magia". Con gli aspetti si possono intercettare momenti dell'esecuzione del codice tramite i pointcut ed applicare operazioni di filtraggio. Per maggiori informazioni sugli aspetti vi rimando a Wikipedia ed AspectJ.

Guardiamo anche le righe aggiunte dentro web.xml:

<context-param>
    <param-name>contextConfigLocation</param-name>
      <param-value>
        /WEB-INF/spring-security.xml
    </param-value>
</context-param>

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>
      org.springframework.web.filter.DelegatingFilterProxy
   </filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping> 

il contextConfigLocation informa il programma che esistono altri file xml da dover leggere, definendone il path subito dopo.
Il FilterChain è un modo di Spring Security di applicare a catena una serie di filtri, volendo implementabili anche dal programmatore. Siccome ne esistono già di default che vengono impilati nell'esecuzione di Spring Security, dobbiamo per forza inserire questa configurazione anche se non ne scriviamo di nostri.

Infine analizziamo spring-security.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
  xmlns:beans="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p"
  xmlns:util="http://www.springframework.org/schema/util"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
 http://www.springframework.org/schema/security
 http://www.springframework.org/schema/security/spring-security-3.1.xsd
 http://www.springframework.org/schema/util
 http://www.springframework.org/schema/util/spring-util-3.1.xsd">

<http pattern="/immagini/*" security="none"/>

<http auto-config="true" use-expressions="true">
  <intercept-url pattern="/user/**" access="isAuthenticated()"/>
  <intercept-url pattern="/admin/**" access="hasRole(admin)"/>
  <form-login />
  <logout />
  <remember-me />
</http>


<authentication-manager>
   <authentication-provider>
      <user-service>
<user name="giuseppe" password="totti" authorities="admin, user"/>
<user name="fabrizio" password="ciao" authorities="autore, user"/>
<user name="massimo" password="12031983" authorities="user"/>
      </user-service>
   </authentication-provider>
</authentication-manager>


Come notate, esistono più blocchi <http>, questa è una novità di Spring Security 3.1.
In generale, possiamo intercettare gli url che l'utente inserisce a mano tramite i pattern. Indichiamo quali cartelle sono da intercettare (l'url) e quale accesso sarà permesso. Qualsiasi tentativo non autorizzato su questi url rimanderà alla pagina di login.
Mettiamo anche use-expressions="true" perchè ci abilita scritte come "hasRole(admin)" che invocano direttamente metodi di oggetti di default.

    <form-login />
    <logout />
    <remember-me />

Queste 3 righe attivano le opzioni di default del login, logout e del checkbox che serve per ricordare l'utente e non dover effettuare un login per un periodo configurabile.
Esiste il modo per creare una pagina di login personalizzata, e di dare ulteriori direttive sia al login che al logout.
Come usare l'authentication-manager, authentication-provider e user-service esula dagli obiettivi di configurazione minima.
I parametri passati nello user si spiegano da soli, vediamo lo username, la password e le autorizzazioni che ha ogni utente.
Le password qui sono in chiaro, ma Spring Security offre la possibilità di crittografarle a regola d'arte.

Utilizzare delle password non in chiaro è conveniente per evitare che malintenzionati, magari tramite una sql injection, possano visualizzare l'elenco delle vostre password ed utilizzarle per l'accesso all'applicativo. 
Resta comunque evidente che utilizzare password deboli come "ciao" o le date di nascita non evita il rischio di vedersi compromesso l'account.
Quello sulla scelta di una password sicura non è però argomento di questo post.


Sicurezza nelle pagine web:

Andiamo a vedere una tipica pagina web in cui è presente una lista:

<ul>
    <li><a href="sondaggio.htm"> visualizza sondaggio </a></li>
    <sec:authorize access="isAuthenticated()">
        <li><a href="profiloUtente.htm"> profilo </a></li>
        <li><a href="logout.htm"> logout </a></li>
    </sec:authorize>
    <sec:authorize access="hasRole('admin')">
        <li><a href="adminMenu.htm"> amministrazione </a></li>
    </sec:authorize>
</ul>

Possiamo notare il tag sec:authorize che tramite un parametro di accesso decide a tempo di esecuzione quali campi fare apparire e quali invece non sono accessibili.
Abbiamo 4 elementi nella lista:
- il primo è accessibile a tutti, quindi anche agli anonimi.

- il secondo ed il terzo sono proprietà che hanno senso solo per un utente registrato, per tanto l'accesso è limitato solo agli autenticati (non anonimi).
- l'ultimo fornisce accesso al menu di amministratore ed è quindi disponibile solamente per un utente che ha l'autorizzazione di admin (la stessa che abbiamo definito prima per l'utente di nome "giuseppe").

L'utente che non dispone dell'autorizzazione, non vede proprio la porzione di codice fra i tag di authorize. Di conseguenza un utente non loggato vede una lista con 1 solo elemento, un utente normale vede 3 elementi e solo un admin li vede tutti e 4.


Sicurezza nei metodi del controller:

Guardiamo un semplice metodo implementato:

@RequestMapping(value = "/menu.htm")
@PreAuthorize("isAuthenticated()")
public String provaPreAuthorize(){
    return "menu.jsp";
}

L'annotation @RequestMapping viene da Spring MVC e non è una novità. Ciò che ci interessa invece è @PreAuthorize("isAuthenticated()"). Questo indica che se il metodo viene chiamato da una pagina web in cui l'utente non è loggato, il pre authorize fa fallire la richiesta e restituisce di default l'errore 404 (pagina non trovata). Tale protezione è utile anche contro attacchi di base che potrebbe fare un utente qualsiasi, scrivendo nell'indirizzo  "http://....../menu.htm". Di fatti in questo modo richiamerebbe direttamente il metodo del controller senza passare per alcuna pagina web in cui magari si controlla l'accesso col sec:authorize descritto in precedenza.


Commenti

  1. Questo commento è stato eliminato dall'autore.

    RispondiElimina
  2. Grande tutorial!

    Il mio obiettivo è costruire un metodo custom @PreAuthorize("@mySecurityService.verify('special')") e verificare essenzialmente due cose:
    -è presente in sessione un oggetto (che indica se l'utente è o meno loggato)?
    -è abilitato l'utente ad eseguire la funzionalità (query su db)?

    Grazie alla tua guida credo di aver capito come fare.

    Ciò detto ho una domanda da farti: per chi non ha necessitò di definire utenti nel file di configurazione spring-security (come me), cosa dovrebbe inserire nel blocco di authentication-manager che è richiesto obbligatoriamente? In una applicazione enterprise (tanti ruoli, tanti utenti e quindi tante password) queste informazioni non posso di certo memorizzarle qui.

    RispondiElimina

Posta un commento

Post popolari in questo blog

Arrotondamento e troncamento in Java

Eclipse: Shortcuts (scorciatoie) da tastiera

Strutture dati: List, Set, Map

Creare un eseguibile Java