Problema CSRF in sviluppo con il plugin 'Discourse OpenID Connect'

I spent five or six weeks setting up Discourse’s SSO, and encountered some problems during this period. Now there is a problem that is blocking me. I will record this problem in as much detail as possible.

Development environment

  • ubuntu22 on vmware
  • discourse 3.2.0.beta2-dev
    • server runs on 127.0.0.1:3000
    • ember-cli runs on 127.0.0.1:4200
    • Install Discourse on Ubuntu or Debian for Development
    • disabled plugins
      • presence
      • chat
      • narrative bot
    • Use plug-in Discourse OpenID Connect to connect kecloak based on OIDC, keycloak as the identity provider of discourse
      • OIDC connection configuration on Discourse OpenID Connect
        • openid connect discovery document: http://127.0.0.1:8080/realms/mediawiki-realm/.well-known/openid-configuration
        • openid connect client id: mydiscourse
        • openid connect client secret: O9A8zQuOn1bfpsWD89U8ULwYf6ooDu73
  • sso provider keycloak 22.0.4
    • runs on 127.0.0.1:8080
    • OIDC connection configuration on keycloak
      • Valid redirect URIs: http://127.0.0.1:3000/auth/oidc/callback
      • Client secret: O9A8zQuOn1bfpsWD89U8ULwYf6ooDu73
  • chrome version 118.0.5993.70

Reproduction process

Log in with OIDC

image

Discourse redirects to keycloak, enter user information in keycloak

CSRF

Logs


//

//

//

// Application Trace

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 Trace

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>'

// Full Trace

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>'

Possible reason

The guidance or tips I want to get

  • How authentication in discourse works?
  • How discourse uses session?
  • Discourse messaging mechanism
  • It would be best if you could tell me the solution directly

Forse non correlato, ma impostare gli URI di reindirizzamento validi su http://127.0.0.1:4200/auth/oidc/callback fa la differenza?

Inoltre, c’è attualmente qualcosa di strano nell’ambiente di sviluppo Ubuntu/Debian in cui il sito è accessibile sia da localhost:4200 che da 127.0.0.1:4200. Ciascuno di questi domini crea una sessione separata. Probabilmente non correlato al tuo problema, ma forse qualcosa che potrebbe causare problemi per lo sviluppo locale. Uso sempre il dominio localhost:4200. Sembra che sia quello che ci si aspetta.

2 Mi Piace

Sì, questo sarebbe anche il mio primo pensiero. È importante che il flusso di autenticazione inizi e finisca sulla stessa porta, altrimenti la sessione potrebbe essere diversa.

Se avvii Rails ed Ember-CLI insieme tramite bin/ember-cli -u, tutto dovrebbe essere configurato automaticamente per te. Ma se li stai avviando separatamente, assicurati di impostare l’ambiente DISCOURSE_PORT=4200 sul server Rails in modo che tutto sia allineato correttamente.

2 Mi Piace

Ho provato, ma in Keycloak appare "Parametro non valido: redirect_uri".

Avvia Rails ed Ember-CLI insieme tramite bin/ember-cli -u

Imposta gli URI di reindirizzamento validi su http://127.0.0.1:4200/auth/oidc/callback.

Sembra che la causa sia una discrepanza tra gli URI di reindirizzamento validi in Keycloak e gli URI raffigurati nella seguente illustrazione.

L’URI raffigurato nell’immagine è

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

Dopo aver decodificato il ‘redirect_uri’, la sua equivalenza a

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

Quale dovrebbe essere, in effetti, il redirect_uri corretto?

Sarebbe così gentile da divulgare la piattaforma utilizzata per la verifica dell’identità durante la creazione di questo plugin?

Grazie, funziona. :blush:
La mia soluzione è stata aprire discourse usando 127.0.0.1:4200 invece di localhost:4200

2 Mi Piace

Non lo consiglio, ma per lo sviluppo locale ho adottato l’approccio piuttosto drastico di modificare il metodo callback_url del plugin: 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

In questo modo restituisce sempre http://localhost:4200/auth/oidc/callback

Senza quella modifica, non sono riuscito a trovare un modo per impostare la parte host dell’URL su qualcosa di diverso da http://127.0.0.1:3000

1 Mi Piace

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.