SURFconext OpenID Connect voor dummies

SURFconext gebruikt al jaren het SAML-protocol om single sign-on mogelijk te maken: met één gebruikersnaam en wachtwoord inloggen bij verschillende diensten. Sinds 2017 ondersteunt SURFconext ook OpenID Connect (OIDC), een relatief nieuw protocol,  specifiek ontworpen voor mobiele apps en API's. In deze blogpost doe ik de basisbegrippen uit de doeken en laat ik zie hoe het loginproces met OIDC bij SURFconext werkt.

Een kleine disclaimer

Deze blogpost is vooral bedoeld om een beter begrip te krijgen van de werking van OpenID Connect in de context van SURFconext, en niet bedoeld als leidraad om je eigen implementatie te schrijven. Daarvoor is het verstandiger om een bestaande implementatie te gebruiken. De OpenID Foundation heeft een uitgebreide lijst met client software voor als je aan de slag wil met OIDC.

SAML & OIDC: beide federatieve authenticatieprotocollen

In essentie lijken SAML en OIDC op elkaar: het zijn allebei zogenaamde "federatieve" authenticatie protocollen, en binnen SURFconext hebben beide protocollen ook dezelfde functionaliteiten.  Federatief betekent dat het systeem waar de identiteit van de gebruiker opgeslagen is, niet hetzelfde is als de online dienst waar de gebruiker op inlogt.  Hierbij vertrouwt de online dienst erop dat de gegevens over de identiteit van de gebruiker correct zijn. Dankzij dergelijke federatieve authenticatieprotocollen kunnen online diensten en gebruikers op gestandaardiseerde wijze veilig met elkaar communiceren.

Verschillen tussen SAML en OIDC

Dit zijn een aantal belangrijke verschillen tussen SAML en OIDC:

  • SAML (of in ieder geval de subset die SURFconext ondersteunt) handelt het berichtenverkeer, met daarin de authenticatiegegevens van de gebruiker, volledig in de browser af. Bij OIDC worden ook berichten rechtstreeks uitgewisseld tussen de online dienst en de server met de identiteitsgegevens van de gebruiker, dus buiten de browser van de gebruiker om. 

  • SAML is gebaseerd op het berichtformaat XML; OIDC op het berichtformaat JSON.  

  • OIDC een relatief nieuw protocol: het bestaat officieel sinds 2014, terwijl SAML 2.0 al sinds 2005 bestaat. Dat betekent ook dat OIDC nog volop in ontwikkeling is.

  • OIDC is specifiek ontworpen voor een wereld met mobiele apps en API's en bouwt voort op weer een andere standaard, OAuth2. Voor meer informatie over het OAuth2-protocol verwijs ik graag naar de blogpost OAuth voor beginners.

Een paar begrippen

Voordat we verder in het loginproces duiken bij OpenID Connect, licht ik eerst een paar begrippen toe:

Relying Party (RP)

De Relying Party is de online dienst waarop een gebruiker wil inloggen. De vergelijkbare term in SAML is Service Provider (SP). Binnen OIDC kan een RP een webapplicatie zijn, maar bijvoorbeeld ook een mobiele app.

OpenID Connect Provider (OP)

Binnen OIDC is de OP de server die het authenticatieverzoek van de RP afhandelt, en de identiteitsgegevens van de gebruiker levert aan de RP.

Access token

Een access token wordt door de OP uitgegeven aan de RP, nadat een gebruiker succesvol is ingelogd bij SURFconext en fungeert als een wachtwoord met een geldigheidsduur. Als dit is verlopen moet een gebruiker opnieuw inloggen om een nieuw access token te verkrijgen. Tijdens het inloggen bij de RP wordt deze gebruikt om extra gegevens van de gebruiker op te halen bij de OP.

ID token

Een ID token bevat informatie over de authenticatie van de gebruiker, bijvoorbeeld een unieke identifier, het tijdstip van de authenticatie en wie de authenticatie heeft verzorgd. Het ID token wordt in het gestandaardiseerde formaat JSON Web Token (JWT) aangeleverd door de OP aan de RP. In de SURFconext OpenID Connect-implementatie is het access token ook in JWT-formaat. Een dienst behoort het access_token echter als te beschouwen als een willekeurige reeks, zoals bij een wachtwoord.   

Voorbeeld van een ID token:

voorbeeld jwt token

Het ID token bevat veel informatie:

  • aud: audience, de applicatie waaraan het token is uitgedeeld.

  • sub: subject, de zogenaamde identifier van de gebruiker; een unieke reeks cijfers en letters waarmee iedere gebruiker uniek wordt geïdentificeerd.

  • nbf: not before, dit token is niet geldig voor deze datum.

  • iss: issuer, de partij die het token heeft uitgegeven.

  • exp: expiry, dit token is geldig tot uiterlijk dit tijdstip. Het formaat is een Unix timestamp. 

  • iat: issued at, het tijdstip waarop dit token is uitgegeven.

  • nonce: een nonce is eenmalig wachtwoord, bedoeld om de ervoor te zorgen dat de twee verzoeken die de RP moet doen tijdens het login proces met elkaar te verbinden. De RP kan hiermee verifiëren dat het uitgegeven ID token behoort bij het oorspronkelijke loginverzoek.

  • jti: een unieke identifier voor het token.

Claims

Claims bevatten extra informatie over een gebruiker. Binnen SAML worden deze gegevens attributen genoemd. Bekijk een volledig overzicht van alle attributen/claims die door SURFconext worden ondersteund.

Redirect URL

Als een RP zich registreert bij SURFconext, dan geeft hij daarbij een redirect URL op. Dat is de URL van de RP waar de OP de (eenmalige) code naartoe stuurt na authenticatie van de gebruiker. De redirect URL kan vergeleken worden met de Assertion Consumer Service (ACS) URL in de SAML-wereld. De RP krijgt vervolgens een clientID en een secret, waarmee deze zichzelf kan identificeren. 

Hoe werkt het loginproces met OpenID Connect?

Het OIDC-protocol ondersteunt verschillende zogenaamde flows om te kunnen inloggen. Een flow definieert de manier waarop de server, de client en de webbrowser van de gebruiker interacteren. Ik bespreek hier de flow die in vrijwel alle gevallen wordt gebruikt: de code flow. De overige twee flows, implicit en hybrid flow worden veel minder vaak toegepast. SURFconext ondersteunt ze alleen om applicaties die geen code flow ondersteunen, toch te kunnen laten authenticeren. 

OpenID Connect login flow

Stap 1

Een gebruiker wil inloggen bij een RP die is aangesloten op SURFconext.

Stap 2

De RP stuurt de gebruiker via zijn browser naar de OP met een verzoek om de gebruiker te authenticeren. Dat HTTP-verzoek ziet er zo uit:

response_type=code&
scope=openid&
client_id=url.van.de.client&
redirect_uri=https://url.van.de.client/redirect

Stap 3

De OP stuurt de gebruiker vervolgens door naar SURFconext om in te loggen. De instellingen zijn via SAML aangesloten op SURFconext. De OP bij SURFconext vertaalt dus het OIDC-verzoek naar een SAML-verzoek. Hoe dat SAML-proces verloopt, lees je in ons blog SAML voor Dummies. We nemen hier aan dat de gebruiker succesvol inlogt bij de instelling en daarna terugkeert bij SURFconext die de gebruiker dan weer doorstuurt naar de OP.

Stap 4

SURFconext authenticeert en stuurt de gebruiker terug naar de OP.

Stap 5

De OP stuurt de gebruiker via zijn browser terug naar de RP, naar de redirect URL. De OP voegt een URL GET-parameter toe waarin de authorisation code wordt vermeld; deze fungeert als eenmalig wachtwoord waarmee de RP het access token en het ID token kan ophalen bij de OP. Met die tokens kan de RP de gebruiker authenticeren. Dat verzoek ziet er zo uit:

GET https://url.van.de.client/redirect?
code=XQPLUkB4x4ei

Stap 6

De RP ontvangt de authorisation code en genereert een verzoek richting de OP om de code in te wisselen voor een access token en een ID token. Daarbij identificeert de RP zichzelf bij de OP met de bij de registratie verkregen clientID en het bijbehorende secret. Deze communicatie verloopt nu rechtstreeks tussen de RP en de OP en niet meer via de browser van de gebruiker, waardoor access token en het ID token niet kunnen worden onderschept of misbruikt. Dat is belangrijk want met een access token kun je direct gegevens over een gebruiker opvragen bij bijvoorbeeld een API. Alleen de authorisation code is te zien door de browser van de gebruiker. Deze code is alleen bruikbaar voor een RP die zich kan identificeren met zijn clientID en secret.

POST /oidc/token HTTP/1.1
grant_type=authorization_code&
code=XQPLUkB4x4ei&
redirect_uri=https://url.van.de.client/redirect&
client_id=url.van.de.client&
client_secret=secret

Stap 7

De OP ontvangt de authorisation code. De OP controleert of de code geldig is, en of deze hoort bij het oorspronkelijke autorisatieverzoek, dat de RP deed in stap 6. De OP antwoordt met een access token en een ID token. Deze zijn alleen zichtbaar voor de RP, en komen niet in de browser van de gebruiker.

access_token en id_token response

In principe is de gebruiker nu ingelogd en weet de RP wie de gebruiker is. Maar vaak zijn extra gegevens over de gebruiker nodig, de claims. Om deze te verkrijgen, doorloopt de RP ook de stappen 8 t/m 10.

Stap 8

De RP kan nu met het verkregen access token de claims (attributen) van de gebruiker ophalen bij de OP. Het access token fungeert daarbij als een wachtwoord. Ook deze stap vindt dus plaats buiten de browser van de gebruiker. Het in stap 7 verkregen ID token bevat informatie over de identiteit van de gebruiker (het subject) en informatie over de authenticatie zelf, bijvoorbeeld het tijdstip van de authenticatie. 

GET /oidc/userinfo
"Authorization: Bearer een_lange_string"

Stap 9

De OP controleert of het access token geldig is. Daarna antwoordt de OP:

userinfo endpoint reply

Stap 10

De RP ontvangt de claims en de login is hiermee afgerond.

Aan de slag!

Er is een playgroundapplicatie waar je kunt experimenteren met SURFconext OpenID Connect. Naast de hierboven beschreven code flow kunnen ook de overige flows worden getest. Verder zijn alle geavanceerde features die de SURFconext OpenID Connect gateway ondersteunt ook te testen in deze playground, zoals bijvoorbeeld PKCE, en de claims requested-parameter. 

Naast het mogelijk maken van een reguliere login, is het met OpenID Connect (of eigenlijk het onderliggende OAuth2-protocol) ook mogelijk om API’s af te schermen. Mocht je daar verder mee aan de slag willen, of meer vragen hebben naar aanleiding van deze blogpost, neem dan contact op met het SURFconext-team, via info@surfconext.nl.

Author

Ik ben technisch product manager bij SURFconext en bij SURFmailfilter.

Bart Geesink

Comments

Dit artikel heeft 0 reacties