From 3d76ce14219a168bdf85769c5474420951c14253 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 11 Nov 2016 16:57:31 +1100 Subject: [PATCH] FEATURE: SSO support for adding and removing a user to groups Use: add_groups with a comma delimited list to ensure a user is in groups (using group names) Use: remove_groups with a comma delimited list to ensure a user is removed from groups (using group names) --- app/models/discourse_single_sign_on.rb | 27 +++++++++++++++ lib/single_sign_on.rb | 3 +- spec/models/discourse_single_sign_on_spec.rb | 35 ++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/app/models/discourse_single_sign_on.rb b/app/models/discourse_single_sign_on.rb index 69bc0d1e837..a4c1fd151b2 100644 --- a/app/models/discourse_single_sign_on.rb +++ b/app/models/discourse_single_sign_on.rb @@ -94,11 +94,38 @@ class DiscourseSingleSignOn < SingleSignOn sso_record.save! + if sso_record.user + apply_group_rules(sso_record.user) + end + sso_record && sso_record.user end private + def apply_group_rules(user) + if add_groups + split = add_groups.split(",") + if split.length > 0 + Group.where('name in (?) AND NOT automatic', split).pluck(:id).each do |id| + unless GroupUser.where(group_id: id, user_id: user.id).exists? + GroupUser.create(group_id: id, user_id: user.id) + end + end + end + end + + if remove_groups + split = remove_groups.split(",") + if split.length > 0 + GroupUser + .where(user_id: user.id) + .where('group_id IN (SELECT id FROM groups WHERE name in (?))',split) + .destroy_all + end + end + end + def match_email_or_create_user(ip_address) unless user = User.find_by_email(email) try_name = name.presence diff --git a/lib/single_sign_on.rb b/lib/single_sign_on.rb index 64d4e909a61..bd0d408e1c0 100644 --- a/lib/single_sign_on.rb +++ b/lib/single_sign_on.rb @@ -1,6 +1,7 @@ class SingleSignOn ACCESSORS = [:nonce, :name, :username, :email, :avatar_url, :avatar_force_update, :require_activation, - :bio, :external_id, :return_sso_url, :admin, :moderator, :suppress_welcome_message] + :bio, :external_id, :return_sso_url, :admin, :moderator, :suppress_welcome_message, + :add_groups, :remove_groups] FIXNUMS = [] BOOLS = [:avatar_force_update, :admin, :moderator, :require_activation, :suppress_welcome_message] NONCE_EXPIRY_TIME = 10.minutes diff --git a/spec/models/discourse_single_sign_on_spec.rb b/spec/models/discourse_single_sign_on_spec.rb index 10a49a09d94..990884fe0aa 100644 --- a/spec/models/discourse_single_sign_on_spec.rb +++ b/spec/models/discourse_single_sign_on_spec.rb @@ -113,6 +113,41 @@ describe DiscourseSingleSignOn do expect(admin_group.users.where('users.id = ?', user.id).exists?).to eq(true) end + it "can specify groups" do + + user = Fabricate(:user) + + add_group1 = Fabricate(:group, name: 'group1') + add_group2 = Fabricate(:group, name: 'group2') + existing_group = Fabricate(:group, name: 'group3') + + existing_group.add(user) + existing_group.save! + + add_group1.add(user) + existing_group.save! + + sso = DiscourseSingleSignOn.new + sso.username = "bobsky" + sso.name = "Bob" + sso.email = user.email + sso.external_id = "A" + + sso.add_groups = "#{add_group1.name},#{add_group2.name},badname" + sso.remove_groups = "#{existing_group.name},badname" + + sso.lookup_or_create_user(ip_address) + + existing_group.reload + expect(existing_group.usernames).to eq("") + + add_group1.reload + expect(add_group1.usernames).to eq(user.username) + + add_group2.reload + expect(add_group2.usernames).to eq(user.username) + end + it "can override name / email / username" do admin = Fabricate(:admin)