OpenID Connect: autorizzazione delle applicazioni interne da custom a standard

Alcuni mesi fa stavo implementando un server OpenID Connect per gestire l'accesso per centinaia di nostre applicazioni interne. Dai nostri sviluppi, convenienti su scala ridotta, siamo passati a uno standard generalmente accettato. L'accesso tramite un servizio centrale semplifica notevolmente le operazioni monotone, riduce i costi di implementazione delle autorizzazioni, consente di trovare tante soluzioni già pronte e di non scervellarsi nello sviluppo di nuove. In questo articolo parlerò di questa transizione e degli ostacoli che siamo riusciti a superare.

OpenID Connect: autorizzazione delle applicazioni interne da custom a standard

Molto tempo fa... Dove tutto ha avuto inizio

Diversi anni fa, quando le applicazioni interne diventavano troppe da gestire manualmente, abbiamo scritto un'applicazione per controllare gli accessi all'interno dell'azienda. Si trattava di una semplice applicazione Rails che si collegava a un database con informazioni sui dipendenti, dove veniva configurato l'accesso a varie funzionalità. Allo stesso tempo abbiamo lanciato il primo SSO, che si basava sulla verifica dei token da parte del client e del server di autorizzazione; il token veniva trasmesso in forma crittografata con diversi parametri e verificato sul server di autorizzazione. Questa non era l'opzione più conveniente, poiché ogni applicazione interna doveva descrivere un notevole livello di logica e i database dei dipendenti erano completamente sincronizzati con il server di autorizzazione.

Dopo qualche tempo, abbiamo deciso di semplificare il compito dell'autorizzazione centralizzata. SSO è stato trasferito al sistema di bilanciamento. Con l'aiuto di OpenResty, è stato aggiunto a Lua un modello che controllava i token, sapeva a quale applicazione era indirizzata la richiesta e poteva verificare se c'era accesso lì. Questo approccio ha notevolmente semplificato il compito di controllare l'accesso alle applicazioni interne: non è stato più necessario descrivere una logica aggiuntiva nel codice di ciascuna applicazione. Di conseguenza, abbiamo chiuso il traffico esternamente, ma l'applicazione stessa non sapeva nulla dell'autorizzazione.

Tuttavia, un problema rimaneva irrisolto. Che dire delle applicazioni che necessitano di informazioni sui dipendenti? Sarebbe possibile scrivere un'API per il servizio di autorizzazione, ma in questo caso sarebbe necessario aggiungere logica aggiuntiva per ciascuna di queste applicazioni. Inoltre, volevamo eliminare la dipendenza da una delle nostre applicazioni scritte da noi, che è ulteriormente focalizzata sulla traduzione in OpenSource, sul nostro server di autorizzazione interno. Ve lo racconteremo un'altra volta. La soluzione a entrambi i problemi era OAuth.

Verso standard generalmente accettati

OAuth è uno standard di autorizzazione chiaro e generalmente accettato, ma poiché la sua funzionalità da sola non è sufficiente, è stato subito preso in considerazione OpenID Connect (OIDC). Lo stesso OIDC è la terza implementazione dello standard di autenticazione aperto, che si è evoluto in un superset del protocollo OAuth 2.0 (Open Authorization Protocol). Questa soluzione risolve il problema della mancanza di dati sull'utente finale e consente anche di cambiare il fornitore di autorizzazioni.

Tuttavia, non abbiamo scelto un fornitore specifico e abbiamo deciso di aggiungere l'integrazione con OIDC per il nostro server di autorizzazione esistente. Questa decisione è stata supportata dal fatto che OIDC è molto flessibile in termini di autorizzazione dell'utente finale. Pertanto è stato possibile implementare il supporto OIDC sul tuo attuale server di autorizzazione.

OpenID Connect: autorizzazione delle applicazioni interne da custom a standard

Il nostro percorso verso l'implementazione del nostro server OIDC

1) Riporta i dati nel form richiesto

Per integrare OIDC, è necessario portare i dati utente attuali in una forma comprensibile per lo standard. In OIDC questo si chiama Claims. I marchi sono essenzialmente i campi finali nel database degli utenti (nome, email, telefono, ecc.). Esiste elenco standard dei marchie tutto ciò che non è incluso in questo elenco è considerato personalizzato. Pertanto, il primo punto a cui prestare attenzione se si desidera scegliere un fornitore OIDC esistente è la possibilità di personalizzare comodamente nuovi francobolli.

Il gruppo di marchi è combinato nel seguente sottoinsieme – Ambito. Durante l'autorizzazione viene richiesto l'accesso non a marchi specifici, ma ad ambiti, anche se alcuni marchi dell'ambito non sono necessari.

2) Implementato le sovvenzioni necessarie

La parte successiva dell'integrazione OIDC è la selezione e l'implementazione dei tipi di autorizzazione, chiamati sovvenzioni. L'ulteriore scenario di interazione tra l'applicazione selezionata e il server di autorizzazione dipenderà dalla concessione selezionata. Uno schema approssimativo per la selezione della sovvenzione giusta è presentato nella figura seguente.

OpenID Connect: autorizzazione delle applicazioni interne da custom a standard

Per la nostra prima applicazione, abbiamo utilizzato la concessione più comune: il codice di autorizzazione. La sua differenza dagli altri è che è in tre fasi, cioè viene sottoposto a ulteriori test. Per prima cosa l'utente effettua una richiesta di permesso di autorizzazione, riceve un token del Codice di Autorizzazione, quindi con questo token, come con un biglietto di viaggio, richiede un token di accesso. Tutte le principali interazioni di questo scenario di autorizzazione si basano su reindirizzamenti tra l'applicazione e il server di autorizzazione. Puoi leggere di più su questa sovvenzione qui.

OAuth aderisce al concetto secondo cui i token di accesso ricevuti dopo l'autorizzazione dovrebbero essere temporanei e preferibilmente cambiare in media ogni 10 minuti. La concessione del Codice di autorizzazione è una verifica in tre passaggi tramite reindirizzamenti; eseguire un passaggio del genere ogni 10 minuti, francamente, non è il compito più piacevole per l'occhio. Per risolvere questo problema, esiste un'altra concessione: Refresh Token, che abbiamo utilizzato anche noi. Qui è tutto più semplice. Durante la verifica da un'altra concessione, oltre al token di accesso principale, ne viene rilasciato un altro: Refresh Token, che può essere utilizzato solo una volta e la sua durata, di norma, è significativamente più lunga. Con questo Refresh Token, al termine del TTL (Time to Live) del token di accesso principale, una richiesta per un nuovo token di accesso arriverà all'endpoint di un'altra concessione. Il Refresh Token utilizzato viene immediatamente azzerato. Questo controllo è in due fasi e può essere eseguito in background, senza che l'utente se ne accorga.

3) Formati di output dei dati utente configurati

Una volta implementate le sovvenzioni selezionate, l'autorizzazione funziona, vale la pena menzionare la ricezione dei dati dell'utente finale. OIDC dispone di un endpoint separato per questo, in cui puoi richiedere i dati dell'utente con il tuo token di accesso corrente e se è aggiornato. E se i dati utente non cambiano così spesso, ma devi cercare quelli attuali molte volte, puoi arrivare a una soluzione come i token JWT. Anche questi token sono supportati dallo standard. Il token JWT stesso è composto da tre parti: intestazione (informazioni sul token), payload (eventuali dati necessari) e firma (firma, il token è firmato dal server e in futuro sarà possibile verificare la fonte della sua firma).

Nell'implementazione OIDC, il token JWT è chiamato id_token. Può essere richiesto insieme ad un normale token di accesso e non resta che verificare la firma. A questo scopo, il server di autorizzazione dispone di un endpoint separato con un gruppo di chiavi pubbliche nel formato J.W.K.. E a questo proposito vale la pena ricordare che esiste un altro endpoint basato sullo standard RFC5785 riflette la configurazione corrente del server OIDC. Contiene tutti gli indirizzi degli endpoint (incluso l'indirizzo del keyring pubblico utilizzato per la firma), i timbri e gli ambiti supportati, gli algoritmi di crittografia utilizzati, le sovvenzioni supportate, ecc.

Ad esempio su Google:

{
 "issuer": "https://accounts.google.com",
 "authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
 "device_authorization_endpoint": "https://oauth2.googleapis.com/device/code",
 "token_endpoint": "https://oauth2.googleapis.com/token",
 "userinfo_endpoint": "https://openidconnect.googleapis.com/v1/userinfo",
 "revocation_endpoint": "https://oauth2.googleapis.com/revoke",
 "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
 "response_types_supported": [
  "code",
  "token",
  "id_token",
  "code token",
  "code id_token",
  "token id_token",
  "code token id_token",
  "none"
 ],
 "subject_types_supported": [
  "public"
 ],
 "id_token_signing_alg_values_supported": [
  "RS256"
 ],
 "scopes_supported": [
  "openid",
  "email",
  "profile"
 ],
 "token_endpoint_auth_methods_supported": [
  "client_secret_post",
  "client_secret_basic"
 ],
 "claims_supported": [
  "aud",
  "email",
  "email_verified",
  "exp",
  "family_name",
  "given_name",
  "iat",
  "iss",
  "locale",
  "name",
  "picture",
  "sub"
 ],
 "code_challenge_methods_supported": [
  "plain",
  "S256"
 ],
 "grant_types_supported": [
  "authorization_code",
  "refresh_token",
  "urn:ietf:params:oauth:grant-type:device_code",
  "urn:ietf:params:oauth:grant-type:jwt-bearer"
 ]
}

Pertanto, utilizzando id_token è possibile trasferire tutti i contrassegni necessari al payload del token e non contattare ogni volta il server di autorizzazione per richiedere i dati dell'utente. Lo svantaggio di questo approccio è che le modifiche ai dati utente dal server non avvengono immediatamente, ma insieme a un nuovo token di accesso.

Risultati dell'implementazione

Quindi, dopo aver implementato il nostro server OIDC e aver configurato le connessioni ad esso dal lato dell'applicazione, abbiamo risolto il problema della trasmissione delle informazioni dell'utente.
Poiché OIDC è uno standard aperto, ora abbiamo la possibilità di scegliere un provider esistente o un'implementazione server. Abbiamo provato Keycloak, che si è rivelato molto semplice da configurare; dopo aver impostato e modificato le configurazioni di connessione lato applicazione, è pronto per l'uso. Lato applicativo non resta che modificare le configurazioni di connessione.

Parlare di soluzioni esistenti

All'interno della nostra organizzazione, come primo server OIDC, abbiamo raccolto la nostra implementazione, che è stata integrata secondo necessità. Dopo un esame dettagliato di altre soluzioni già pronte, possiamo dire che questo è un punto controverso. La decisione di implementare un nostro server è stata dettata dalle preoccupazioni dei fornitori riguardo alla mancanza delle funzionalità necessarie, nonché dalla presenza di un vecchio sistema che conteneva varie autorizzazioni personalizzate per alcuni servizi e memorizzava già molti dati sui dipendenti . Tuttavia, nelle implementazioni già pronte, ci sono comodità per l'integrazione. Ad esempio, Keycloak ha un proprio sistema di gestione degli utenti e i dati vengono archiviati direttamente al suo interno e spostare i tuoi utenti lì non sarà difficile. A questo scopo, Keycloak dispone di un'API che ti consentirà di eseguire completamente tutte le azioni di trasferimento necessarie.

Un altro esempio di implementazione certificata, interessante, secondo me, è Ory Hydra. È interessante perché è composto da diversi componenti. Per l'integrazione, dovrai collegare il tuo servizio di gestione utenti al loro servizio di autorizzazione ed espanderlo secondo necessità.

Keycloak e Ory Hydra non sono le uniche soluzioni già pronte. È meglio selezionare un'implementazione certificata dalla OpenID Foundation. Queste soluzioni in genere dispongono di un badge di certificazione OpenID.

OpenID Connect: autorizzazione delle applicazioni interne da custom a standard

Inoltre, non dimenticare i fornitori a pagamento esistenti se non desideri mantenere il tuo server OIDC. Oggi ci sono molte buone opzioni.

Cosa c'è Next

Nel prossimo futuro chiuderemo il traffico verso i servizi interni in modo diverso. Stiamo pianificando di migrare il nostro attuale SSO sul bilanciatore utilizzando OpenResty su un proxy basato su OAuth. Ci sono anche molte soluzioni già pronte qui, ad esempio:
github.com/bitly/oauth2_proxy
github.com/ory/oathkeeper
github.com/keycloak/keycloak-gatekeeper

Materiali aggiuntivi

jwt.io – buon servizio per controllare i token JWT
openid.net/developers/certificato — elenco delle implementazioni OIDC certificate

Fonte: habr.com

Aggiungi un commento