CSRF-Problem in der Entwicklung mit dem 'Discourse OpenID Connect'-Plugin

Ich habe fünf oder sechs Wochen damit verbracht, Discourses SSO einzurichten, und dabei auf einige Probleme gestoßen. Jetzt blockiert mich ein Problem. Ich werde dieses Problem so detailliert wie möglich dokumentieren.

Entwicklungsumgebung

  • Ubuntu 22 auf VMware
  • Discourse 3.2.0.beta2-dev
    • Server läuft auf 127.0.0.1:3000
    • Ember-CLI läuft auf 127.0.0.1:4200
    • Installation von Discourse auf Ubuntu oder Debian für die Entwicklung
    • Deaktivierte Plugins:
      • Presence
      • Chat
      • Narrative Bot
    • Verwendung des Plugins Discourse OpenID Connect, um Keycloak basierend auf OIDC zu verbinden; Keycloak fungiert als Identitätsanbieter für Discourse
      • OIDC-Konfiguration auf Discourse OpenID Connect:
        • OpenID Connect-Entdeckungs-Dokument: http://127.0.0.1:8080/realms/mediawiki-realm/.well-known/openid-configuration
        • OpenID Connect-Client-ID: mydiscourse
        • OpenID Connect-Client-Geheimnis: O9A8zQuOn1bfpsWD89U8ULwYf6ooDu73
  • SSO-Anbieter Keycloak 22.0.4
    • Läuft auf 127.0.0.1:8080
    • OIDC-Konfiguration auf Keycloak:
      • Gültige Redirect-URIs: http://127.0.0.1:3000/auth/oidc/callback
      • Client-Geheimnis: O9A8zQuOn1bfpsWD89U8ULwYf6ooDu73
  • Chrome-Version 118.0.5993.70

Reproduktionsprozess

Anmeldung mit OIDC

Discourse leitet zu Keycloak weiter, Benutzerdaten in Keycloak eingeben

CSRF

Logs


//

//

//

// Anwendungsnachverfolgung

lib/middleware/omniauth_bypass_middleware.rb:53:in `call'
lib/content_security_policy/middleware.rb:12:in `call'
lib/middleware/gtm_script_nonce_injector.rb:10:in `call'
config/initializers/100-quiet_logger.rb:20:in `call'
config/initializers/100-silence_logger.rb:29:in `call'
lib/middleware/missing_avatars.rb:22:in `call'
lib/middleware/turbo_dev.rb:31:in `call'

// Framework-Nachverfolgung

omniauth (1.9.2) lib/omniauth/failure_endpoint.rb:25:in `raise_out!'
omniauth (1.9.2) lib/omniauth/failure_endpoint.rb:20:in `call'
omniauth (1.9.2) lib/omniauth/failure_endpoint.rb:12:in `call'
omniauth (1.9.2) lib/omniauth/strategy.rb:491:in `fail!'
/home/hardway/Downloads/omniauth-oauth2/lib/omniauth/strategies/oauth2.rb:88:in `callback_phase'
plugins/discourse-openid-connect/lib/omniauth_open_id_connect.rb:142:in `callback_phase'
omniauth (1.9.2) lib/omniauth/strategy.rb:238:in `callback_call'
omniauth (1.9.2) lib/omniauth/strategy.rb:189:in `call!'
omniauth (1.9.2) lib/omniauth/strategy.rb:169:in `call'
omniauth (1.9.2) lib/omniauth/strategy.rb:192:in `call!'
omniauth (1.9.2) lib/omniauth/strategy.rb:169:in `call'
omniauth (1.9.2) lib/omniauth/strategy.rb:192:in `call!'
omniauth (1.9.2) lib/omniauth/strategy.rb:169:in `call'
omniauth (1.9.2) lib/omniauth/strategy.rb:192:in `call!'
omniauth (1.9.2) lib/omniauth/strategy.rb:169:in `call'
omniauth (1.9.2) lib/omniauth/strategy.rb:192:in `call!'
omniauth (1.9.2) lib/omniauth/strategy.rb:169:in `call'
omniauth (1.9.2) lib/omniauth/strategy.rb:192:in `call!'
omniauth (1.9.2) lib/omniauth/strategy.rb:169:in `call'
omniauth (1.9.2) lib/omniauth/builder.rb:45:in `call'
rack (2.2.8) lib/rack/tempfile_reaper.rb:15:in `call'
rack (2.2.8) lib/rack/conditional_get.rb:27:in `call'
rack (2.2.8) lib/rack/head.rb:12:in `call'
actionpack (7.0.7) lib/action_dispatch/http/permissions_policy.rb:38:in `call'
rack (2.2.8) lib/rack/session/abstract/id.rb:266:in `context'
rack (2.2.8) lib/rack/session/abstract/id.rb:260:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/cookies.rb:704:in `call'
activerecord (7.0.7) lib/active_record/migration.rb:603:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport (7.0.7) lib/active_support/callbacks.rb:99:in `run_callbacks'
actionpack (7.0.7) lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/actionable_exceptions.rb:17:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/debug_exceptions.rb:28:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/show_exceptions.rb:29:in `call'
logster (2.13.0) lib/logster/middleware/reporter.rb:40:in `call'
railties (7.0.7) lib/rails/rack/logger.rb:40:in `call_app'
railties (7.0.7) lib/rails/rack/logger.rb:27:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/remote_ip.rb:93:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/request_id.rb:26:in `call'
rack (2.2.8) lib/rack/method_override.rb:24:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/static.rb:23:in `call'
rack (2.2.8) lib/rack/sendfile.rb:110:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/host_authorization.rb:137:in `call'
rack-mini-profiler (3.1.1) lib/mini_profiler.rb:413:in `call'
message_bus (4.3.8) lib/message_bus/rack/middleware.rb:60:in `call'
railties (7.0.7) lib/rails/engine.rb:530:in `call'
railties (7.0.7) lib/rails/railtie.rb:226:in `public_send'
railties (7.0.7) lib/rails/railtie.rb:226:in `method_missing'
rack (2.2.8) lib/rack/urlmap.rb:74:in `block in call'
rack (2.2.8) lib/rack/urlmap.rb:58:in `each'
rack (2.2.8) lib/rack/urlmap.rb:58:in `call'
unicorn (6.1.0) lib/unicorn/http_server.rb:634:in `process_client'
unicorn (6.1.0) lib/unicorn/http_server.rb:739:in `worker_loop'
unicorn (6.1.0) lib/unicorn/http_server.rb:547:in `spawn_missing_workers'
unicorn (6.1.0) lib/unicorn/http_server.rb:143:in `start'
unicorn (6.1.0) bin/unicorn:128:in `<top (required)>'
bin/unicorn:96:in `load'
bin/unicorn:96:in `block in <main>'
bin/unicorn:95:in `fork'
bin/unicorn:95:in `<main>'

// Vollständige Nachverfolgung

omniauth (1.9.2) lib/omniauth/failure_endpoint.rb:25:in `raise_out!'
omniauth (1.9.2) lib/omniauth/failure_endpoint.rb:20:in `call'
omniauth (1.9.2) lib/omniauth/failure_endpoint.rb:12:in `call'
omniauth (1.9.2) lib/omniauth/strategy.rb:491:in `fail!'
/home/hardway/Downloads/omniauth-oauth2/lib/omniauth/strategies/oauth2.rb:88:in `callback_phase'
plugins/discourse-openid-connect/lib/omniauth_open_id_connect.rb:142:in `callback_phase'
omniauth (1.9.2) lib/omniauth/strategy.rb:238:in `callback_call'
omniauth (1.9.2) lib/omniauth/strategy.rb:189:in `call!'
omniauth (1.9.2) lib/omniauth/strategy.rb:169:in `call'
omniauth (1.9.2) lib/omniauth/strategy.rb:192:in `call!'
omniauth (1.9.2) lib/omniauth/strategy.rb:169:in `call'
omniauth (1.9.2) lib/omniauth/strategy.rb:192:in `call!'
omniauth (1.9.2) lib/omniauth/strategy.rb:169:in `call'
omniauth (1.9.2) lib/omniauth/strategy.rb:192:in `call!'
omniauth (1.9.2) lib/omniauth/strategy.rb:169:in `call'
omniauth (1.9.2) lib/omniauth/strategy.rb:192:in `call!'
omniauth (1.9.2) lib/omniauth/strategy.rb:169:in `call'
omniauth (1.9.2) lib/omniauth/strategy.rb:192:in `call!'
omniauth (1.9.2) lib/omniauth/strategy.rb:169:in `call'
omniauth (1.9.2) lib/omniauth/builder.rb:45:in `call'
lib/middleware/omniauth_bypass_middleware.rb:53:in `call'
rack (2.2.8) lib/rack/tempfile_reaper.rb:15:in `call'
rack (2.2.8) lib/rack/conditional_get.rb:27:in `call'
rack (2.2.8) lib/rack/head.rb:12:in `call'
actionpack (7.0.7) lib/action_dispatch/http/permissions_policy.rb:38:in `call'
lib/content_security_policy/middleware.rb:12:in `call'
lib/middleware/gtm_script_nonce_injector.rb:10:in `call'
rack (2.2.8) lib/rack/session/abstract/id.rb:266:in `context'
rack (2.2.8) lib/rack/session/abstract/id.rb:260:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/cookies.rb:704:in `call'
activerecord (7.0.7) lib/active_record/migration.rb:603:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport (7.0.7) lib/active_support/callbacks.rb:99:in `run_callbacks'
actionpack (7.0.7) lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/actionable_exceptions.rb:17:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/debug_exceptions.rb:28:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/show_exceptions.rb:29:in `call'
logster (2.13.0) lib/logster/middleware/reporter.rb:40:in `call'
railties (7.0.7) lib/rails/rack/logger.rb:40:in `call_app'
railties (7.0.7) lib/rails/rack/logger.rb:27:in `call'
config/initializers/100-quiet_logger.rb:20:in `call'
config/initializers/100-silence_logger.rb:29:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/remote_ip.rb:93:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/request_id.rb:26:in `call'
rack (2.2.8) lib/rack/method_override.rb:24:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/static.rb:23:in `call'
rack (2.2.8) lib/rack/sendfile.rb:110:in `call'
actionpack (7.0.7) lib/action_dispatch/middleware/host_authorization.rb:137:in `call'
lib/middleware/missing_avatars.rb:22:in `call'
lib/middleware/turbo_dev.rb:31:in `call'
rack-mini-profiler (3.1.1) lib/mini_profiler.rb:413:in `call'
message_bus (4.3.8) lib/message_bus/rack/middleware.rb:60:in `call'
railties (7.0.7) lib/rails/engine.rb:530:in `call'
railties (7.0.7) lib/rails/railtie.rb:226:in `public_send'
railties (7.0.7) lib/rails/railtie.rb:226:in `method_missing'
rack (2.2.8) lib/rack/urlmap.rb:74:in `block in call'
rack (2.2.8) lib/rack/urlmap.rb:58:in `each'
rack (2.2.8) lib/rack/urlmap.rb:58:in `call'
unicorn (6.1.0) lib/unicorn/http_server.rb:634:in `process_client'
unicorn (6.1.0) lib/unicorn/http_server.rb:739:in `worker_loop'
unicorn (6.1.0) lib/unicorn/http_server.rb:547:in `spawn_missing_workers'
unicorn (6.1.0) lib/unicorn/http_server.rb:143:in `start'
unicorn (6.1.0) bin/unicorn:128:in `<top (required)>'
bin/unicorn:96:in `load'
bin/unicorn:96:in `block in <main>'
bin/unicorn:95:in `fork'
bin/unicorn:95:in `<main>'

Mögliche Ursachen

Gewünschte Hinweise oder Tipps

  • Wie funktioniert die Authentifizierung in Discourse?
  • Wie verwendet Discourse Sessions?
  • Discourse-Nachrichtenmechanismus
  • Am besten wäre es, wenn Sie mir direkt die Lösung nennen könnten

Möglicherweise nicht relevant, aber macht es einen Unterschied, die gültigen Redirect-URIs auf http://127.0.0.1:4200/auth/oidc/callback zu setzen?

Außerdem gibt es derzeit etwas Seltsames in der Ubuntu/Debian-Entwicklungsumgebung, wo die Seite entweder unter localhost:4200 oder 127.0.0.1:4200 erreichbar ist. Jede dieser Domains erstellt eine separate Sitzung. Wahrscheinlich nicht mit Ihrem Problem zusammenhängend, aber vielleicht etwas, das Probleme bei der lokalen Entwicklung verursachen könnte. Ich benutze immer die Domain localhost:4200. Das scheint das zu sein, was erwartet wird.

Ja, das wäre auch mein erster Gedanke. Es ist wichtig, dass der Authentifizierungsfluss auf demselben Port beginnt und endet, da sonst die Sitzung unterschiedlich sein kann.

Wenn Sie Rails und Ember-CLI zusammen über bin/ember-cli -u starten, sollten die Dinge automatisch für Sie konfiguriert werden. Wenn Sie sie jedoch separat starten, stellen Sie sicher, dass Sie die Umgebung DISCOURSE_PORT=4200 auf dem Rails-Server einstellen, damit alles korrekt übereinstimmt.

Ich habe es versucht, aber in Keycloak erscheint „Ungültiger Parameter: redirect_uri“.

Starte Rails und Ember-CLI zusammen über bin/ember-cli -u

Setze die gültigen Umleitungs-URIs auf http://127.0.0.1:4200/auth/oidc/callback.

Es scheint, dass die Ursache eine Diskrepanz zwischen den gültigen Redirect-URIs in Keycloak und den in der folgenden Abbildung dargestellten URIs ist.

Die in der Abbildung dargestellte URI ist

http://127.0.0.1:8080/realms/mediawiki-realm/protocol/openid-connect/auth?client_id=mydiscourse&nonce=dce3dd8bccb09b25f88d1645d26b9d20b58e3d2ff3804f83ed79098c793a5ae2&redirect_uri=http%3A%2F%2F127.0.0.1%3A3000%2Fauth%2Foidc%2Fcallback&response_type=code&scope=openid+profile+email&state=7fd712dd2b28c8264eac170721b898b26ae8fb2edb9a2e9f

Nach dem Dekodieren der ‘redirect_uri’ entspricht sie

http://127.0.0.1:3000/auth/oidc/callback

Was genau sollte die korrekte redirect_uri sein?

Wären Sie so freundlich, die für die Erstellung dieses Plugins verwendete Plattform für die Identitätsprüfung preiszugeben?

Danke, es funktioniert. :blush:
Meine Problemumgehung war, Discourse über 127.0.0.1:4200 anstelle von localhost:4200 zu öffnen.

Ich empfehle es nicht, aber für die lokale Entwicklung habe ich den etwas brutalen Ansatz gewählt, die callback_url-Methode des Plugins zu bearbeiten: discourse-openid-connect/lib/omniauth_open_id_connect.rb at main · discourse/discourse-openid-connect · GitHub.

     def callback_url
        full_host = 'http://localhost:4200'
        full_host + script_name + callback_path
      end

Auf diese Weise gibt es immer http://localhost:4200/auth/oidc/callback zurück.

Ohne diese Änderung konnte ich keinen Weg finden, den Hostteil der URL auf etwas anderes als http://127.0.0.1:3000 zu setzen.