mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 22:01:14 +08:00
FEATURE: Add option to have sso synchronize group membership
In some cases add_groups and remove_groups is too much work, some sites may wish to simply synchronize group membership based on a list. When sso_overrides_groups is on all not automatic group membership is sourced from SSO. Note if you omit to specify groups, they will be cleared out.
This commit is contained in:
@ -106,7 +106,29 @@ class DiscourseSingleSignOn < SingleSignOn
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def synchronize_groups(user)
|
||||||
|
names = (groups || "").split(",").map(&:downcase)
|
||||||
|
ids = Group.where('LOWER(NAME) in (?) AND NOT automatic', names).pluck(:id)
|
||||||
|
|
||||||
|
group_users = GroupUser
|
||||||
|
.where('group_id IN (SELECT id FROM groups WHERE NOT automatic)')
|
||||||
|
.where(user_id: user.id)
|
||||||
|
|
||||||
|
group_users.where('group_id NOT IN (?)', ids).destroy_all
|
||||||
|
|
||||||
|
ids -= group_users.where('group_id IN (?)', ids).pluck(:group_id)
|
||||||
|
|
||||||
|
ids.each do |group_id|
|
||||||
|
GroupUser.create(group_id: group_id, user_id: user.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def apply_group_rules(user)
|
def apply_group_rules(user)
|
||||||
|
if SiteSetting.sso_overrides_groups
|
||||||
|
synchronize_groups(user)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
if add_groups
|
if add_groups
|
||||||
split = add_groups.split(",").map(&:downcase)
|
split = add_groups.split(",").map(&:downcase)
|
||||||
if split.length > 0
|
if split.length > 0
|
||||||
|
@ -1185,6 +1185,7 @@ en:
|
|||||||
sso_url: "URL of single sign on endpoint (must include http:// or https://)"
|
sso_url: "URL of single sign on endpoint (must include http:// or https://)"
|
||||||
sso_secret: "Secret string used to cryptographically authenticate SSO information, be sure it is 10 characters or longer"
|
sso_secret: "Secret string used to cryptographically authenticate SSO information, be sure it is 10 characters or longer"
|
||||||
sso_overrides_bio: "Overrides user bio in user profile and prevents user from changing it"
|
sso_overrides_bio: "Overrides user bio in user profile and prevents user from changing it"
|
||||||
|
sso_overrides_groups: "Synchronize all manual group membership with groups specified in the groups sso attribute (WARNING: if you do not specify groups all manual group membership will be cleared for user)"
|
||||||
sso_overrides_email: "Overrides local email with external site email from SSO payload on every login, and prevent local changes. (WARNING: discrepancies can occur due to normalization of local emails)"
|
sso_overrides_email: "Overrides local email with external site email from SSO payload on every login, and prevent local changes. (WARNING: discrepancies can occur due to normalization of local emails)"
|
||||||
sso_overrides_username: "Overrides local username with external site username from SSO payload on every login, and prevent local changes. (WARNING: discrepancies can occur due to differences in username length/requirements)"
|
sso_overrides_username: "Overrides local username with external site username from SSO payload on every login, and prevent local changes. (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 on every login, and prevent local changes."
|
sso_overrides_name: "Overrides local full name with external site full name from SSO payload on every login, and prevent local changes."
|
||||||
|
@ -320,6 +320,7 @@ login:
|
|||||||
default: ''
|
default: ''
|
||||||
regex: '^https?:\/\/.+[^\/]$'
|
regex: '^https?:\/\/.+[^\/]$'
|
||||||
sso_secret: ''
|
sso_secret: ''
|
||||||
|
sso_overrides_groups: false
|
||||||
sso_overrides_bio: false
|
sso_overrides_bio: false
|
||||||
sso_overrides_email:
|
sso_overrides_email:
|
||||||
default: false
|
default: false
|
||||||
|
@ -4,7 +4,6 @@ class SingleSignOn
|
|||||||
:add_groups, :remove_groups, :groups]
|
:add_groups, :remove_groups, :groups]
|
||||||
FIXNUMS = []
|
FIXNUMS = []
|
||||||
BOOLS = [:avatar_force_update, :admin, :moderator, :require_activation, :suppress_welcome_message]
|
BOOLS = [:avatar_force_update, :admin, :moderator, :require_activation, :suppress_welcome_message]
|
||||||
ARRAYS = [:groups]
|
|
||||||
NONCE_EXPIRY_TIME = 10.minutes
|
NONCE_EXPIRY_TIME = 10.minutes
|
||||||
|
|
||||||
attr_accessor(*ACCESSORS)
|
attr_accessor(*ACCESSORS)
|
||||||
@ -41,7 +40,6 @@ class SingleSignOn
|
|||||||
if BOOLS.include? k
|
if BOOLS.include? k
|
||||||
val = ["true", "false"].include?(val) ? val == "true" : nil
|
val = ["true", "false"].include?(val) ? val == "true" : nil
|
||||||
end
|
end
|
||||||
val = Array(val) if ARRAYS.include?(k) && !val.nil?
|
|
||||||
sso.send("#{k}=", val)
|
sso.send("#{k}=", val)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -121,6 +121,34 @@ describe DiscourseSingleSignOn do
|
|||||||
expect(admin_group.users.where('users.id = ?', user.id).exists?).to eq(true)
|
expect(admin_group.users.where('users.id = ?', user.id).exists?).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "can force a list of groups with the groups attribute" do
|
||||||
|
user = Fabricate(:user)
|
||||||
|
group1 = Fabricate(:group, name: 'group1')
|
||||||
|
group2 = Fabricate(:group, name: 'group2')
|
||||||
|
|
||||||
|
sso = DiscourseSingleSignOn.new
|
||||||
|
sso.username = "bobsky"
|
||||||
|
sso.name = "Bob"
|
||||||
|
sso.email = user.email
|
||||||
|
sso.external_id = "A"
|
||||||
|
|
||||||
|
sso.groups = "#{group2.name.capitalize},group4,badname,trust_level_4"
|
||||||
|
sso.lookup_or_create_user(ip_address)
|
||||||
|
|
||||||
|
SiteSetting.sso_overrides_groups = true
|
||||||
|
|
||||||
|
group1.reload
|
||||||
|
expect(group1.usernames).to eq("")
|
||||||
|
expect(group2.usernames).to eq("")
|
||||||
|
|
||||||
|
group1.add(user)
|
||||||
|
group1.save
|
||||||
|
|
||||||
|
sso.lookup_or_create_user(ip_address)
|
||||||
|
expect(group1.usernames).to eq("")
|
||||||
|
expect(group2.usernames).to eq(user.username)
|
||||||
|
end
|
||||||
|
|
||||||
it "can specify groups" do
|
it "can specify groups" do
|
||||||
|
|
||||||
user = Fabricate(:user)
|
user = Fabricate(:user)
|
||||||
|
Reference in New Issue
Block a user