diff --git a/app/models/discourse_single_sign_on.rb b/app/models/discourse_single_sign_on.rb index 3daa48dee36..4abfc61a4a9 100644 --- a/app/models/discourse_single_sign_on.rb +++ b/app/models/discourse_single_sign_on.rb @@ -31,21 +31,37 @@ class DiscourseSingleSignOn < SingleSignOn def register_nonce(return_path) if nonce - @secure_session.set(nonce_key, return_path, expires: SingleSignOn.nonce_expiry_time) + if SiteSetting.discourse_connect_csrf_protection + @secure_session.set(nonce_key, return_path, expires: SingleSignOn.nonce_expiry_time) + else + Discourse.cache.write(nonce_key, return_path, expires_in: SingleSignOn.nonce_expiry_time) + end end end def nonce_valid? - nonce && @secure_session[nonce_key].present? + if SiteSetting.discourse_connect_csrf_protection + nonce && @secure_session[nonce_key].present? + else + nonce && Discourse.cache.read(nonce_key).present? + end end def return_path - @secure_session[nonce_key] || "/" + if SiteSetting.discourse_connect_csrf_protection + @secure_session[nonce_key] || "/" + else + Discourse.cache.read(nonce_key) || "/" + end end def expire_nonce! if nonce - @secure_session[nonce_key] = nil + if SiteSetting.discourse_connect_csrf_protection + @secure_session[nonce_key] = nil + else + Discourse.cache.delete nonce_key + end end end diff --git a/config/site_settings.yml b/config/site_settings.yml index 300bb24fdec..a2baeccf36e 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -475,6 +475,9 @@ login: discourse_connect_overrides_website: false discourse_connect_overrides_card_background: false discourse_connect_not_approved_url: "" + discourse_connect_csrf_protection: + default: true + hidden: true blocked_email_domains: default: "mailinator.com" type: list diff --git a/spec/models/discourse_single_sign_on_spec.rb b/spec/models/discourse_single_sign_on_spec.rb index edf3b856abc..e1d03c12e73 100644 --- a/spec/models/discourse_single_sign_on_spec.rb +++ b/spec/models/discourse_single_sign_on_spec.rb @@ -375,10 +375,27 @@ describe DiscourseSingleSignOn do sso = DiscourseSingleSignOn.parse(payload, secure_session: secure_session) expect(sso.nonce_valid?).to eq true + other_session_sso = DiscourseSingleSignOn.parse(payload, secure_session: SecureSession.new("differentsession")) + expect(other_session_sso.nonce_valid?).to eq false + sso.expire_nonce! expect(sso.nonce_valid?).to eq false + end + it "allows disabling CSRF protection" do + SiteSetting.discourse_connect_csrf_protection = false + _ , payload = DiscourseSingleSignOn.generate_url(secure_session: secure_session).split("?") + + sso = DiscourseSingleSignOn.parse(payload, secure_session: secure_session) + expect(sso.nonce_valid?).to eq true + + other_session_sso = DiscourseSingleSignOn.parse(payload, secure_session: SecureSession.new("differentsession")) + expect(other_session_sso.nonce_valid?).to eq true + + sso.expire_nonce! + + expect(sso.nonce_valid?).to eq false end it "generates a correct sso url" do