OpenID Connect: Login mit OAuth, Teil 2: Identity-Federation und fortgeschrittene Themen

Mit den früher vorgestellten Funktionen von OpenID Connect sind die grundsätzlichen Anforderungen an ein Login und Single Sign-On auf einfache Art und Weise abgedeckt. Aber auch wenn die Anwendungsfälle komplizierter werden, hat OpenID Connect noch eine Menge zu bieten.

In Pocket speichern vorlesen Druckansicht
Lesezeit: 20 Min.
Von
  • Torsten Lodderstedt
Inhaltsverzeichnis

Mit den früher vorgestellten Funktionen von OpenID Connect sind die grundsätzlichen Anforderungen an ein Login und Single Sign-On auf einfache Art und Weise abgedeckt. Aber auch wenn die Anwendungsfälle komplizierter werden, hat OpenID Connect noch eine Menge zu bieten.

Bisher wurde immer davon ausgegangen, dass eine Anwendung zu einem bestimmten OpenID Provider (OP) gehört. Da OpenID ein standardisiertes Protokoll ist, ist es aber auch möglich, darüber andere Nutzer "anzuzapfen" (Sicht der Anwendung) beziehungsweise die Reichweite der eigenen Identitäten zu erhöhen (Sichtweise des OP bzw. des Benutzers).

Dafür sei als Beispiel vorgestellt, dass Max aus dem früheren Artikel sich auf dem Nachrichtenportal des Anbieters News Corp registrieren möchte. Da er keine Lust hat, sich einen neuen Account anzulegen, will er stattdessen seinen Account bei der Fun Corp, seinem E-Mail-Anbieter, verwenden. Der Vorteil für die News Corp besteht darin, dass ein solches 3rd Party Login eine direkte Registrierung und Nutzung des Dienstes ohne lästiges Double Opt-in für die E-Mail-Adresse erlaubt. Obwohl News Corp und Fun Corp keine Geschäftsbeziehung unterhalten, lässt sich das gewünschte Szenario mit OpenID Connect implementieren.

Zuerst muss der potenzielle Client (hier News Corp) den OpenID Provider (hier der Autorisierungsserver von Fun Corp) suchen und herausfinden, unter welchen URLs die Endpunkte exponiert werden und welche Fähigkeiten von OpenID Connect dieser unterstützt. Hierzu spezifiziert OpenID Connect das sogenannte OpenID Connect Discovery, bei dem sich der OP und dessen Metadaten unter Nutzung der E-Mail-Adresse (oder anderer Daten) des Benutzers finden lassen. Der Ablauf soll anhand des Beispiels aus dem ersten Artikel
veranschaulicht werden.

Max' E-Mail-Adresse lautet bekanntlich "m.mustermann@funcorp.com". News Corp leitet aus dem Domain-Teil der E-Mail-Adresse die Adresse "https://funcorp.com" ab und sendet an diese Adresse einen sogenannten WebFinger-Request:

GET /.well-known/webfinger
?resource=acct%3Am.mustermann%40funcorp.com
&rel=http%3A%2F%2Fopenid.net%2Fspecs%2Fconnect%2F1.0%2Fissuer
HTTP/1.1
Host: funcorp.com

Dabei wird im Parameter resource die E-Mail-Adresse als Identifier des betreffenden Benutzers übergeben. Da es sich bei WebFinger um einen generischen Internet-Dienst für das Bestimmen von Adressen handelt, bekommt der WebFinger-Server mit dem Parameter rel (Relation) mitgeteilt, dass der Client in diesem Fall an der sogenannten Issuer-URL des OpenID Provider der Fun Corp interessiert ist. Diese liefert der Server auch prompt in der entsprechenden HTTP Response:

HTTP/1.1 200 OK
Content-Type: application/jrd+json

{
"subject": "acct:joe@example.com",
"links":
[
{
"rel": "http://openid.net/specs/connect/1.0/issuer",
"href": "https://accounts.funcorp.com"
}
]
}

Die Response verwendet im Falle von WebFinger den Content Type application/jrd+json, wobei "jrd" für "JSON Resource Descriptor" steht. Im Response-Parameter href liefert der Server eine Issuer-URL wie im früheren Artikel. Dabei handelt es sich um die eindeutige ID des OP von Fun Corp, die auch die ID Tokens des betreffenden OP verwenden. OpenID Connect Discovery legt nun fest, dass unter dem Unterpfad /.well-known/openid-configuration eben dieser URL Metadaten über den OP zur Abfrage zur Verfügung zu stellen sind. Also sendet der Client einen entsprechenden Request an diese URL:

GET /.well-known/openid-configuration HTTP/1.1
Host: accounts.funcorp.com

Der Request liefert im Ergebnis ein Dokument mit den gesamten Metadaten des OpenID Providers von Fun Corp:

HTTP/1.1 200 OK
Content-Type: application/json

{
"issuer":
"https://accounts.funcorp.com",
"authorization_endpoint":
"https://accounts.funcorp.com/oauth/auth",
"token_endpoint":
"https://accounts.funcorp.com/oauth/token",
...
"userinfo_endpoint":
"https://accounts.funcorp.com/userinfo",
...
"jwks_uri":
"https://server.example.com/jwks.json",
"registration_endpoint":
"https://accounts.funcorp.com/connect/register",
"scopes_supported":
["openid", "profile", "email", "address",
"phone", "offline_access"],
"response_types_supported":
["code", "code id_token", "id_token", "token id_token"],
...
"display_values_supported":
["page", "popup"]
...
}

Dazu zählen insbesondere die verschiedenen Endpunkte (z. B. der zur Autorisierung im Wert authorization_endpoint), aber auch eine Liste der unterstützten Scope-Werte (scopes_supported/i]) und Response-Typen ([i]response_types). Auf Basis dieser Informationen kann der Client entscheiden, welche Requests er gegen welche URLs absetzen wird, um den Benutzer zu authentifizieren.