OpenID Connect: godkendelse af interne applikationer fra brugerdefinerede til standard

For nogle måneder siden arbejdede jeg på at implementere en OpenID Connect-server til at håndtere adgangen til hundrede af vores interne applikationer. Fra egne løsninger, der fungerede godt i mindre skala, gik vi over til en anerkendt standard. Adgang gennem en central service forenkler de monotone operationer betydeligt, reducerer omkostningerne ved at implementere autoriseringer, muliggør adgangen til mange færdige løsninger og sparer en for hovedpiner ved udvikling af nye. I denne artikel vil jeg fortælle om denne overgang og om de bumps, vi har fået undervejs.

OpenID Connect: godkendelse af interne applikationer fra brugerdefinerede til standard

For længe siden… Hvordan det hele begyndte

For flere år siden, da der blev for mange interne applikationer til manuel styring, skrev vi en applikation til kontrol af adgange inden for virksomheden. Det var en enkel Rails-applikation, der blev tilsluttet en database med information om medarbejdere, hvor adgangen til forskellige funktioner blev konfigureret. På det tidspunkt opsatte vi også vores første SSO, som var baseret på kontrol af tokens mellem klienten og autorisationsserveren; tokenet blev sendt i krypteret form med flere parametre og blev verificeret på autorisationsserveren. Dette var ikke den mest bekvemme løsning, da hver intern applikation skulle have beskrevet et betydeligt lag af logik, og medarbejderdatabaserne blev slet ikke synkroniseret med autorisationsserveren.

Efter nogen tid besluttede vi at forenkle opgaven med centraliseret autorisation. SSO blev flyttet til en load balancer. Ved hjælp af OpenResty på Lua tilføjede vi en skabelon, der kontrollerede tokens, vidste, hvilken applikation anmodningen gik til, og kunne tjekke, om der var adgang dertil. Denne tilgang forenklede opgaven med kontrol af adgange til interne applikationer betydeligt — i koden for hver applikation var det ikke længere nødvendigt at beskrive yderligere logik. I sidste ende lukkede vi trafik udad, og selve applikationen vidste intet om autorisation.

Men en af problemerne forbliver uløst. Hvad med de applikationer, der har brug for information om medarbejdere? Man kunne have skrevet et API til autoriseringstjenesten, men så skulle der tilføjes ekstra logik til hver enkelt applikation. Desuden ønskede vi at fjerne afhængigheden fra en af vores egne applikationer, der i fremtiden ville blive konverteret til OpenSource, fra vores interne autoriseringsserver. Det vil vi fortælle om en anden gang. Løsningen på begge problemer blev OAuth.

De almindeligt accepterede standarder

OAuth er en klar, almindeligt accepteret standard for autorisation, men da denne funktionalitet ikke var tilstrækkelig, begyndte man også at overveje OpenID Connect (OIDC). OIDC er i sig selv den tredje implementering af en åben autentificeringsstandard, som bygger oven på OAuth 2.0-protokollen (den åbne autorisationsprotokol). Denne løsning løser problemet med manglende data om slutbrugeren og giver mulighed for at skifte autorisationsudbyder.

Men vi valgte ikke en specifik udbyder og besluttede at tilføje integration med OIDC til vores eksisterende autoriseringsserver. Fordelen ved denne løsning var, at OIDC er meget fleksibel med hensyn til slutbrugerens autorisation. Dermed var det muligt at implementere OIDC-support på vores nuværende autoriseringsserver.

OpenID Connect: godkendelse af interne applikationer fra brugerdefinerede til standard

Vores vej til implementering af en egen OIDC-server

1) Klargjorde data i det ønskede format

For at integrere OIDC er det nødvendigt at bringe de nuværende brugerdata i en form, der er forståelig for standarden. I OIDC kaldes dette Claims. Claims er i princippet de endelige felter i databasen om brugerne (navn, email, telefon osv.). Der findes en standardliste over claims, og alt hvad der ikke er inkluderet i denne liste, betragtes som brugerdefineret. Derfor er det første punkt, man skal være opmærksom på, hvis man vil vælge en eksisterende OIDC-udbyder – muligheden for nem tilpasning af nye claims.

Gruppen af claims samles i følgende undergruppe – Scope. Ved autorisation anmodes der ikke om adgang til specifikke claims, men netop til scopes, selvom en del af claims'ene fra scopet ikke er nødvendige.

2) Implementerede de nødvendige grants

Den næste del af OIDC-integrationen er valget og implementeringen af autorisationstyper, de såkaldte grants. Den valgte grant vil afgøre det videre scenarie for interaktion mellem den valgte applikation og autorisationsserveren. Et eksempel på, hvordan man vælger den rigtige grant, er vist i diagrammet nedenfor.

OpenID Connect: godkendelse af interne applikationer fra brugerdefinerede til standard

Til vores første applikation brugte vi den mest udbredte grant - Authorization Code. Forskellen fra de andre er, at den er tredelt, dvs. den gennemgår en ekstra kontrol. Først anmoder brugeren om autorisationstilladelse, får en token - Authorization Code, og derefter anmoder han med denne token, ligesom med en billet, om en adgangstoken. Al hovedinteraktion i dette autorisationsscenarie er baseret på redirects mellem applikationen og autorisationsserveren. Du kan læse mere om denne grant her.

OAuth følger konceptet om, at adgangstokener, der opnås efter autorisation, skal være midlertidige og ændres helst hver 10. minut. Authorization Code-granten er en tredelt kontrol gennem redirects, og at gennemføre et sådant skridt hver 10. minut er, ærligt talt, ikke den mest behagelige opgave. For at løse dette problem findes der en anden grant - Refresh Token, som vi også har anvendt. Her er alt enklere. Under kontrollen med en anden grant gives der, ud over den primære adgangstoken, også en anden - Refresh Token, som kun kan bruges én gang, og dens levetid er som regel betydeligt længere. Med denne Refresh Token, når TTL (Time to Live) for den primære adgangstoken udløber, vil anmodningen om en ny adgangstoken komme til endpointet for en anden grant. Den anvendte Refresh Token nulstilles straks. Denne kontrol er totrins og kan udføres i baggrunden, næsten uset af brugeren.

3) Vi har konfigureret outputformaterne for brugerdata

Når de valgte tilskud er implementeret, fungerer godkendelsen, så lad os nævne indhentning af data om slutbrugeren. I OIDC er der en separat endpoint til dette, hvor man med sin nuværende adgangstoken, så længe den er gyldig, kan anmode om brugerdata. Og hvis brugerdata ikke ændrer sig så ofte, men det er nødvendigt at hente de nuværende mange gange, kan man komme frem til en løsning som JWT-tokens. Disse tokens understøttes også af standarden. Selve JWT-tokenet består af tre dele: header (oplysninger om tokenet), payload (enhver nødvendig data) og signature (tokenet underskrives af serveren, og kilden til denne signatur kan verificeres).

I implementeringen af OIDC kaldes JWT-token id_token. Det kan anmodes sammen med den almindelige adgangstoken, og alt hvad der er tilbage er at verificere signaturen. Serveren for godkendelse har en separat endpoint til dette med et sæt af offentlige nøgler i formatet JWK. Og i den forbindelse bør det nævnes, at der også findes en anden endpoint, der baseret på standarden RFC5785 afspejler den aktuelle konfiguration af OIDC-serveren. Den indeholder alle adresser på endpoints (inklusiv adressen for det sæt af offentlige nøgler, der bruges til signatur), understøttede claims og scopes, anvendte krypteringsmetoder, understøttede tilskud osv.

For eksempel hos 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"
 ]
}

Med id_token kan man således overføre alle nødvendige claims i tokenets payload uden at skulle kontakte autorisationsserveren hver gang for at anmode om brugerdata. Ulempen ved denne tilgang er, at ændringer i brugerdata fra serveren ikke kommer med det samme, men først med det nye adgangstoken.

Resultater af implementeringen

Så efter at have implementeret vores egen OIDC-server og konfigureret forbindelser til den fra applikationssiden, har vi løst problemet med at overføre information om brugerne.
Da OIDC er en åben standard, har vi haft mulighed for at vælge en eksisterende udbyder eller implementere serveren selv. Vi prøvede Keycloak, som viste sig at være meget praktisk at konfigurere; efter opsætning og ændring af forbindelseskonfigurationerne i applikationerne var den klar til brug. I applikationerne skal man kun ændre forbindelseskonfigurationerne.

Når vi taler om eksisterende løsninger

I vores organisation opbyggede vi vores egen implementering som den første OIDC-server, som blev suppleres efter behov. Efter nøje overvejelse af andre eksisterende løsninger kan det siges, at dette er et omstridt emne. At implementere vores egen server blev motiveret af bekymringer fra leverandørerne om mangel på nødvendig funktionalitet og eksistensen af et gammelt system, hvor der var forskellige brugerdefinerede godkendelser for nogle tjenester, samt et stort antal data om medarbejderne, der allerede var gemt. Dog indeholder de færdige løsninger bekvemme integrationsmuligheder. For eksempel har Keycloak sit eget brugerstyringssystem, og dataene gemmes direkte der; det er ikke svært at migrere sine brugere dertil. Til dette har Keycloak et API, der muliggør alle nødvendige handlinger for overførsel.

Et andet eksempel på en certificeret, interessant implementering — Ory Hydra. Den er interessant, fordi den består af forskellige komponenter. For integrationen skal du forbinde dit brugerstyringssystem med deres autorisationstjeneste og udvide efter behov.

Keycloak og Ory Hydra er ikke de eneste færdige løsninger. Det er bedst at vælge en certificeret OpenID Foundation-implementering. Sådanne løsninger har normalt et OpenID-certificeringssymbol.

OpenID Connect: godkendelse af interne applikationer fra brugerdefinerede til standard

Husk også de eksisterende betalte udbydere, hvis du ikke ønsker at drive din egen OIDC-server. I dag er der mange gode muligheder.

vil være udsolgt

I den nærmeste fremtid planlægger vi at lukke trafikken til interne tjenester på en anden måde. Vi planlægger at migrere vores nuværende SSO til en balanceret løsning med OpenResty baseret på en proxy, der understøtter OAuth. Der findes allerede mange færdige løsninger, for eksempel:
github.com/bitly/oauth2_proxy
github.com/ory/oathkeeper
github.com/keycloak/keycloak-gatekeeper

Yderligere materialer

jwt.io – en god tjeneste til validering af JWT-tokens
openid.net/developers/certified — en liste over certificerede implementeringer af OIDC

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster