|
|
OAuth / OpenID Connect als Zentraler Anmeldedienst HIT/ZIDStand Sept 2024
Kurz und bündigBevor eine OAuth-Anfrage durchgeführt werden kann, müssen die Clients bei der Zentralen Datenbank registriert worden sein. Jeder Client (nicht der Benutzer!) wird durch seine Kennung, seine Antwort-URIs und ein Passwort authentifiziert. Dann kann damit nach dem OpenID Connect-Verfahren (kurz OIDC) zunächst eine Nutzerautorisierung und schließlich ein Access Token angefordert werden:
Neben diesen kann über OIDC Discovery in Erfahrung gebracht werden, welche URIs und Parameter die OIDC-Schnittstelle versteht: z.B. für Test-System. Es ist neben OIDC Core lediglich OIDC Session Management implemeniert. Keine der beiden Channel Logout-Mechanismen sind vorhanden. Registrierung ClientWichtiger Hinweis: Nur registrierte Clients können sich mit OAuth verbinden. Für eine Registrierung ist vorab eine Genehmigung durch den Vertreter des Landes in der BLAG/DZ erforderlich! Da wir (derzeit) eine Client-Registrierung weder per Webseite, noch per HIT-Protokoll, noch per OpenID Connect Dynamic Registration unterstützen, bitte formlos eine Email an ralph.reuchlein@hi-tier.de mit folgenden Angaben senden (einfach Tabelle ausfüllen, dann den "Email-Text erzeugen"-Knopf klicken und das erzeugte in die Email einfügen):
Wir tragen die per Email zugesandten Angaben manuell bei uns ein und Sie erhalten dann von
uns einen zufällig generierten String, der als Neu ab Februar 2022: die Schnittstelle wurde um eine Anmelde-Nutzergruppe,
eine Daten/Rechte-Freigabe und Angaben von Verantwortlichen erweitert
(siehe die letzten vier Felder im Formular oben). Diejenigen, die vor
Februar 2022 einen Client registriert haben (egal ob für Test,
Prodution oder Wartung), melden bitte die Angaben aus den vier
genannten Feldern formlos per Email unter der Angabe des Systems und der
Details zur ImplementierungAblaufDie OAuth-Autorisierung nach OIDC läuft in zwei Stufen ab:
Dadurch, dass der Authorization Code eingetauscht wird, ist sichergestellt, dass mögliche PIN-Angaben im Browser (in Schritt 2) dort verbleiben und der Client in Schritt 3 (und folgenden) keine Angaben zur Nutzer-PIN kennt. Es wird ein klassisches Session-Cookie mitgeführt, um mehrfache Authentifizierungen innerhalb kurzer Zeit zu ermöglichen, ohne sich jedesmal erneut anmelden zu müssen. Erkennt der ZAD ein erhaltenes Session-Cookie, wird sofort ein neuer Authorization Code an den Client zurückgesendet, ohne die Anmeldemaske des ZAD anzuzeigen. Ein explizites Abmelden des Anwenders ist daher auch implementiert, Details dazu siehe unten. Domains für OIDC-AnfragenDie Webserver von HIT sind unter der zentralen Domain Damit der Client sicher nur mit einer IP-Adresse arbeitet, muss dieser mit einer der folgenden Domainnamen arbeiten:
Es ist dringend anzuraten, im Client, der OIDC handhabt, alle genannten Domainnamen zu hinterlegen und bei jedem Authorization Request zufällig eine Domain auszuwählen und in sämtlichen URLs dieser Session zu verwenden. Der Tokentausch (Authorization Code zum Access Token)
muss mit der gleichen ausgewählten Domain wie beim Authorization Request
vorgenommen werden. In den
Beispielaufrufen der einzelnen Stufen unten ist somit der Platzhalter SystemeIn den folgenden beschriebenen Stufen wird die URI für unser Testsystem angegeben. Für die anderen Systeme lautet die Pfadangabe in der URI wie folgt:
(zum Platzhalter Eine Eintragung Ihres Clients in eines der Systeme setzt voraus, dass ein Vertreter des Landes in der Bund.-Länder-Arbeitsgruppe Direktzahlungen (BLAG/DZ) die Nutzung von OIDC genehmigt. Stufe 1: Authorization Code [AUC]Client-Anfrage an den HIT/ZID-Anmeldedienst mit HTTP GETDie URI für die Client-Anfrage (Schritt 1) ist Der Die Angaben für Die Der Optional: Technisch gesehen wird z.B. aus einer Webanwendung heraus ein Redirect an unseren Autorisierungsendpunkt (Schritt 1) abgesetzt: HTTP/1.1 302 Found Location: /HitTest3/zad_oauth/auth_req? scope=openid &response_type=code &client_id=45678R &redirect_uri=https%3A%2F%2Fwww.ihr-client.de%2Froute%2Fendpunkt &nonce=client.session.id &state=xsrf.blocker Host: www.hi-tier.de ( Überprüfung der QueryString-ParameterUnser Endpunkt überprüft auf Vorhandensein der übergebenen Parameter. Wenn nicht ausreichend, dann wird eine entsprechende JSON-Fehlerantwort gesendet. OIDC erlaubt weitere Angaben im Authentication Request, von
denen manche (z.B. Zuerst wird die Client-Angabe Wenn Client gültig, dann wird Wenn Client und Redirect-URI gültig, dann wird zusammen mit einem internen Token zur Anmeldemaske des Zentralen Anmeldedienstes weitergeleitet, auf der sich der Nutzer des Clients als HIT/ZID-Anwender authentifizieren muss (Schritt 2). Schlägt die Anmeldung fehl, kann der Anwender die Anmeldung wie bei der klassischen HIT-Webanwendung wiederholen, bis er angemeldet ist (weiterhin Schritt 2). Kann er sich aufgrund einer falschen PIN nicht anmelden oder ist er gesperrt, muss er über den Knopf "Abbrechen" zu OAuth zurückkehren. In dem Fall wird eine entsprechende JSON-Fehlerantwort gesendet (Schritt 3). Ist das Passwort eines Nutzers abgelaufen oder muss dieses wegen Neuzuteilung sofort geändert werden, dann wird der Nutzer auf eine Passwort-Änderungsseite weitergeleitet, auf dieser er sich unter Angabe seines bisherigen Passwortes ein neues Passwort vergeben kann. Ist dieser Vorgang erfolgreich, dann ist der Nutzer authorisiert und wird zu OAuth zurückgeleitet.
Beispiel Fehlerantwort, wenn Client nicht autorisiert (Schritt 3): HTTP/1.1 400 Bad Request Content-Type: application/json; charset=utf-8 Cache-Control: private Pragma: no-cache { "error": "invalid_request", "error_description": "OAuth-Anmeldung fehlgeschlagen - CLIENT_ID nicht gefunden", "nonce": "client.session.id", "state": "xsrf.blocker" } Erfolgreiche Anmeldung am HIT/ZID-AnmeldedienstNach erfolgreicher Anmeldung erzeugt der HitServer auf der selben Datenbankverbindung den Authorization Code für diesen Client und dessen Nutzer. Die Antwort-URI wird anhand Beispiel Fehlerantwort, wenn Client autorisiert, aber Nutzeranmeldung abgebrochen (Schritt 3): es wird ein Redirect an den von Ihnen registrierten Endpunkt veranlasst: https://www.ihr-client.de/route/endpunkt? error=unauthorized_client &error_description=Anmeldung+fehlgeschlagen:+Falsche+oder+fehlende+PIN &error_hit=224 &nonce=client.session.id &state=xsrf.blocker Im Schlüssel Beispiel Antwort nach erfolgreicher Anmeldung des Nutzers (Schritt 3): es wird ein Redirect an den von Ihnen registrierten Endpunkt veranlasst: HTTP/1.1 302 Found Location: https://www.ihr-client.de/route/endpunkt?code=ich.bin.der.lange.kurzlebige.auth.code&nonce=client.session.id&state=xsrf.blocker An keiner Stelle wird die PIN des Nutzers aus der Anmeldemaske des Zentralen Anmeldedienstes an den Client übermittelt. Da aber der Authorization Code und die PIN über HTTP-Client oder Webbrowser tranferiert wurden, muss dieser im nächsten Schritt ohne diese Clients durch einen Access Token ersetzt werden.
Stufe 2: Access Token [ACT]Client-Anfrage an den HIT/ZID-Anmeldedienst mit HTTP
|
entweder einen HTTP-Header Authorization mit dem
Schema Basic und Base64-encodetem
client_id:client_secret
mitsenden | |
oder client_id und client_secret als
Teil des querystring mitliefern |
Letzteres ist laut OAuth zulässig, wenn die Verbindung mit TLS verschlüsselt ist, was sie bei HIT/ZID grundsätzlich ist.
Eine POST-Anfrage mit Authorization
-Header (Schritt 4) sähe so aus:
POST /HitTest3/zad_oauth/token HTTP 1.1 Host: www.hi-tier.de Content-Type: application/x-www-form-urlencoded Authorization: Basic base64base64base64base64base64 grant_type=authorization_code &code=ich.bin.der.lange.kurzlebige.auth.code &redirect_uri=https%3A%2F%2Fwww.ihr-client.de%2Froute%2Fendpunkt
Die Angaben der Autorisierung werden geprüft. Im Fehlerfall wird eine entsprechende JSON-Fehlerantwort gesendet (Schritt 5).
Der Parameter grant_type
muss authorization_code
lauten. Falls nicht, wird eine entsprechende JSON-Fehlerantwort
gesendet (Schritt 5).
Wenn soweit korrekt, werden sämtliche Angaben gegen den HitServer geprüft. Bei fehlerhaften Angaben erhält man eine entsprechende JSON-Fehlerantwort (Schritt 5).
Eine Fehlerantwort bei falscher Client-ID (Schritt 5) sähe z.B. so aus:
HTTP/1.1 400 Bad Request Content-Type: application/json; charset=utf-8 Cache-Control: private Pragma: no-cache { "error": "invalid_client", "error_description": "Falsche Client-Credentials" }
Wenn erfolgreich, liefert der HitServer das Access Token ACT, optional das Refresh Token (RET), und für den Payload in Form eines ID-Token die Betriebsnummer und ggf. weitere Angaben je nach Daten-/Rechtefreigabe.
Aus diesen Angaben wird eine Datenstruktur (=Payload) für ein
ID-Token befüllt und als
JWT (=JSON Web Token) codiert,
dieses als
id_token
zusammen mit dem access_token
, ggf. dem
refresh_token
und weiteren
Angaben
als JSON-Antwort an den Client zurückgesendet (Schritt 5).
Der Client erhält im ID-Token zusätzlich zu den vorgegebenen
Schlüsseln lediglich bnr
und mbn
, da aus
Sicherheitsgründen gegenüber dem HitServer mit einer sehr beschränkten
Kompetenz auf der HIT-Datenbank gearbeitet wird. Möchte man mehr Daten
zum Betrieb erhalten, dann kann dies unter Zuhilfenahme des Access
Token z.B. über unsere REST-Schnittstelle abgefragt werden.
Eine erfolgreiche Antwort auf die Anforderung eines Access Tokens sieht so aus:
HTTP/1.1 200 OK Cache-Control: private Pragma: no-cache Content-Type: application/json; charset=utf-8 { "token_type": "Bearer", "access_token": "mit.mir.kann.man.sich.bei.HIT.autorisieren", "expires_in": 1200, "expires_at": 1576760000, "refresh_token": "wenn.ACT.abgelaufen.nimm.mich", "id_token": "eyJhbGciOiJub25lIn0=.codiertesJWT." }
Die Angabe expires_at
(=Anzahl Sekunden seit Unix Epoch
am 01.01.1970 0 Uhr UTC) ist die einzige ausserhalb der
OIDC-Spezifikation, korreliert aber direkt mit expires_in
:
es ist der Zeitpunkt, an dem das ACT abgelaufen sein wird.
Das gelieferte ID-Token (der Payload) enthält in jedem Fall
die Standard-OIDC-Claims "iss
" (Issuer), "sub
"
(Subject), "aud
" (Audience), "iat
"
(Issued at), "exp
" (Expires at) und wenn
vorhanden auch "nonce
".
HIT/ZID-spezifisch werden immer "bnr
" und "mbn
"
geliefert und je nach Daten-/Rechte-Freigabe zusätzlich: "typ_betr
"
(als Array), "name_betr
", "adresse_betr
".
Siehe Formular oben zu den Details.
Der Inhalt von Feld access_token
kann nun für die Dauer
von expires_in
Sekunden als Identifikation, als PIN-Ersatz oder als Session-Key verwendet werden.
Als Identifikation genügt der bloße "Besitz" dieses Tokens - damit lässt sich ein Benutzer eindeutig identifizieren.
Darüber hinaus kann das Token -derzeit nur im Test!- in
Kombination mit Betriebsnummer und Mitbenutzerkennung zur Anmeldung
verwendet werden.
Beispiel: Login mit Access Token statt PIN
*1:XS:LOGON/BNR15;MELD_WG;TIMEOUT;OI_C_ID;OI_TOKEN:09 000 000 0001;3;1200;45678R;mit.mir.kann.man.sich.bei.HIT.autorisieren
Die Angabe des Clients OI_C_ID
ist hierbei zusätzlich
erforderlich, um alle von diesem Client zur Betriebsnummer vergebenen
Access Token
zu löschen, falls jemand mehrmals durch
Ausprobieren dieses Token "erraten" möchte. Damit wird verhindert, dass
der Betrieb für die PIN-Anmeldung gesperrt wird.
Im REST-Interface von HIT3 gibt des optional die Parameter cid
(für die Client ID) und act
(für das Access Token), die
statt der Angabe einer Nutzer-PIN verwendet werden können. Auf die
Angabe des act
kann verzichtet werden, wenn das Token als
HTTP-Header Authorization
und dem Schema Bearer
(und nicht als klassisches Basic
-Schema) mitgesendet wird.
Die Clients, die bei der Registrierung (siehe oben) angegeben
haben, dass sie ein refresh_token
nutzen wollen, erhalten dieses
auch in Stufe 2 zusammen mit dem Access Token geliefert.
Das Refresh Token dient dazu, ein abgelaufenes oder auch noch gültiges Access Token zu erneuern.
POST
Die URI für die Client-Anfrage (Schritt 4) ist https://DOMAIN/HitTest3/zad_oauth/token
Da eine HTTP POST
-Anfrage zwingend ist, enthält der
HTTP-Content (nicht die URI) dieser Anfrage einen
querystring
,
der aus grant_type=refresh_token&refresh_token=XXX&scope=openid
besteht.
Der Content-Type
dafür ist application/x-www-form-urlencoded
.
Der HTTP POST
-Request muss autorisiert sein, d.h.
entweder einen HTTP-Header Authorization mit dem
Schema Basic und Base64-encodetem
client_id:client_secret
mitsenden | |
oder client_id und client_secret als
Teil des querystring mitliefern |
Letzteres ist laut OAuth zulässig, wenn die Verbindung mit TLS verschlüsselt ist, was sie bei HIT/ZID grundsätzlich ist.
Eine POST-Anfrage mit Authorization
-Header (Schritt 4) sähe so aus:
POST /HitTest3/zad_oauth/token HTTP 1.1 Host: www.hi-tier.de Content-Type: application/x-www-form-urlencoded Authorization: Basic base64base64base64base64base64 grant_type=refresh_token &scope=openid &refresh_token=wenn.ACT.abgelaufen.nimm.mich
Die Angaben der Autorisierung werden geprüft. Im Fehlerfall wird eine entsprechende JSON-Fehlerantwort gesendet (Schritt 5).
Der Parameter grant_type
muss refresh_token
lauten, auch scope
ist vorgegeben. Falls nicht, wird eine
entsprechende JSON-Fehlerantwort gesendet (Schritt 5).
Wenn soweit korrekt, werden sämtliche Angaben gegen den HitServer geprüft. Bei fehlerhaften Angaben erhält man eine entsprechende JSON-Fehlerantwort (Schritt 5). Auch, wenn das Refesh Token selbst bereits abgelaufen ist.
Wenn erfolgreich, wird mit dem neuen Access Token (das bisherige wird gelöscht, wenn noch gültig)
eine Antwort gebildet.
Weitere Angaben für z.B. ein neues ID-Token werden nicht
ermittelt (also kein "frisches" Payload).
Eine Fehlerantwort bei falscher Client-ID (Schritt 5) sähe so aus:
HTTP/1.1 400 Bad Request Content-Type: application/json; charset=utf-8 Cache-Control: private Pragma: no-cache { "error": "invalid_client", "error_description": "Falsche Client-Credentials" }
Eine einfache JSON-Antwort mit dem neuen Access Token, dem bekannten Refresh Token und dessen Gültigkeitsdauer wird erzeugt und geliefert (Schritt 5).
Beispiel:
HTTP/1.1 200 OK Cache-Control: private Pragma: no-cache Content-Type: application/json; charset=utf-8 { "token_type": "Bearer", "access_token": "ich.bin.ab.jetzt.zustaendig.fuer.HIT", "expires_in": 1200, "expires_at": 1576777777, "refresh_token": "wenn.ACT.abgelaufen.nimm.mich" }
Nach erfolgreicher Anmeldung in der Anmeldemaske des Zentralen Anmeldedienstes wird ein klassisches Session-Cookie gesetzt, das einen Nutzer für die nächsten 20 Minuten authentifiziert. Nach einem erfolgreichen Austausch des Authorization Code in ein Access Token ändert sich diese Laufzeit auf die bei der Registrierung des Clients gewünschte Laufzeit des Access Tokens.
Wird in der Zeit, in der die Session besteht, ein neuer Authorization Request
versendet, erhält man einen neuen Authorization Code, ohne sich neu anmelden zu müssen.
Damit diese Session vorzeitig beendet werden kann, z.B. wenn die Sitzung nicht
mehr benötigt wird oder ein anderer Nutzer sich anmelden möchte, gibt es den
end_session_endpoint mit der URI: https://DOMAIN/HitTest3/zad_oauth/let_me_go
Die URI besitzt drei Parameter, keiner davon ist zwingend:
id_token_hint : das erhaltende ID-Token kann als
Hinweisgeber für eine Sitzung mitgesendet werden, um inbesondere nach Ablauf
der Session dennoch geordnet per Redirect zurückkehren zu können | |
post_logout_redirect_uri : dies ist das gewünschte Ziel zum
Rückkehren per Redirect. Dieses muss angegeben werden, wenn bei der
Registrierung mehr als nur ein Rückkehrziel angegeben wurde! | |
state : ein für den Client zum Schutz vor XSRF interessanter
Status, der durchgeschleift wird. Sollte state nicht zum Client
gehören, weil ein Dritter den Logout durchführt, findet der Logout dennoch
statt. |
Weder das OpenID Connect Front-Channel Logout noch das OpenID Connect Back-Channel Logout sind hier implementiert!
Stimmen Parameter nicht oder passt das ID-Token nicht zur Session oder kann die Weiterleitungs-URI nicht eindeutig bestimmt werden, erhält man eine JSON-Antwort als Fehlermeldung.
..