Per Iniziare
Comincia dalle basi e scopri come utilizzare Mia-Platform a piccoli passi.
Comincia dalle basi e scopri come utilizzare Mia-Platform a piccoli passi.
Inizia ora
Diventa Partner certificato e scopri tutti i benefici del Partner Program.
Scopri il nostro programma
In un articolo precedente abbiamo parlato di come si gestisce l’autenticazione machine to machine attraverso il protocollo OAuth 2.0, specificando anche le differenze tra autorizzazione e autenticazione.
In questo articolo vogliamo raccontare come lo gestiamo internamente attraverso un componente appositamente realizzato, Client Credentials, che utilizza la registrazione dei client e il flusso Client Credentials di OAuth 2.0, e i metodi di Client Authentication client_secret_basic e private_key_jwt descritti in OpenID Connect 1.0.
Client Credentials è un servizio di Mia-Platform che abbiamo implementato allo scopo di gestire la registrazione, la login, i permessi e i metadati dei client.
Tra i requisiti fondamentali troviamo:
Abbiamo deciso di implementare il servizio usando Go, linguaggio già usato in Mia-Platform per altri progetti e che sappiamo essere performante.
Di seguito descriveremo i metodi di autenticazione supportati dal servizio e la fase di autorizzazione, che è indipendente dal tipo di autenticazione che si è effettuata.
Prima di tutto però è importante definire come abbiamo deciso di costruire l’access token che, come abbiamo spiegato in questo articolo, è un attore centrale del protocollo OAuth 2.0.
Abbiamo scelto di utilizzare come tipologia di access token lo standard JWT (JSON Web Token) che permette di firmare un payload contenente un JSON con un numero variabile di claim. I claim sono un modo comune per le applicazioni di acquisire informazioni sugli utenti, come per esempio i permessi del client che ha richiesto l’autenticazione.
Il Client Credentials crea la signature del token utilizzando una coppia di chiavi asimmetriche, quindi una chiave pubblica e una chiave privata.
Il primo metodo di autenticazione che abbiamo sviluppato è il metodo base per il grant type client credentials, chiamato client secret basic.
Questo metodo di autenticazione si basa sulla condivisione tra il client e il servizio Client Credentials di un client id e di un client secret.
La creazione di questa coppia avviene durante la registrazione del client.
Come si può vedere dall’immagine, per effettuare la registrazione l’utente deve inviare all’endpoint di registrazione un nome per identificare il client.
Il Client Credentials genera un client id e un secret, e li salva in un database riservato alle credenziali; in un altro database vengono salvate le informazioni non riservate del client, come il nome.
Il Client Credentials risponde quindi con la coppia di credenziali, più le informazioni sulla scadenza e la data di rilascio delle credenziali, come da specifica OAuth2.0 RFC7591.
L’endpoint di login è esposto sotto la rotta /oauth/token, e segue le specifiche OAuth2.0 per il grant type Client Credentials. La richiesta avviene usando il formato x-www-form-urlencoded e le credenziali sono inviate nell’authorization header con tipo Basic. Come si può notare, il nome del metodo di autenticazione deriva dalla posizione delle credenziali nella chiamata di autenticazione.
Il servizio Client Credentials verifica che le credenziali siano corrette e risponde al client con un access token, le informazioni sul tipo di token (nel nostro caso, Bearer) e l’informazione sulla durata (in secondi) del token.
La durata dell’access token deve essere temporalmente limitata così da rendere sicura l’autorizzazione: chi dovesse riuscire a rubare il token non farebbe in tempo a utilizzarlo.
Per andare incontro alle diverse necessità di sicurezza dei nostri clienti, si è deciso di lasciare configurabile la durata dell’access token.
Con il metodo client secret basic viene inviata la secret per effettuare la login; in questo modo è possibile essere esposti ad attacchi quali man in the middle volti ad ottenere la secret o a possibili errori umani (come per esempio la condivisione di una curl di autenticazione con inserite le credenziali).
Questo metodo di autenticazione eleva notevolmente il livello di sicurezza del meccanismo. Risulta infatti essere tra i metodi consentiti per l’uso di API Financial-Grade (FAPI): questo significa che è adatto a proteggere interazioni di tipo finanziario, bancario e assicurativo.
Da un punto di vista implementativo, gli endpoint di registrazione e di login sono gli stessi usati per Client Secret Basic e cambiano solo i parametri che vengono passati.
Questo metodo di autenticazione si basa sul possesso da parte del client di una coppia di chiavi asimmetriche.
Come primo passaggio, il client deve creare una coppia formata da una chiave privata e dalla relativa chiave pubblica e rendere accessibile la chiave pubblica al servizio Client Credentials, condividendola tramite JSON Web Key (JWK), un oggetto JSON che rappresenta una chiave crittografica, come spiegato nel RFC 7517.
Con questo metodo di autenticazione il client non condivide con il servizio di autorizzazione nessun secret, ma solamente delle informazioni pubbliche.
Nel diagramma seguente, viene illustrato il flusso di registrazione.
Di seguito, un esempio della chiamata di registrazione di un client usando questo sistema di autenticazione e una chiave RSA256:
curl --location --request POST 'http://client-credential-host/register'
--header 'Content-Type: application/json'
--data-raw '{
"client_name": "my client name",
"token_endpoint_auth_method": "private_key_jwt",
"public_key": {
"kid": "key id",
"use": "sig",
"kty": "RSA",
"alg": "RSA256",
"n": "...",
"e": "AQAB"
}
}
La public_key indicata nel body della chiamata è un esempio di JWK.
Il servizio Client Credentials ritorna il client id generato e l’informazione su quando è stato generato.
Una volta ottenuto il client id, il client può usare la chiave privata per ottenere un access token.
A tal fine il client deve creare un JWT firmato con la propria chiave privata chiamata client assertion. La client assertion contiene le informazioni che consentono a Client Credentials di identificare il client. In questo modo, Client Credentials può validare sia il contenuto del JWT, sia chi è stato a crearlo: l’unico a possedere la chiave privata è il client.
Per scongiurare un Replay Attack, il JWT non può essere usato più di una volta come metodo di asserzione; chi dovesse entrare in possesso dell’assertion JWT non potrebbe in ogni caso utilizzarlo. È stato quindi risolto in questo modo anche il possibile errore umano della condivisione accidentale di credenziali.
La richiesta di autenticazione contiene nel body in formato urlencoded:
Una volta ottenuto l’access token con uno dei due metodi di autenticazione supportati da Client Credentials, il client può utilizzarlo per richiedere l’autorizzazione al resource owner. Questo viene fatto inserendo l’access token nella richiesta, all’interno dell’authorization header.
Se il servizio richiesto è erogato dalla piattaforma di Mia-Platform, la validazione è fatta dallo stesso Client Credentials.
Una delle esigenze dei clienti di Mia-Platform è permettere a sistemi esterni di usare Client Credentials come provider di autenticazione e sistema di assegnazione dei permessi. Tramite questo meccanismo, a un sistema esterno sarà sufficiente verificare la validità dell’access token e i permessi contenuti tra i claim.
Vediamo di seguito i due meccanismi.
Una volta che la richiesta è giunta alla piattaforma Mia-Platform, l’access token viene estratto dall’authorization header.
Client Credentials verifica la validità dell’access token attraverso la rispettiva chiave pubblica ed estrae i claim del JWT. Tra questi claim sono presenti i permessi che ha il client, e che possono quindi essere utilizzati per autorizzare il client in base alla richiesta.
La verifica dei permessi, quindi la fase di autorizzazione, può essere fatta dal servizio Authorization Service di Mia-Platform. Il metodo con cui le operazioni di autorizzazione vengono effettuate all’interno della piattaforma Mia-Platform vanno oltre gli scopi di questo articolo.
Come detto in precedenza, l’access token è un JWT firmato tramite una chiave asimmetrica. Client Credentials espone un set di chiavi pubbliche (JWKS) tramite un apposito endpoint.
Un provider esterno per verificare l’access token:
Validato il JWT, il servizio esterno estrae e usa i permessi per autorizzare, o meno, l’accesso alla risorsa richiesta.
L’access token ha un ulteriore claim, detto audience, che contiene un identificativo del sistema che possiede la risorsa richiesta. In fase di login un client deve specificare l’audience richiesto.
Questo claim permette di evitare un uso improprio dell’access token da parte del ricevente, come mostrato di seguito.
Tre sistemi A, B e C utilizzano lo stesso provider di autenticazione e possiedono i seguenti permessi:
Se il sistema A chiamasse con un token il sistema B, nulla vieterebbe al sistema B di usare lo stesso token per accedere al sistema C, sistema al quale non dovrebbe poter accedere. Ma poiché in fase di login il client A specifica come audience B, l’access token può essere utilizzato solo per accedere a B.
Poiché l’audience viene salvato tra i claim del JWT, un sistema esterno può, e deve, verificare se quel token è stato creato per accedere a quel sistema specifico.
Ci sono diversi modi per gestire l’autenticazione M2M; noi abbiamo scelto di realizzare un servizio apposito, Client Credentials, che utilizza il flusso Client Credentials di OAuth 2.0, e i metodi di Client Authentication client_secret_basic e private_key_jwt descritti in OpenID Connect 1.0.
Realizzando un componente apposito, oltre a svincolarci da terzi, abbiamo potuto calibrare le scelta sulle nostre necessità di performance – utilizzando il linguaggio Go – e di sicurezza – implementando la tecnologia jwt.
Il risultato è un nuovo componente di piattaforma, sicuro e performante, che può essere configurato in modo semplice e veloce, con un notevole risparmio di costi.
Articolo scritto da Davide Bianchi, Senior Technical Leader, e Davide Tantillo, Senior Technical Leader.