مشكلة CSRF في التطوير مع المكون الإضافي 'Discourse OpenID Connect'

قضيت من خمسة إلى ستة أسابيع في إعداد نظام الدخول الموحد (SSO) الخاص بـ Discourse، وواجهت بعض المشكلات خلال هذه الفترة. الآن، هناك مشكلة تمنعني من المضي قدمًا. سأقوم بتسجيل هذه المشكلة بأقصى قدر ممكن من التفاصيل.

بيئة التطوير

  • ubuntu22 على VMware
  • discourse 3.2.0.beta2-dev
    • يعمل الخادم على 127.0.0.1:3000
    • يعمل ember-cli على 127.0.0.1:4200
    • تثبيت Discourse على Ubuntu أو Debian للتطوير
    • تم تعطيل الإضافات التالية:
      • presence
      • chat
      • narrative bot
    • استخدام إضافة Discourse OpenID Connect للاتصال بـ Keycloak بناءً على OIDC، حيث يعمل Keycloak كمزود هوية لـ Discourse
      • إعدادات اتصال OIDC في Discourse OpenID Connect
        • مستند اكتشاف OpenID Connect: http://127.0.0.1:8080/realms/mediawiki-realm/.well-known/openid-configuration
        • معرف عميل OpenID Connect: mydiscourse
        • سر عميل OpenID Connect: O9A8zQuOn1bfpsWD89U8ULwYf6ooDu73
  • مزود الدخول الموحد Keycloak 22.0.4
    • يعمل على 127.0.0.1:8080
    • إعدادات اتصال OIDC في Keycloak
      • عناوين URI لإعادة التوجيه الصالحة: http://127.0.0.1:3000/auth/oidc/callback
      • سر العميل: O9A8zQuOn1bfpsWD89U8ULwYf6ooDu73
  • متصفح Chrome الإصدار 118.0.5993.70

عملية إعادة إنتاج المشكلة

تسجيل الدخول باستخدام OIDC

يعيد Discourse التوجيه إلى Keycloak، أدخل معلومات المستخدم في Keycloak

CSRF

السجلات


//

//

//

// تتبع التطبيق

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'

// تتبع الإطار

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

// التتبع الكامل

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

الأسباب المحتملة

التوجيهات أو النصائح التي أود الحصول عليها

  • كيف يعمل المصادقة في Discourse؟
  • كيف يستخدم Discourse الجلسة (session)؟
  • آلية المراسلة في Discourse
  • الأفضل أن تخبرني بالحل مباشرة

ربما لا علاقة له، ولكن هل يؤدي تعيين عناوين URI لإعادة التوجيه الصالحة إلى http://127.0.0.1:4200/auth/oidc/callback إلى إحداث فرق؟

أيضًا، هناك حاليًا شيء غريب يحدث مع بيئة التطوير Ubuntu/Debian حيث يمكن الوصول إلى الموقع إما على localhost:4200 أو 127.0.0.1:4200. كل من هذه المجالات ينشئ جلسة منفصلة. ربما لا علاقة له بمشكلتك، ولكن ربما شيء يمكن أن يسبب مشاكل للتطوير المحلي. أنا دائمًا أستخدم المجال localhost:4200. يبدو أن هذا هو المتوقع.

نعم، هذا سيكون أول ما أفكر فيه أيضًا. من المهم أن تبدأ عملية المصادقة وتنتهي على نفس المنفذ، وإلا فقد تكون الجلسة مختلفة.

إذا قمت بتشغيل Rails و Ember-CLI معًا عبر bin/ember-cli -u، فسيتم تكوين كل شيء تلقائيًا لك. ولكن إذا كنت تبدأهما بشكل منفصل، فتأكد من تعيين بيئة DISCOURSE_PORT=4200 على خادم Rails حتى تتوافق كل الأشياء بشكل صحيح.

حاولت، ولكن يظهر “Invalid parameter: redirect_uri” في Keycloak.

قم بتشغيل Rails و Ember-CLI معًا عبر bin/ember-cli -u

قم بتعيين عناوين URI لإعادة التوجيه الصالحة إلى http://127.0.0.1:4200/auth/oidc/callback.

يبدو أن السبب هو وجود تباين بين عناوين URI لإعادة التوجيه الصالحة في Keycloak وعناوين URI الموضحة في الرسم التوضيحي التالي.

عنوان URI الموضح في الصورة هو

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

بعد فك تشفير ‘redirect_uri’، فإن معادلته لـ

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

ما الذي ينبغي أن يكون عليه ‘redirect_uri’ الصحيح بالفعل؟

هل تتكرم بالكشف عن المنصة المستخدمة للتحقق من الهوية أثناء إنشاء هذا المكون الإضافي؟

شكرًا، لقد نجح الأمر. :blush:
كان الحل البديل الخاص بي هو فتح discourse باستخدام 127.0.0.1:4200 بدلاً من localhost:4200

لا أوصي به، ولكن للتطوير المحلي، اتخذت نهجًا وحشيًا إلى حد ما لتعديل طريقة callback_url الخاصة بالمكون الإضافي: 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

بهذه الطريقة، فإنه يعيد دائمًا http://localhost:4200/auth/oidc/callback

بدون هذا التغيير، لم أتمكن من العثور على طريقة لجعل جزء المضيف من عنوان URL مضبوطًا على أي شيء آخر غير http://127.0.0.1:3000