hitobito / hitobito_sac_cas

A hitobito wagon defining the organization hierarchy and additional features for SAC/CAS
Other
4 stars 1 forks source link

APP: Doorkeeper OIDC Anpassungen für prompt param und redirect_uri #1075

Open amaierhofer opened 1 month ago

amaierhofer commented 1 month ago

Aktuell funktioniert der OIDC Authorization Flow in der App nicht. Möglicherweise hängt es mit der von der App verwendenten PKCE Erweiterung zusammen.

Warum genau nach dem Login doorkeeper in die App zurück redirected (sacappdev://signin-oidc?error=login_required&error_description=The+authorization+server+requires+end-user+authentication&state=VL0uBHopjeSJ9I0MwevgwA) ist unklar.

Zum lokalen testen von oidc muss JWT_SIGNING_KEY gesetzt sein.

❯ openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
❯ JWT_SIGNING_KEY=private_key.pem rails s

Der prompt=login Parameter signalisiert, dass das der client sich neu anmelden will. Daher soll hitobito

  1. Bestehende Session invalidieren
  2. Zur login seite redirecten oder diese rendern
  3. Mit den request parameter vom client nach erfolgreichem Login wieder zum client zurück redirecten

Das default auf StoreLocationVerhalten basisierende redirect handling muss adaptiert werden, so dass nach einem abgefangenen authorization request und anschliessendem erfolgreichem Login, an die redirect_uri aus dem authorization request weitergeleitet und nicht an den abgefangenen (weil nicht authorisierten) authorization request selbst weitergeleitet wird.

amaierhofer commented 1 month ago

Bei Tests mit oidcdebugger.com scheint der PKCE Flow in Ordnung.

via applogin

{"method":"POST","path":"/en/users/sign_in","format":"html","controller":"Devise::Hitobito::SessionsController","action":"create","status":303,"allocations":39338,"duration":166.81,"view":0.0,"db":0.0,"location":"https://sac-cas.puzzle.ch/oauth/authorize","time":"2024-10-04 14:30:56 +0200","request_uuid":"e9d593ac-aba5-4b3b-a830-ce3c74bc5016","params":"{authenticity_token: '7hl1/6AyyOPpEP8QL0/X4Gee7iKE7iDJy1ga03SRv2k7PXvTKco01nM/I16NMg0PFqQQSFwq8BTaYVZyvSSg2g==', person: {login_identity: 'testubique2@ubique.ch', password: '[FILTERED]', remember_me: '0'}, button: '', oauth: 'true', locale: 'en'}","user_id":600520}
{"method":"GET","path":"/oauth/authorize","format":"html","controller":"Doorkeeper::AuthorizationsController","action":"new","status":302,"allocations":14527,"duration":43.46,"view":0.0,"db":0.0,"location":"sacappdev://signin-oidc","time":"2024-10-04 14:30:56 +0200","request_uuid":"f82a5a84-c31b-40f3-831a-da583709dde0","params":"{redirect_uri: 'sacappdev://signin-oidc', client_id: 'Ve1whYs5mHxHCUOSoD2fi6MG5jQN4PgeI9NWawE9Klg', response_type: 'code', prompt: 'login', ui_locales: 'en-GB de-CH nb-NO fr-CH it-CH', state: 'qlNYjf3C5mFAJc2e7nP_9g', nonce: 'cU8TF2WgFDuSF3cbtiyh8w', scope: 'openid', code_challenge: 'tWcE8HbXpGPvg0pdZoQXOV4Fcy6QqfXJcOL4fAfT3s4', code_challenge_method: 'S256', language: 'en'}","user_id":600520}

via oidcdebugger

{"method":"POST","path":"/de/users/sign_in","format":"html","controller":"Devise::Hitobito::SessionsController","action":"create","status":303,"allocations":32208,"duration":182.22,"view":0.0,"db":0.0,"location":"https://sac-cas.puzzle.ch/oauth/authorize","time":"2024-10-04 16:58:21 +0200","request_uuid":"06f20fd5-99bf-41be-b975-d3eeeebe992f","params":"{authenticity_token: 'F1NxCpJb/oKEasU3zePY28sR5JhtgjfpiFySgjEJeeYDh2OKsms6yZxP8Xa6YV4GDKoINCExYWQWeNxNW/B7Cw==', person: {login_identity: 'hitobito-sac-cas@puzzle.ch', password: '[FILTERED]', remember_me: '0'}, button: '', oauth: 'true', locale: 'de'}","user_id":600000}
{"method":"GET","path":"/oauth/authorize","format":"html","controller":"Doorkeeper::AuthorizationsController","action":"new","status":302,"allocations":17161,"duration":52.97,"view":0.0,"db":0.0,"location":"https://oidcdebugger.com/debug#code=F0rtuJBO0vgaqNL1UijimdyHDglaDFx7radIQSK-JQQ&state=8isbempx1sw","time":"2024-10-04 16:58:21 +0200","request_uuid":"9d156855-d395-47bd-95f3-16e4731f70f5","params":"{client_id: 'Ve1whYs5mHxHCUOSoD2fi6MG5jQN4PgeI9NWawE9Klg', redirect_uri: 'https://oidcdebugger.com/debug', scope: 'openid', response_type: 'code', response_mode: 'fragment', code_challenge_method: 'S256', code_challenge: 'g85KMxdScHJIMmEklWA6LI9_uamv_PyNiC-REcgjd2k', state: '8isbempx1sw', nonce: 'qpcyxr1cuc'}","user_id":600000}
{"method":"POST","path":"/oauth/token","format":"*/*","controller":"Doorkeeper::TokensController","action":"create","status":200,"allocations":14551,"duration":48.63,"view":0.25,"db":0.0,"time":"2024-10-04 16:58:22 +0200","request_uuid":null,"params":"{client_id: 'Ve1whYs5mHxHCUOSoD2fi6MG5jQN4PgeI9NWawE9Klg', code: '[FILTERED]', code_verifier: 'K1l6OgZ1P5w8IT1XeRaLZkZr7ADadYhvsPaoDI6lxgA', grant_type: 'authorization_code', redirect_uri: 'https://oidcdebugger.com/debug'}"}

Nebem dem request format existieren folgende Unterschiede bei den parametern im /oauth/authorize GET request

[6] pry(main)> app.keys - oidc.keys
=> [:prompt, :ui_locales, :language]
[7] pry(main)> oidc.keys - app.keys
=> [:response_mode]
amaierhofer commented 1 month ago

Problem scheint der prompt=login parameter,

curl 'http://localhost:3000/oauth/authorize?client_id=tb2cCp7jd7GqEZI2V1iEozJa_W_MargUBQ-ocnncHwE&code_challenge=tWcE8HbXpGPvg0pdZoQXOV4Fcy6QqfXJcOL4fAfT3s4&code_challenge_method=S256&language=en&nonce=cU8TF2WgFDuSF3cbtiyh8w&prompt=login&redirect_uri=sacappdev%3A%2F%2Fsignin-oidc&response_type=code&scope=openid&state=qlNYjf3C5mFAJc2e7nP_9g&ui_locales=en-GB+de-CH+nb-NO+fr-CH+it-CH'  -H 'Cookie: locale=en;  _session_id=a2809420e540d127da19276fe3c02589'
<html><body>You are being <a href="sacappdev://signin-oidc?error=login_required&amp;error_description=The+authorization+server+requires+end-user+authentication&amp;state=qlNYjf3C5mFAJc2e7nP_9g">redirected</a>.</body></html>

der produziert folgenden fehler

Started GET "/oauth/authorize?client_id=tb2cCp7jd7GqEZI2V1iEozJa_W_MargUBQ-ocnncHwE&code_challenge=tWcE8HbXpGPvg0pdZoQXOV4Fcy6QqfXJcOL4fAfT3s4&code_challenge_method=S256&language=en&nonce=cU8TF2WgFDuSF3cbtiyh8w&prompt=login&redirect_uri=sacappdev%3A%2F%2Fsignin-oidc&response_type=code&scope=openid&state=qlNYjf3C5mFAJc2e7nP_9g&ui_locales=en-GB+de-CH+nb-NO+fr-CH+it-CH" for 127.0.0.1 at 2024-10-08 10:52:40 +0200
Processing by Doorkeeper::AuthorizationsController#new as */*
  Parameters: {"client_id"=>"tb2cCp7jd7GqEZI2V1iEozJa_W_MargUBQ-ocnncHwE", "code_challenge"=>"tWcE8HbXpGPvg0pdZoQXOV4Fcy6QqfXJcOL4fAfT3s4", "code_challenge_method"=>"S256", "language"=>"en", "nonce"=>"cU8TF2WgFDuSF3cbtiyh8w", "prompt"=>"login", "redirect_uri"=>"sacappdev://signin-oidc", "response_type"=>"code", "scope"=>"openid", "state"=>"qlNYjf3C5mFAJc2e7nP_9g", "ui_locales"=>"en-GB de-CH nb-NO fr-CH it-CH"}
Redirected to sacappdev://signin-oidc?error=login_required&error_description=The+authorization+server+requires+end-user+authentication&state=qlNYjf3C5mFAJc2e7nP_9g
Filter chain halted as :authenticate_resource_owner! rendered or redirected
Completed 302 Found in 38ms (ActiveRecord: 0.0ms | Allocations: 37865)
amaierhofer commented 1 month ago

Scheinbar gibt es bisher keine Verwender für den optionale prompt=login Parameter. Brauchen wir den wirklich? Eventuell in Kombination mit max_age? Beides wird aktuell in hitobito nicht behandelt und die library defaults scheinen so nicht richtig bzw nicht app library kompatibel zu sein.

Siehe reauthenticate_resource_owner in https://github.com/doorkeeper-gem/doorkeeper-openid_connect und https://github.com/doorkeeper-gem/doorkeeper-openid_connect/blob/master/lib/doorkeeper/openid_connect/helpers/controller.rb#L16 für das authentication handling