For et par måneder siden implementerede jeg en OpenID Connect-server til at administrere adgang til hundredvis af vores interne applikationer. Fra vores egen udvikling, praktisk i mindre skala, er vi gået over til en almindeligt accepteret standard. Adgang gennem den centrale service forenkler i høj grad monotone operationer, reducerer omkostningerne ved at implementere autorisationer, giver dig mulighed for at finde mange færdige løsninger og ikke rack din hjerne, når du udvikler nye. I denne artikel vil jeg tale om denne overgang og de bump, som vi formåede at udfylde.
For lang tid siden... Hvordan det hele begyndte
For nogle år siden, da der var for mange interne applikationer til manuel kontrol, skrev vi en applikation til at kontrollere adgangen i virksomheden. Det var en simpel Rails-applikation, der koblede sig til en database med information om medarbejdere, hvor der var konfigureret adgang til forskellige funktioner. Samtidig rejste vi den første SSO, som var baseret på verifikation af tokens fra siden af klienten og autorisationsserveren, tokenet blev transmitteret i krypteret form med flere parametre og verificeret på autorisationsserveren. Dette var ikke den mest bekvemme mulighed, da hver intern applikation skulle beskrive et betydeligt lag af logik, og medarbejderdatabaserne var fuldstændig synkroniseret med autorisationsserveren.
Efter nogen tid besluttede vi at forenkle opgaven med centraliseret autorisation. SSO blev overført til balanceren. Ved hjælp af OpenResty blev der tilføjet en skabelon til Lua, der tjekkede tokens, vidste hvilken applikation anmodningen skulle til og kunne tjekke om der var adgang der. Denne tilgang forenklede i høj grad opgaven med at kontrollere adgangen til interne applikationer - i koden for hver applikation var det ikke længere nødvendigt at beskrive yderligere logik. Det resulterede i, at vi lukkede trafikken eksternt, og selve applikationen vidste ikke noget om autorisation.
Et problem forblev dog uløst. Hvad med applikationer, der har brug for information om medarbejdere? Det var muligt at skrive en API til autorisationstjenesten, men så skulle du tilføje yderligere logik for hver sådan applikation. Derudover ønskede vi at slippe af med afhængigheden af en af vores selvskrevne applikationer, som senere skulle blive oversat til OpenSource, på vores interne autorisationsserver. Vi vil tale om det en anden gang. Løsningen på begge problemer var OAuth.
til fælles standarder
OAuth er en forståelig, generelt accepteret autorisationsstandard, men da kun dens funktionalitet ikke er nok, begyndte de straks at overveje OpenID Connect (OIDC). OIDC i sig selv er den tredje implementering af den åbne godkendelsesstandard, som er strømmet ind i en tilføjelse over OAuth 2.0-protokollen (en åben godkendelsesprotokol). Denne løsning lukker problemet med manglen på data om slutbrugeren, og gør det også muligt at skifte autorisationsudbyder.
Vi valgte dog ikke en specifik udbyder og besluttede at tilføje integration med OIDC til vores eksisterende godkendelsesserver. Til fordel for denne beslutning var det faktum, at OIDC er meget fleksibel med hensyn til slutbrugerautorisation. Det var således muligt at implementere OIDC-understøttelse på din nuværende autorisationsserver.
Vores måde at implementere vores egen OIDC-server på
1) Bragte dataene til den ønskede form
For at integrere OIDC er det nødvendigt at bringe de aktuelle brugerdata i en form, der kan forstås af standarden. I OIDC kaldes dette for krav. Påstande er i det væsentlige sidste felter i brugerdatabasen (navn, e-mail, telefon osv.). Eksisterer
Gruppen af kendetegn kombineres i følgende undergruppe - Omfang. Under autorisation anmodes der ikke om adgang til specifikke mærker, men til scopes, selvom nogle af mærkerne fra scopet ikke er nødvendige.
2) Gennemført de nødvendige bevillinger
Den næste del af OIDC integration er udvælgelse og implementering af autorisationstyper, de såkaldte grants. Det yderligere scenarie for interaktion mellem den valgte applikation og autorisationsserveren vil afhænge af den valgte bevilling. En eksemplarisk ordning for valg af det rigtige tilskud er vist i nedenstående figur.
Til vores første ansøgning brugte vi den mest almindelige bevilling, autorisationskoden. Dens forskel fra andre er, at det er et tre-trin, dvs. gennemgår yderligere test. Først laver brugeren en anmodning om autorisationstilladelse, modtager et token - Autorisationskode, og derefter med dette token, som med en rejsebillet, anmoder han om et adgangstoken. Al hovedinteraktionen i dette autorisationsscript er baseret på omdirigeringer mellem applikationen og autorisationsserveren. Du kan læse mere om denne bevilling
OAuth følger konceptet om, at adgangstokens, der opnås efter godkendelse, skal være midlertidige og bør ændres, helst hvert 10. minut i gennemsnit. Godkendelseskodebevillingen er en tre-trins verifikation gennem omdirigeringer, hvert 10. minut at dreje et sådant trin, ærligt talt, er ikke den mest behagelige opgave for øjnene. For at løse dette problem er der en anden bevilling - Refresh Token, som vi også brugte i vores land. Alt er nemmere her. Under verifikation fra en anden bevilling udstedes der ud over hovedadgangstokenet endnu et - Refresh Token, som kun kan bruges én gang, og dets levetid er normalt meget længere. Med dette Refresh Token, når TTL (Time to Live) for hovedadgangstokenet slutter, vil anmodningen om et nyt adgangstoken komme til endepunktet for en anden bevilling. Det brugte Refresh Token nulstilles øjeblikkeligt. Denne kontrol er to-trins og kan udføres i baggrunden, umærkeligt for brugeren.
3) Konfigurer brugerdefinerede dataoutputformater
Efter at de udvalgte bevillinger er implementeret, virker autorisation, det er værd at nævne at få data om slutbrugeren. OIDC har et separat slutpunkt til dette, hvor du kan anmode om brugerdata med dit nuværende adgangstoken og om det er opdateret. Og hvis brugerens data ikke ændrer sig så ofte, og du skal følge de nuværende mange gange, kan du komme til en løsning som JWT-tokens. Disse tokens understøttes også af standarden. Selve JWT-tokenet består af tre dele: header (information om tokenet), nyttelast (eventuelt nødvendige data) og signatur (signatur, tokenet er underskrevet af serveren, og du kan senere tjekke kilden til dets signatur).
I OIDC-implementeringen kaldes JWT-tokenet id_token. Det kan anmodes om sammen med et almindeligt adgangstoken, og det eneste, der er tilbage, er at bekræfte signaturen. Autorisationsserveren har et separat slutpunkt til dette med en masse offentlige nøgler i formatet
For eksempel på 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"
]
}
Ved at bruge id_token kan du således overføre alle de nødvendige kendetegn til tokenets nyttelast og ikke kontakte autorisationsserveren hver gang for at anmode om brugerdata. Ulempen ved denne tilgang er, at ændringen i brugerdata fra serveren ikke kommer med det samme, men sammen med et nyt adgangstoken.
Implementeringsresultater
Så efter at have implementeret vores egen OIDC-server og konfigureret forbindelser til den på applikationssiden, løste vi problemet med at overføre oplysninger om brugere.
Da OIDC er en åben standard, har vi mulighed for at vælge en eksisterende udbyder eller serverimplementering. Vi prøvede Keycloak, som viste sig at være meget praktisk at konfigurere, efter opsætning og ændring af forbindelseskonfigurationer på applikationssiden er den klar til at gå. På applikationssiden er der kun tilbage at ændre forbindelseskonfigurationerne.
Taler om eksisterende løsninger
Inden for vores organisation, som den første OIDC-server, samlede vi vores egen implementering, som blev suppleret efter behov. Efter en detaljeret gennemgang af andre færdige løsninger, kan vi sige, at dette er et problem. Til fordel for beslutningen om at implementere deres egen server var der bekymringer fra udbydernes side i mangel af den nødvendige funktionalitet, samt tilstedeværelsen af et gammelt system, hvor der var forskellige tilpassede autorisationer for nogle tjenester og en hel del af data om medarbejdere allerede var gemt. Men i færdige implementeringer er der bekvemmeligheder for integration. Keycloak har fx sit eget brugerstyringssystem og data gemmes direkte i det, og det vil ikke være svært at overhale dine brugere der. For at gøre dette har Keycloak en API, der giver dig mulighed for fuldt ud at udføre alle de nødvendige overførselshandlinger.
Et andet eksempel på en certificeret, interessant, efter min mening, implementering er Ory Hydra. Det er interessant, fordi det består af forskellige komponenter. For at integrere skal du forbinde din brugeradministrationstjeneste til deres autorisationstjeneste og udvide efter behov.
Keycloak og Ory Hydra er ikke de eneste hyldeløsninger. Det er bedst at vælge en implementering certificeret af OpenID Foundation. Disse løsninger har normalt et OpenID-certificeringsmærke.
Glem heller ikke eksisterende betalte udbydere, hvis du ikke ønsker at beholde din OIDC-server. I dag er der mange gode muligheder.
Hvad er næste
I den nærmeste fremtid kommer vi til at lukke trafikken til interne tjenester på en anden måde. Vi planlægger at overføre vores nuværende SSO på balanceren ved hjælp af OpenResty til en proxy baseret på OAuth. Der er allerede mange færdige løsninger her, f.eks.
Yderligere materialer
Kilde: www.habr.com