OpenID Connect: autorisatie van interne applicaties van zelfgemaakt naar standaard

Enkele maanden geleden was ik bezig met de implementatie van een OpenID Connect-server voor het beheren van de toegang tot honderden van onze interne applicaties. Van onze eigen oplossingen, die handig waren op kleinere schaal, zijn we overgestapt naar een algemeen aanvaarde standaard. Toegang via een centrale service vereenvoudigt monotone taken aanzienlijk, vermindert de kosten voor het implementeren van autorisaties, maakt het mogelijk om veel kant-en-klare oplossingen te vinden en voorkomt dat je moet piekeren bij het ontwikkelen van nieuwe. In dit artikel zal ik vertellen over deze overgang en de problemen die we hebben ondervonden.

OpenID Connect: autorisatie van interne applicaties van zelfgemaakt naar standaard

Lang geleden… Hoe het allemaal begon

Enkele jaren geleden, toen er te veel interne applicaties waren om handmatig te beheren, schreven we een applicatie voor toegangcontrole binnen het bedrijf. Het was een eenvoudige Rails-applicatie die verbinding maakte met een database met informatie over medewerkers, waarin toegang tot verschillende functionaliteiten werd ingesteld. Toen hebben we de eerste SSO opgezet, die gebaseerd was op tokencontroles van de klant en de autorisatieserver; de token werd in gecodeerde vorm met verschillende parameters verzonden en gecontroleerd op de autorisatieserver. Dit was niet de handigste optie, omdat in elke interne applicatie aanzienlijk veel logica moest worden beschreven, terwijl de medewerkersdatabases helemaal niet gesynchroniseerd waren met de autorisatieserver.

Na enige tijd besloten we de taak van centrale autorisatie te vereenvoudigen. De SSO werd overgezet naar een load balancer. Met behulp van OpenResty op Lua hebben we een sjabloon toegevoegd dat de tokens controleerde, wist naar welke applicatie de aanvraag ging en kon controleren of daar toegang toe was. Deze aanpak vereenvoudigde de controle over de toegang tot interne applicaties aanzienlijk — in de code van elke applicatie hoefde geen extra logica te worden beschreven. Uiteindelijk hebben we de externe traffic afgesloten en wist de applicatie zelf niets van de autorisatie.

Echter, een van de problemen blijft onopgelost. Wat te doen met applicaties die informatie over werknemers nodig hebben? We zouden een API voor de autorisatieservice kunnen schrijven, maar dat zou betekenen dat we extra logica voor elk van die applicaties moesten toevoegen. Bovendien wilden we af van de afhankelijkheid van onze zelfgebouwde applicatie, die uiteindelijk is gericht op een vertaling naar OpenSource, van onze interne autorisatieserver. Daarover vertellen we later meer. De oplossing voor beide problemen werd OAuth.

Algemene standaarden

OAuth is een begrijpelijke, algemeen aanvaarde standaard voor autorisatie, maar omdat de functionaliteit ervan niet voldoende is, is ook OpenID Connect (OIDC) in overweging genomen. OIDC op zich is de derde implementatie van een open authenticatiestandaard, die voortvloeit uit een uitbreiding bovenop het OAuth 2.0 protocol (een open autorisatieprotocol). Deze oplossing sluit het probleem van het gebrek aan gegevens over de eindgebruiker op, en biedt de mogelijkheid om de autoriteitsprovider te wisselen.

We hebben echter geen specifieke provider gekozen en besloten om de integratie met OIDC aan onze bestaande autorisatieserver toe te voegen. Dit besluit werd genomen omdat OIDC erg flexibel is op het gebied van autorisatie van de eindgebruiker. Op deze manier was er de mogelijkheid om OIDC-ondersteuning op onze huidige autorisatieserver te implementeren.

OpenID Connect: autorisatie van interne applicaties van zelfgemaakt naar standaard

Onze weg naar de implementatie van een eigen OIDC-server

1) Gegevens in de juiste vorm gebracht

Voor de integratie van OIDC is het noodzakelijk om de huidige gegevens over gebruikers in een formaat te brengen dat begrijpelijk is voor de standaard. In OIDC worden deze Claims genoemd. Claims zijn in wezen de eindvelden in de gebruikersdatabase (naam, e-mail, telefoon, enzovoort). Er bestaat een standaardlijst van claims, en alles wat niet op deze lijst staat, wordt als custom beschouwd. Daarom is het eerste aandachtspunt, als je een bestaande OIDC-provider wilt kiezen, de mogelijkheid tot gemakkelijke aanpassing van nieuwe claims.

Een groep claims wordt samengevoegd in de volgende subset – Scope. Bij autorisatie wordt er geen toegang aangevraagd tot specifieke claims, maar juist tot scopes, ook al zijn sommige claims uit de scope niet nodig.

2) De benodigde grants geïmplementeerd

Het volgende deel van de OIDC-integratie is de keuze en implementatie van autorisatietypes, de zogenaamde grants. De gekozen grant bepaalt het verdere interactiescenario van de geselecteerde applicatie met de autorisatieserver. Een voorbeeldschema voor het kiezen van de juiste grant is hieronder weergegeven.

OpenID Connect: autorisatie van interne applicaties van zelfgemaakt naar standaard

Voor onze eerste applicatie hebben we de meest voorkomende grant gebruikt – de Authorization Code. Het kenmerk van deze grant ten opzichte van andere is dat het een driefaseprocedure is, wat betekent dat er een aanvullende controle plaatsvindt. Eerst vraagt de gebruiker om autorisatie, ontvangt een token – de Authorization Code, en vraagt vervolgens met deze token, als een vervoersbewijs, om een toegangstoken. Alle belangrijkste interacties in dit autorisatiescenario zijn gebaseerd op redirects tussen de applicatie en de autorisatieserver. Meer lezen over deze grant kan hier. hier.

OAuth volgt het principe dat toegangstokens, verkregen na autorisatie, tijdelijk moeten zijn en idealiter om de 10 minuten moeten worden gewijzigd. De Authorization Code grant is een driefasecontrole via redirects, elke 10 minuten zo'n stap herhalen is eerlijk gezegd niet de meest prettige bezigheid voor het oog. Voor dit probleem bestaat er nog een grant – de Refresh Token, die we ook in onze implementatie hebben gebruikt. Dit is eenvoudiger. Tijdens de controle met een andere grant wordt naast de hoofdtoegangstoken ook een andere – de Refresh Token – uitgegeven, die slechts één keer kan worden gebruikt en waarvan de levensduur doorgaans aanzienlijk langer is. Met deze Refresh Token, wanneer de TTL (Time to Live) van de hoofdtoegangstoken is verlopen, komt een verzoek voor een nieuw toegangstoken al op de endpoint van een andere grant. De gebruikte Refresh Token wordt onmiddellijk geannuleerd. Deze controle is tweeledig en kan op de achtergrond worden uitgevoerd, onopgemerkt door de gebruiker.

3) We hebben de uitvoerformaten van gebruikersgegevens ingesteld.

Nadat de geselecteerde subsidies zijn uitgevoerd, werkt de autorisatie en is het belangrijk om gegevens over de eindgebruiker te verkrijgen. In OIDC is er een aparte endpoint hiervoor, waar je met je actuele toegangstoken en mits dit geldig is, gegevens over gebruikers kunt opvragen. En als gebruikersgegevens niet zo vaak veranderen, maar je vaak actuele gegevens nodig hebt, kan je besluiten om JWT-tokens te gebruiken. Deze tokens worden ook ondersteund door de standaard. Een JWT-token zelf bestaat uit drie delen: header (informatie over de token), payload (de benodigde gegevens) en signature (de token wordt ondertekend door de server en later kan de bron van de ondertekening worden gecontroleerd).

In de implementatie van OIDC wordt de JWT-token id_token genoemd. Deze kan worden aangevraagd samen met de gewone toegangstoken en alles wat rest is de handtekening te controleren. De autorisatieserver heeft hiervoor een aparte endpoint met een set publieke sleutels in het formaat JWK. En wat dit betreft, is het belangrijk om te vermelden dat er nog een andere endpoint bestaat die op basis van de standaard RFC5785 de huidige configuratie van de OIDC-server weerspiegelt. Hierin staan alle adressen van endpoints (inclusief het adres van de set publieke sleutels die voor ondertekening wordt gebruikt), ondersteunde claims en scopes, gebruikte encryptie-algoritmes, ondersteunde subsidies, enzovoort.

Bijvoorbeeld bij 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"
 ]
}

Met behulp van het id_token kunnen alle benodigde claims in de payload van de token worden verzonden, zonder telkens de autorisatieserver te raadplegen voor gebruikersgegevens. Een nadeel van deze aanpak is dat wijzigingen in de gebruikersgegevens van de server niet onmiddellijk worden ontvangen, maar pas met de nieuwe toegangstoken.

Resultaten van de implementatie

Na de implementatie van onze eigen OIDC-server en het instellen van de verbindingen aan de applicatietoepassingen, hebben we het probleem van het doorgeven van informatie over gebruikers opgelost.
Aangezien OIDC een open standaard is, hebben we de mogelijkheid om een bestaande provider te kiezen of een server te implementeren. We hebben Keycloak geprobeerd, dat zeer gebruiksvriendelijk bleek te zijn in de configuratie. Na de installatie en aanpassing van de verbindingsconfiguraties aan de applicaties, is het klaar voor gebruik. Aan de applicatiezijde hoeft alleen nog de verbindingsconfiguratie te worden gewijzigd.

Over bestaande oplossingen gesproken

Binnen onze organisatie hebben we onze eigen implementatie als eerste OIDC-server gebouwd, die we naar behoefte hebben uitgebreid. Na een gedetailleerd onderzoek van andere kant-en-klare oplossingen, kan worden gezegd dat dit een discutabele kwestie is. De zorgen van providers over het ontbreken van de benodigde functionaliteit en het bestaan van een verouderd systeem met verschillende aangepaste autorisaties voor bepaalde diensten, waarin al vrij veel gegevens over werknemers zijn opgeslagen, hebben bijgedragen aan de keuze voor een eigen serveroplossing. Aan de andere kant bieden kant-en-klare implementaties gemak voor integratie. Bijvoorbeeld, Keycloak heeft zijn eigen gebruikersbeheersysteem en de gegevens worden daar opgeslagen, terwijl het niet moeilijk zal zijn om onze gebruikers daarheen over te zetten. Hiervoor beschikt Keycloak over een API die in staat stelt alle noodzakelijke acties voor de migratie volledig uit te voeren.

Een ander voorbeeld van een gecertificeerde, interessante implementatie is Ory Hydra. Het is interessant omdat het uit verschillende componenten bestaat. Voor integratie moet u uw gebruikersbeheerservice koppelen aan hun autorisatieservice en deze uitbreiden indien nodig.

Keycloak en Ory Hydra zijn niet de enige kant-en-klare oplossingen. Het is het beste om een gecertificeerde implementatie van de OpenID Foundation te kiezen. Dergelijke oplossingen hebben doorgaans een OpenID Certification-logo.

OpenID Connect: autorisatie van interne applicaties van zelfgemaakt naar standaard

Vergeet ook de bestaande betaalde aanbieders niet als je je OIDC-server niet zelf wilt hosten. Tegenwoordig zijn er veel goede opties beschikbaar.

Hier was eigenlijk een praktische sectie gepland met demonstratie van drie projecten op STM32 en STM8, speciaal voor dit artikel gemaakt met behulp van datasheets, met lampen, SPI, timers, PWM en interrupts:

In de nabije toekomst zijn we van plan om het verkeer naar interne services op een andere manier af te sluiten. We plannen om onze huidige SSO over te zetten naar een load balancer met OpenResty als proxy, gebaseerd op OAuth. Ook hier zijn er al veel kant-en-klare oplossingen, bijvoorbeeld:
github.com/bitly/oauth2_proxy
github.com/ory/oathkeeper
github.com/keycloak/keycloak-gatekeeper

Aanvullend materiaal

jwt.io – een goede service voor het controleren van JWT-tokens
openid.net/developers/certified — lijst van gecertificeerde implementaties van OIDC

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers 🔥 Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster