Spring Boot + Spring Security + SAML 2.0
In questo articolo andiamo a vedere come configurare l’autenticazione tramite lo standard SAML 2.0 (Security Assertion Markup Language) su una applicazione realizzata con il framework Spring Boot.
Le versioni delle dipendenze utilizzate sono le seguenti:
- Spring Boot 2.4.2
- Spring Security 5.4.2
- Spring Security SAML2 Service Provider 5.4.2
Come Identity Provider (free) utilizziamo Okta.
Tutto il sorgente Java presente nell’articolo è disponibile al seguente Git repos:
Cosa è SAML 2.0?
SAML (Security Assertion Markup Language) è uno standard informatico per lo scambio di dati di autenticazione e autorizzazione (asserzioni SAML basate su XML) tra domini di sicurezza eterogenei.
In genere le entità che partecipano sono due:
- Identity Provider: Sistema Informatico che fornisce informazioni sull’identità degli utenti. In genere questi sistemi fanno parte del mondo IAM (Identity Access Management) con moduli WAM (Web Access Management)
- Service Provider: Applicazione che fornisce un servizio protetto dalla sicurezza SAML2.
SAML è uno standard di mercato ed è mantenuto dall’ente OASIS Security Services Technical Committee (link).
Il problema principale che SAML cerca di risolvere è quello del Web Single sign-on (SSO) tra entità appartenenti a organizzazioni e domini di sicurezza distinti.
Come funziona SAML 2.0?
SAML richiede che l’utente (denominato “principal”) sia registrato presso almeno un Identity provider. L’identity provider deve provvedere ad autenticare l’utente. Il Service provider a questo punto si affida all’identity provider per identificare il principal. Su richiesta del principal l’identity provider passa una asserzione SAML al service provider sulla base della quale quest’ultimo decide se permettere o negare l’accesso ai propri servizi da parte del principal.
Di seguito viene mostrato il Sequence Diagram del flusso di autenticazione SAML 2.0:
Configurazione Identity Provider (Okta)
Come prima cosa dobbiamo configurare la nostra applicazione, che andremo successivamente a creare con il framework Spring Boot, su un Identity Provider.
L’Identity Provider utilizzato è Okta, quindi dopo aver creato un utenza free di tipo Developer, andiamo a creare la nostra Applicazione.
Entrando nella console di amministrazione, sotto la voce “Applications”, troviamo il bottone “Add Application”:
Cliccando sul bottone si apre una finestra modale dove specifichiamo il tipo di piattaforma della nostra applicazione (in questo caso “Web”) ed il tipo di autenticazione che vogliamo sfruttare, nello specifico SAML 2.0:
Nella pagina seguente andiamo ad inserire il nome della nostra applicazione (nella figura abbiamo inserito “App SAML”):
Andando avanti nel processo possiamo ora configurare i parametri necessari alla configurazione del nostro Identity Provider (brevemente IdP) per l’utilizzo di SAML.
I valori che andiamo ad inserire sono i seguenti:
- Single sign on URL: http://localhost:8080/login/saml2/sso/okta-saml
- Audience URI (SP Entity ID): http://localhost:8080/saml2/service-provider-metadata/okta-saml
Concludiamo la configurazione della nostra Applicazione dichiarando che è una applicazione interna, di prova, che stiamo creando:
Terminata la procedura di creazione dell’applicazione, selezionandola e spostandoci sul tab “Assignements” andiamo ad aggiungere gli utenti abilitati all’accesso sull’applicazione.
Ora che la nostra applicazione è stata creata ed abbiamo istruito l’Identity Provider con le informazioni degli utenti che possono accedervi, è ora il momento di configurare la nostra applicazione Spring Boot.
Per la configurazione dobbiamo recuperare alcuni parametri che serviranno in seguito, andando sul tab “Sign On” clicchiamo su “View Setup Instructions” sotto il box SAML 2.0.
All’apertura della pagina andiamo a salvare le informazioni ai punti 1, 2 e 3.
Spring Security SAML2
Come prima cosa andiamo a creare il nostro progetto con Maven, di seguito riportiamo il pom.xml utile a soddisfare le dipendenze di Spring Boot e Spring Security:
Il nostro pom.xml contiene le seguenti dipendenze:
- spring-boot-starter-web → Per la gestione MVC
- spring-boot-starter-thymeleaf → Per la gestione dei template HTML
- spring-boot-starter-security→ Dipendenza alla libreria spring-security
- spring-security-saml2-service-provider → Dipendenza di SAML2
In seguito creiamo la nostra Spring Boot Application con due pagine web, la home e una post-autenticazione (/secured/hello) in cui andremo a stampare l’utente loggato ritornato dall’Identity Provider.
Come vediamo sopra per recuperare il principal (utente) loggato andiamo ad utilizzare, all’interno dei parametri del metodo, questa annotazione:
@AuthenticationPrincipal Saml2AuthenticatedPrincipal principal
Un altro meccanismo per recuperare il principal, senza voler utilizzare l’annotazione è il seguente:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Saml2AuthenticatedPrincipal principal = (Saml2AuthenticatedPrincipal) authentication.getPrincipal();
Ora passiamo alla configurazione di Spring Security:
Nel sorgente sopra è possibile vedere le seguenti configurazioni:
- Abilitazione di SAML2 tramite il seguente snippet:
http.authorizeRequests(authorize ->
authorize.antMatchers("/").permitAll().
anyRequest().authenticated()
).saml2Login();
- Generazione del file metadata.xml del Service Provider (quindi la nostra applicazione). Il metadata.xml sarà visionabile e scaricabile all’indirizzo:
http://localhost:8080/saml2/service-provider-metadata/okta-saml
Questo file il più delle volte è utilizzato come contratto tra l’Identity Provider e il Service Provider. Il codice che permette la generazione è il seguente:
// add auto-generation of ServiceProvider Metadata
Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationResolver = new DefaultRelyingPartyRegistrationResolver(relyingPartyRegistrationRepository);Saml2MetadataFilter filter = new Saml2MetadataFilter(relyingPartyRegistrationResolver, new OpenSamlMetadataResolver());http.addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class);
- Il bean RelyingPartyRegistrationRepository utile alla configurazione dei parametri per SAML2. In questo bean andiamo ad inserire i valori presi nella pagina “Setup Instructions” del provider Okta (passo spiegato alcuni paragrafi sopra). In dettaglio, visualizzando l’immagine “Parametri di configurazione SAML 2.0”, andiamo ad inserire il valore al punto 1 in singleSignOnServiceLocation, il valore al punto 2 in entityId ed copiare l’interno contenuto del certificato al punto 3 sotto il file /src/main/resources/saml-certificate/okta.crt e inseriamo il puntamento nella variabile verificationKey
Qualora non si volesse creare il bean RelyingPartyRegistrationRepository programmaticamente, è possibile utilizzare la configurazione nel file application.yaml di Spring mostrato di seguito:
Come ultima cosa andiamo a creare le nostre due pagine web:
- La homepage, con un link alla pagina protetta:
- La nostra pagina protetta, dove andremo a stampare l’utente loggato tramite IdP:
La nostra applicazione è ora pronta e configurata per l’autenticazione SAML2.
Autenticazione con SAML2 tramite Identity Provider
Eseguiamo il comando per startare la nostra applicazione:
mvn spring-boot:run
Da browser navigando all’indirizzo http://localhost:8080/ , visualizzeremo la nostra home page.
Cliccando sul link automaticamente saremo reindirizzati alla pagina di login dell’Identity Provider, come mostrato:
Inseriamo le credenziali di Okta (dell’utente associato sull’applicazione Okta, configurato nei paragrafi sopra)e all’avvenuto login, saremo reindirizzati nuovamente alla nostra applicazione alla pagina richiesta (quindi quella protetta) e potremo vedere a video l’utente con il quale abbiamo effettuato l’accesso su Okta.
Ora siamo dentro la nostra applicazione loggati tramite SAML2!