· 8 min Progettare

Il login scritto in casa non è il problema. Il secondo lo è.

Keycloak OAuth2 OpenID Connect Security Autenticazione

Scrivere un sistema di login da zero è noioso, ma si fa. Registrazione, reset password, hash delle credenziali, gestione delle sessioni: una settimana, forse due, e funziona.

Il conto arriva alla seconda applicazione. Perché la seconda non riusa la prima: riscrive le stesse tabelle, ripete gli stessi dubbi, e aggiunge un secondo posto in cui le password di una persona sono conservate — magari diverse dalle prime.

E il momento in cui quel conto diventa visibile a tutti è preciso: è il giorno in cui qualcuno lascia l’azienda. Perché a quel punto disattivarlo non è un’operazione, sono N operazioni su N sistemi, ognuna che può essere dimenticata. E quella dimenticata non fa rumore.

Perché i silos di identità si pagano dopo, non subito

Tre applicazioni in un’organizzazione — un gestionale HR, un CRM, un client di posta — ognuna con il proprio database utenti.

Tre applicazioni, tre database utenti separati: la stessa persona esiste tre volte, con tre password che non sono la stessa

Finché sono tre, sembra gestibile. I costi che crescono sono altri quattro, e nessuno si vede il primo giorno:

  • Le password si duplicano. L’utente usa la stessa ovunque — e allora una compromissione le apre tutte — oppure ne usa tre diverse e ne dimentica due, il che diventa carico per chi fa supporto.
  • Non c’è Single Sign-On. Login separato per ogni applicazione, ogni volta.
  • La sicurezza diverge. MFA, lockout dopo N tentativi falliti, audit degli accessi: ogni app li implementa a modo suo, o non li implementa. Nessuno sa quale sia messa peggio.
  • La disattivazione è N interventi. Quello di cui sopra.

E le architetture di oggi peggiorano il conto invece di migliorarlo. Un singolo prodotto può avere una SPA, un’API REST, cinque microservizi e un’app mobile: ognuno deve sapere chi sta chiamando. Riscrivere l’autenticazione in ognuno non è faticoso, è insostenibile.

Se il codice non tocca le password, non può gestirle male

La soluzione è togliere l’autenticazione dalle applicazioni e metterla in un componente dedicato — un Identity Provider. Le app smettono di gestire credenziali: ricevono un token firmato e ne verificano la firma.

Il punto non è la comodità. È che il rischio si sposta in un punto solo, e un punto solo si può presidiare davvero: si aggiorna quando esce una patch, si configura MFA una volta, si guarda un log di accessi invece di quattro.

Da qui discendono le due conseguenze che contano:

  • L’utente fa login una volta sola e accede a tutto. È il Single Sign-On.
  • Un dipendente esce? Lo disattivi in un posto e perde accesso ovunque.

Va detta anche l’altra faccia: quel punto solo è anche un punto singolo di guasto. Se l’IdP non risponde, non si autentica nessuno da nessuna parte. È un rischio che si progetta — repliche, cache dei token, tolleranza alla scadenza — non che si ignora.

Cosa deleghi a Keycloak, e cosa resta tuo

Keycloak è un Identity Provider open source nato in casa Red Hat, licenza Apache 2.0. Non è una libreria da integrare: è un servizio a sé stante che si avvia accanto alle applicazioni.

Le capacità di Keycloak: authorization server OAuth 2.0 e OIDC, federazione utenti, social login, single sign-on e console di amministrazione

Quello che smette di essere codice tuo:

  • Authorization server — implementa OAuth 2.0 e OpenID Connect. Le app delegano seguendo standard aperti, non un protocollo inventato in casa.
  • Federazione utenti — se esiste già un LDAP o un Active Directory con migliaia di utenti, Keycloak ci si collega e li usa. Nessuna migrazione.
  • Social login — Google, GitHub e gli altri si configurano dalla console, senza scrivere niente.
  • Gestione utenti — registrazione, reset password, sessioni, MFA.

Quello che resta tuo, e va detto perché è la parte che sorprende: decidere cosa un utente può fare. Keycloak dice chi è e trasporta i ruoli; è la vostra applicazione a decidere cosa quei ruoli aprono. Dove finisce l’autenticazione e comincia l’autorizzazione è una linea che va tracciata a mano, ed è il tema di OPA come motore di policy.

Realm, client, ruolo: i tre concetti che decidono la struttura

Prima di toccare qualsiasi cosa, tre parole. Sono tre perché sono le tre decisioni che poi è costoso cambiare.

  • Realm — il contenitore isolato: utenti, ruoli e configurazioni propri. Uno per progetto, o uno per ambiente. Due realm non si vedono fra loro, ed è esattamente questo che li rende utili.
  • Client — ogni applicazione che si collega. Il frontend React è un client, l’API che sta dietro è un altro. Non è burocrazia: è ciò che permette di dire che un token emesso per l’uno non vale per l’altro.
  • Ruolo — i permessi che finiscono nel token e che l’app userà per decidere.

Un esempio concreto: realm techstore, due client shop-ui e shop-api, gli utenti Mario e Admin, e il ruolo admin assegnato solo al secondo. Quando Mario fa login, il suo token dice all’applicazione chi è e cosa gli è consentito, senza che l’applicazione debba chiederlo a nessuno.

Il login, in tre passaggi

Il flusso standard per un’applicazione web si chiama Authorization Code Flow, e dal punto di vista dell’utente sono tre cose:

  1. clicca “Login” nell’app e viene reindirizzato alla pagina di Keycloak
  2. inserisce le credenziali su Keycloak, non sull’app
  3. torna all’app con un token JWT che contiene identità, ruoli e scadenza

Keycloak firma quel token con la propria chiave privata; l’app lo valida scaricando la chiave pubblica. Se qualcuno lo modifica, la firma non torna e il token viene rifiutato.

Il passaggio 2 è quello su cui si sbaglia più spesso: l’app non deve avere un form di login proprio. Se raccogliete username e password nel vostro frontend, quelle credenziali passano di nuovo attraverso il vostro codice — e siete tornati al punto di partenza, con tutti i problemi che l’IdP doveva togliere. Il redirect esiste precisamente per evitarlo.

Il flusso completo, con PKCE e la configurazione di client e middleware, è il tema del prossimo articolo della serie.

Le quattro trappole del primo giorno

  • Il form di login nell’app. Quello di sopra. È l’errore che annulla il senso dell’operazione.
  • start-dev in produzione. Comodo per provare, inadatto oltre: abilita HTTP senza TLS, usa un database H2 locale e rilassa diverse configurazioni di sicurezza. In produzione serve start, con PostgreSQL e HTTPS.
  • Ignorare i ruoli. Keycloak ha un sistema di ruoli completo. Reinventare l’autorizzazione con logica custom nel backend significa riportare dentro il codice quello che si era appena tolto.
  • URL hardcoded. L’indirizzo di Keycloak cambia fra locale, staging e produzione. Se non è configurabile dal primo giorno, il primo deploy fuori da localhost vi accoglie con un 401 senza spiegazione.

Provarlo in un minuto

docker run -p 8080:8080 \
  -e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
  -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \
  quay.io/keycloak/keycloak:26.0 start-dev

Su http://localhost:8080, con admin/admin, c’è la console. Da lì: un realm, un client di tipo public con il redirect URI dell’app, un utente. Lato applicazione serve una libreria client — keycloak-js per il frontend, un middleware JWT per il backend — ma la logica di autenticazione resta tutta di là.

Quanto vale, detto a chi non scrive codice

Il beneficio non è “una cosa in meno da scrivere”, che è un argomento da sviluppatori. È questo: l’uscita di una persona dall’azienda passa da N interventi su N sistemi, ognuno dimenticabile, a un interruttore solo — e insieme a quello, MFA e audit degli accessi diventano una decisione presa una volta invece di N implementazioni scritte da persone diverse in momenti diversi.

Il che si traduce nella domanda a cui una direzione tecnica deve saper rispondere: quanto tempo passa, oggi, fra il momento in cui una persona lascia e il momento in cui non può più entrare in nulla? Se la risposta richiede di aprire una lista di sistemi e spuntarli a mano, il numero non lo sapete.

Da dove partire

Contate i posti in cui esiste una tabella users nei vostri progetti. Se sono più di uno, avete già il problema di questo articolo — semplicemente non l’avete ancora pagato.

Poi lanciate il comando qui sopra e create un realm con due client. Dieci minuti servono a capire se i tre concetti della sezione precedente reggono il vostro caso, che è la sola domanda che conta prima di adottarlo.

Cosa resta aperto

Ciò che una panoramica d'introduzione lascia deliberatamente fuori

  • Il flusso di login è descritto nei suoi tre passaggi ad alto livello: la configurazione completa di client e protocollo resta fuori da questa introduzione
  • Federazione LDAP, social login e ruoli compaiono come capacità disponibili: nessuna viene qui configurata
  • L'esempio di avvio fissa la versione 26.0 dell'immagine Docker: comandi e console di amministrazione possono variare in altre release
  • `start-dev` vale solo per la prova: HTTP senza TLS e database H2 locale lo rendono inadatto oltre lo sviluppo
  • Centralizzare l'identità sposta il rischio invece di eliminarlo: l'IdP diventa un punto singolo di guasto, e va progettato di conseguenza
Francesco Montelli
Francesco Montelli
Software Engineer freelance

Software Engineer freelance. Progetto, sviluppo e automatizzo il software di prodotto: dall'architettura alla realizzazione, fino ai processi che ne garantiscono la qualità nel tempo. Da zero o su sistemi irrigiditi.

Seguimi su LinkedIn

Articoli correlati

Modifica su GitHub