OAuth Identificatie

 
09 juli 2013

Voor een interne webapplicatie willen we OAuth gebruiken: een autorisatieprotocol voor het web dat ons de zorg om wachtwoorden uit handen neemt. De werking van OAuth wordt kort uitgelegd en van de implementatie een klein verslagje gedaan.

Bij de Sogyo Academy loopt op het moment een project met als doel om een intranetapplicatie te vernieuwen. De oude variant draait in het netwerk waar hij wordt geconsumeerd, maar de nieuwe willen wij het liefst deployen op een cloudplatform. De oorspronkelijke keuze voor LDAP zou dan vereisen dat de LDAP vanaf het publieke internet toegankelijk zou zijn. Dat doen we liever niet. Daarom onderzoek ik, terwijl ik deze post schrijf, hoe wij de authenticatie anders kunnen regelen. Het ‘intranet’ van Sogyo ‘bevat’ namelijk ook de Google Apps (gmail, calendar, …). Dit kan ook gebruikt worden om gebruikers te identificeren, namelijk met OAuth (2.0) authenticatie.

OAuth is een authorisatieprotocol voor het web. Dat komt goed uit, want hoewel dit stukje “identificatie” in de titel heeft, is identificatie namelijk niet wat wij nodig hebben. Wat wij willen, is onze gebruikers authoriseren, niet meer en niet minder. Dat betekent ook dat wij ons geen zorgen hoeven te maken over exact hoe de gebruiker zich identificeert. Zelfs zonder wachtwoord inloggen wordt dan een mogelijkheid, als de eindgebruiker zich recent heeft geidentificeerd bij Google. Het moet nog even blijken, maar het ziet er tot dusver appetijtelijk uit.

De werking van OAuth

OAuth definieert vier rollen:

Resource owner
De entiteit die toegang kan geven tot een beschermde resource. In ons geval: de eindgebruiker die zich wel identificeren.
Resource server
De server die de beschermde resource host. Deze is in staat om met requests en responses te werken met behulp van access tokens.
Client
De applicatie die namens de resource owner en met toestemming van de resource owner requests uitvoert. Voor de specificatie maakt het niet uit, maar bij ons is het dus een webapplicatie.
Authorization server
De server die access tokens uitgeeft nadat deze de resource owner heeft geidentificeerd en geautoriseerd. Deze tokens worden gegeven aan de client.

Tussen de rollen kunnen de volgende interacties plaatsvinden:

+--------+                               +-----------------+
|        |--(A)- Authorization Request ->|    Resource     |
|        |                               |      Owner      |
|        |<-(B)-- Authorization Grant ---| = Eindgebruiker |
|        |                               +-----------------+
|        |
|        |                               +-----------------+
|        |--(C)-- Authorization Grant -->|  Authorization  |
| Client |                               |      Server     |
|        |<-(D)----- Access Token -------| = Google        |
|  = de  |                               +-----------------+
| webapp |
|        |                               +-----------------+
|        |--(E)----- Access Token ------>|     Resource    |
|        |                               |      Server     |
|        |<-(F)--- Protected Resource ---| = Google        |
+--------+                               +-----------------+

(naar RFC 6749)

De Authorization Grant kan verschillende vormen hebben. Volgens de specificatie kan deze bijvoorbeeld bestaan uit de username en password. Deze gegevens worden ‘ingewisseld’ voor een Access Token, die gebruikt kan worden voor de rest van de conversatie met de Resource Server.

Deze manier werkt, maar is niet ideaal. Het wachtwoord moet namelijk worden doorgegeven door de Client. Dat is niet nodig en vormt een risico.

De specificatie gaat namelijk nog een stapje verder om dit schema te verbeteren. In plaats van een username en password door de Client te laten passeren, kan er als Authorization Grant een Authorization Code worden verstuurd. In plaats van een wachtwoord dus. Dit wordt bereikt door de eindgebruiker eerst door te sturen (met (A)) naar een pagina van de Authorization Server. Wanneer de Authorization Server akkoord gaat, stuurt deze de eindgebruiker met een Authorization Code door naar de Client, en bewerkstelligt zo (B).

Het is eventjes pittig om de termen uit elkaar te houden, en als bonus houdt onze Java OAuth library weer nieuwe termen aan.

Java Client

Voor Java zijn verschillende OAuth client libraries te vinden. Zo is er bijvoorbeeld

Wij kiezen voor Scribe, omdat deze vanaf oauth.net als volwassen wordt aangeduid, en makkelijk in het gebruik is.

Op github is een eenvoudig voorbeeld te vinden. Het is een console applicatie, dus er zal nog wat aanpassing nodig zijn. Hij werkte wel meteen, al had ik gehoopt op een niet-werkende redirect in plaats van een copy-paste code.

Na openen van de door het voorbeeld gegeven link

Na openen van de door het voorbeeld gegeven link

Na klikken op “Toegang verlenen”

Na klikken op “Toegang verlenen”

Na het invoeren van de code in de console applicatie, kon deze inderdaad een xml file opvragen met daarin een lijstje van documenten. Nu willen we eigenlijk alleen nog “anonymous” vervangen door onze applicatienaam, en in plaats van een code te presenteren, willen we een automatische redirect naar de applicatie.

Webapplicatie

De volgende stap is om te gaan werken met API keys. Hiermee kunnen Google en de eindgebruiker zien naar wie de gegevens toe moeten gaan. Keys kunnen verkregen worden op code.google.com. Hier kun je bij linkermenu “API Access” klikken op “Create an OAuth 2.0 client ID…”. In het getoonde dialoogje kun je vervolgens een naam en homepage URL en logo URL opgeven. Daarna kun je de URL opgeven die gebruikt moet worden voor redirects (en eventueel JavaScript). Vervolgens wordt op een pagina alle informatie getoond.

Om het interessant te houden is er hier een verschil in naamgeving. Waar je Scribe een API key kan geven, moet namelijk de Client Secret worden gegeven. De API key zoals Scribe dat noemt, is de Client ID van Google.

Zo is de authorisatiepagina is al wat vriendelijker geworden.

Met een API key

Met een API key

De callback-pagina kan worden ingesteld met ServiceBuilder.callback(url). De scope zetten we op https://www.googleapis.com/auth/userinfo.profile en vervolgens valt met de access token op https://www.googleapis.com/oauth2/v3/userinfo een JSON documentje uit te lezen met de gezochte informatie.

{
 "sub": "103655028397460982",
 "name": "John Doe",
 "given_name": "John",
 "family_name": "Doe",
 "picture": "https://lh5.googleusercontent.com/[...]/photo.jpg",
 "locale": "nl"
}

Voorbeeld van https://www.googleapis.com/oauth2/v3/userinfo

Puntjes op de ι

Zo hebben we dus genoeg voor een werkende identificatie. Verder zou het leuk zijn als de applicatienaam zoals we die eigenlijk hebben ingesteld ook wordt getoond. Nu wordt namelijk nog een onbegrijpelijk google-adres getoond (813132871300-d31ql6fdpl22l1c24sciir58felepmvc.apps.googleusercontent.com). Hier hebben we nog geen oplossing voor gevonden.

Wel hebben we ontdekt dat aan de google authorisatiepagina een hd parameter kan worden meegegeven. Hiermee kan worden aangegeven wat voor account we willen, bijvoorbeeld een sogyo.nl account. Dit werkt alleen ook nog niet. Waarschijnlijk is er nog een handeling nodig waardoor de site beter geverifieerd kan worden door Google, maar iets dergelijks hebben wij nog niet kunnen vinden. Het helpt overigens wel om de hd parameters op default te zetten. Dat scheelt op zijn minst twee redirects in de browser, en als de gebruiker met twee google accounts is ingelogd, wordt de default account gekozen en kan de gebruiker op de pagina alsnog de andere kiezen. Anders wordt er eerst nog een pagina getoond om de account te kiezen.


Werken met ?
Kijk dan bij onze mogelijkheden voor zowel starters als ervaren engineers.


Categorieën: Development, Java (EE)

Tags: , , , , ,