From 4c26c4d9bcf8a16c245e69a7a1998e47e3c0d193 Mon Sep 17 00:00:00 2001 From: Paul Kaplan <paul@inventables.com> Date: Fri, 15 May 2015 12:00:34 -0500 Subject: [PATCH 1/3] Add a SiteSetting to not trust sso emails by default --- app/models/discourse_single_sign_on.rb | 2 +- config/locales/server.en.yml | 1 + config/site_settings.yml | 1 + spec/models/discourse_single_sign_on_spec.rb | 23 ++++++++++++++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/app/models/discourse_single_sign_on.rb b/app/models/discourse_single_sign_on.rb index db2387923..8eae077d8 100644 --- a/app/models/discourse_single_sign_on.rb +++ b/app/models/discourse_single_sign_on.rb @@ -57,7 +57,7 @@ class DiscourseSingleSignOn < SingleSignOn change_external_attributes_and_override(sso_record, user) end - if sso_record && (user = sso_record.user) && !user.active + if sso_record && (user = sso_record.user) && !user.active && SiteSetting.sso_trusts_email user.active = true user.save! user.enqueue_welcome_message('welcome_user') unless suppress_welcome_message diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 28c064ccf..4f22b37f1 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -885,6 +885,7 @@ en: enable_sso_provider: "Implement Discourse SSO provider protocol at the /session/sso_provider endpoint, requires sso_secret to be set" sso_url: "URL of single sign on endpoint" sso_secret: "Secret string used to cryptographically authenticate SSO information, be sure it is 10 characters or longer" + sso_trusts_email: "Allow SSO accounts to skip email verification" sso_overrides_email: "Overrides local email with external site email from SSO payload (WARNING: discrepancies can occur due to normalization of local emails)" sso_overrides_username: "Overrides local username with external site username from SSO payload (WARNING: discrepancies can occur due to differences in username length/requirements)" sso_overrides_name: "Overrides local full name with external site full name from SSO payload" diff --git a/config/site_settings.yml b/config/site_settings.yml index c53d526ee..94e21c864 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -234,6 +234,7 @@ login: enable_sso_provider: false sso_url: '' sso_secret: '' + sso_trusts_email: true sso_overrides_email: false sso_overrides_username: false sso_overrides_name: false diff --git a/spec/models/discourse_single_sign_on_spec.rb b/spec/models/discourse_single_sign_on_spec.rb index d102e291c..2430e3176 100644 --- a/spec/models/discourse_single_sign_on_spec.rb +++ b/spec/models/discourse_single_sign_on_spec.rb @@ -140,6 +140,29 @@ describe DiscourseSingleSignOn do expect(sso.nonce).to_not be_nil end + context 'trusting emails' do + let(:sso) { + sso = DiscourseSingleSignOn.new + sso.username = "test" + sso.name = "test" + sso.email = "test@example.com" + sso.external_id = "A" + sso + } + + it 'activates users by default' do + user = sso.lookup_or_create_user(ip_address) + expect(user.active).to eq(true) + end + + it 'does not activate user when asked to' do + SiteSetting.sso_trusts_email = false + user = sso.lookup_or_create_user(ip_address) + expect(user.active).to eq(false) + end + + end + context 'welcome emails' do let(:sso) { sso = DiscourseSingleSignOn.new From b8a43e153c4080c510af61105736f7bc97a3495e Mon Sep 17 00:00:00 2001 From: Paul Kaplan <paul@inventables.com> Date: Fri, 15 May 2015 12:01:30 -0500 Subject: [PATCH 2/3] Use session controller to prevent inactive SSO users --- app/controllers/session_controller.rb | 5 +++ spec/controllers/session_controller_spec.rb | 48 +++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/app/controllers/session_controller.rb b/app/controllers/session_controller.rb index f1c56ba68..8223a95ed 100644 --- a/app/controllers/session_controller.rb +++ b/app/controllers/session_controller.rb @@ -73,6 +73,11 @@ class SessionController < ApplicationController if SiteSetting.must_approve_users? && !user.approved? render text: I18n.t("sso.account_not_approved"), status: 403 return + elsif !user.active? + activation = UserActivator.new(user, request, session, cookies) + activation.finish + session["user_created_message"] = activation.message + redirect_to users_account_created_path and return else log_on_user user end diff --git a/spec/controllers/session_controller_spec.rb b/spec/controllers/session_controller_spec.rb index 309152e9d..093f4a3c5 100644 --- a/spec/controllers/session_controller_spec.rb +++ b/spec/controllers/session_controller_spec.rb @@ -193,6 +193,54 @@ describe SessionController do expect(logged_on_user.custom_fields["bla"]).to eq(nil) end + context 'when sso emails are not trusted' do + before do + SiteSetting.sso_trusts_email = false + end + + context 'if you have not activated your account' do + it 'does not log you in' do + sso = get_sso('/a/') + sso.external_id = '666' # the number of the beast + sso.email = 'bob@bob.com' + sso.name = 'Sam Saffron' + sso.username = 'sam' + + get :sso_login, Rack::Utils.parse_query(sso.payload) + + logged_on_user = Discourse.current_user_provider.new(request.env).current_user + expect(logged_on_user).to eq(nil) + end + + it 'sends an activation email' do + Jobs.expects(:enqueue).with(:user_email, has_entries(type: :signup)) + sso = get_sso('/a/') + sso.external_id = '666' # the number of the beast + sso.email = 'bob@bob.com' + sso.name = 'Sam Saffron' + sso.username = 'sam' + get :sso_login, Rack::Utils.parse_query(sso.payload) + end + end + + context 'if you have activated your account' do + it 'allows you to log in' do + sso = get_sso('/hello/world') + sso.external_id = '997' + sso.sso_url = "http://somewhere.over.com/sso_login" + + user = Fabricate(:user) + user.create_single_sign_on_record(external_id: '997', last_payload: '') + user.stubs(:active?).returns(true) + + get :sso_login, Rack::Utils.parse_query(sso.payload) + + logged_on_user = Discourse.current_user_provider.new(request.env).current_user + expect(user.id).to eq(logged_on_user.id) + end + end + end + it 'allows login to existing account with valid nonce' do sso = get_sso('/hello/world') sso.external_id = '997' From 1c34341f31518e369c818ae6b6db415a53bb2250 Mon Sep 17 00:00:00 2001 From: Paul Kaplan <paul@inventables.com> Date: Tue, 19 May 2015 11:16:02 -0500 Subject: [PATCH 3/3] Replace site setting with a payload attribute --- app/models/discourse_single_sign_on.rb | 2 +- config/locales/server.en.yml | 1 - config/site_settings.yml | 1 - lib/single_sign_on.rb | 2 +- spec/controllers/session_controller_spec.rb | 8 ++++---- spec/models/discourse_single_sign_on_spec.rb | 4 ++-- 6 files changed, 8 insertions(+), 10 deletions(-) diff --git a/app/models/discourse_single_sign_on.rb b/app/models/discourse_single_sign_on.rb index 8eae077d8..4966cf9a1 100644 --- a/app/models/discourse_single_sign_on.rb +++ b/app/models/discourse_single_sign_on.rb @@ -57,7 +57,7 @@ class DiscourseSingleSignOn < SingleSignOn change_external_attributes_and_override(sso_record, user) end - if sso_record && (user = sso_record.user) && !user.active && SiteSetting.sso_trusts_email + if sso_record && (user = sso_record.user) && !user.active && !require_activation user.active = true user.save! user.enqueue_welcome_message('welcome_user') unless suppress_welcome_message diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 4f22b37f1..28c064ccf 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -885,7 +885,6 @@ en: enable_sso_provider: "Implement Discourse SSO provider protocol at the /session/sso_provider endpoint, requires sso_secret to be set" sso_url: "URL of single sign on endpoint" sso_secret: "Secret string used to cryptographically authenticate SSO information, be sure it is 10 characters or longer" - sso_trusts_email: "Allow SSO accounts to skip email verification" sso_overrides_email: "Overrides local email with external site email from SSO payload (WARNING: discrepancies can occur due to normalization of local emails)" sso_overrides_username: "Overrides local username with external site username from SSO payload (WARNING: discrepancies can occur due to differences in username length/requirements)" sso_overrides_name: "Overrides local full name with external site full name from SSO payload" diff --git a/config/site_settings.yml b/config/site_settings.yml index 94e21c864..c53d526ee 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -234,7 +234,6 @@ login: enable_sso_provider: false sso_url: '' sso_secret: '' - sso_trusts_email: true sso_overrides_email: false sso_overrides_username: false sso_overrides_name: false diff --git a/lib/single_sign_on.rb b/lib/single_sign_on.rb index 66285e4dc..f0875a306 100644 --- a/lib/single_sign_on.rb +++ b/lib/single_sign_on.rb @@ -1,5 +1,5 @@ class SingleSignOn - ACCESSORS = [:nonce, :name, :username, :email, :avatar_url, :avatar_force_update, + ACCESSORS = [:nonce, :name, :username, :email, :avatar_url, :avatar_force_update, :require_activation, :about_me, :external_id, :return_sso_url, :admin, :moderator, :suppress_welcome_message] FIXNUMS = [] BOOLS = [:avatar_force_update, :admin, :moderator, :suppress_welcome_message] diff --git a/spec/controllers/session_controller_spec.rb b/spec/controllers/session_controller_spec.rb index 093f4a3c5..683e7ced1 100644 --- a/spec/controllers/session_controller_spec.rb +++ b/spec/controllers/session_controller_spec.rb @@ -194,10 +194,6 @@ describe SessionController do end context 'when sso emails are not trusted' do - before do - SiteSetting.sso_trusts_email = false - end - context 'if you have not activated your account' do it 'does not log you in' do sso = get_sso('/a/') @@ -205,6 +201,7 @@ describe SessionController do sso.email = 'bob@bob.com' sso.name = 'Sam Saffron' sso.username = 'sam' + sso.require_activation = true get :sso_login, Rack::Utils.parse_query(sso.payload) @@ -219,6 +216,8 @@ describe SessionController do sso.email = 'bob@bob.com' sso.name = 'Sam Saffron' sso.username = 'sam' + sso.require_activation = true + get :sso_login, Rack::Utils.parse_query(sso.payload) end end @@ -228,6 +227,7 @@ describe SessionController do sso = get_sso('/hello/world') sso.external_id = '997' sso.sso_url = "http://somewhere.over.com/sso_login" + sso.require_activation = true user = Fabricate(:user) user.create_single_sign_on_record(external_id: '997', last_payload: '') diff --git a/spec/models/discourse_single_sign_on_spec.rb b/spec/models/discourse_single_sign_on_spec.rb index 2430e3176..c49b3b44c 100644 --- a/spec/models/discourse_single_sign_on_spec.rb +++ b/spec/models/discourse_single_sign_on_spec.rb @@ -155,8 +155,8 @@ describe DiscourseSingleSignOn do expect(user.active).to eq(true) end - it 'does not activate user when asked to' do - SiteSetting.sso_trusts_email = false + it 'does not activate user when asked not to' do + sso.require_activation = true user = sso.lookup_or_create_user(ip_address) expect(user.active).to eq(false) end