2014-02-24 22:30:49 -05:00
|
|
|
require_dependency 'single_sign_on'
|
2014-04-19 00:00:40 -04:00
|
|
|
|
2014-02-24 22:30:49 -05:00
|
|
|
class DiscourseSingleSignOn < SingleSignOn
|
2014-06-02 03:32:39 -04:00
|
|
|
|
2014-02-24 22:30:49 -05:00
|
|
|
def self.sso_url
|
|
|
|
SiteSetting.sso_url
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.sso_secret
|
|
|
|
SiteSetting.sso_secret
|
|
|
|
end
|
|
|
|
|
2017-07-27 21:20:09 -04:00
|
|
|
def self.generate_sso(return_path = "/")
|
2014-02-24 22:30:49 -05:00
|
|
|
sso = new
|
|
|
|
sso.nonce = SecureRandom.hex
|
2014-02-25 17:58:30 -05:00
|
|
|
sso.register_nonce(return_path)
|
2014-11-26 01:25:54 -05:00
|
|
|
sso.return_sso_url = Discourse.base_url + "/session/sso_login"
|
2016-04-07 21:20:01 -04:00
|
|
|
sso
|
|
|
|
end
|
|
|
|
|
2017-07-27 21:20:09 -04:00
|
|
|
def self.generate_url(return_path = "/")
|
2016-04-07 21:20:01 -04:00
|
|
|
generate_sso(return_path).to_url
|
2014-02-24 22:30:49 -05:00
|
|
|
end
|
|
|
|
|
2014-02-25 17:58:30 -05:00
|
|
|
def register_nonce(return_path)
|
2014-02-24 22:30:49 -05:00
|
|
|
if nonce
|
2014-02-25 17:58:30 -05:00
|
|
|
$redis.setex(nonce_key, NONCE_EXPIRY_TIME, return_path)
|
2014-02-24 22:30:49 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def nonce_valid?
|
|
|
|
nonce && $redis.get(nonce_key).present?
|
|
|
|
end
|
|
|
|
|
2014-02-25 17:58:30 -05:00
|
|
|
def return_path
|
|
|
|
$redis.get(nonce_key) || "/"
|
|
|
|
end
|
|
|
|
|
2014-02-24 22:30:49 -05:00
|
|
|
def expire_nonce!
|
|
|
|
if nonce
|
|
|
|
$redis.del nonce_key
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def nonce_key
|
|
|
|
"SSO_NONCE_#{nonce}"
|
|
|
|
end
|
|
|
|
|
2017-07-27 21:20:09 -04:00
|
|
|
def lookup_or_create_user(ip_address = nil)
|
2014-05-06 09:41:59 -04:00
|
|
|
sso_record = SingleSignOnRecord.find_by(external_id: external_id)
|
2014-04-15 01:53:48 -04:00
|
|
|
|
2016-09-01 22:04:22 -04:00
|
|
|
if sso_record && (user = sso_record.user)
|
2014-02-24 22:30:49 -05:00
|
|
|
sso_record.last_payload = unsigned_payload
|
|
|
|
else
|
2015-02-23 15:58:45 -05:00
|
|
|
user = match_email_or_create_user(ip_address)
|
2014-02-27 19:48:46 -05:00
|
|
|
sso_record = user.single_sign_on_record
|
|
|
|
end
|
2014-04-15 01:53:48 -04:00
|
|
|
|
2016-06-21 05:28:58 -04:00
|
|
|
# ensure it's not staged anymore
|
|
|
|
user.staged = false
|
|
|
|
|
2014-02-27 19:48:46 -05:00
|
|
|
# if the user isn't new or it's attached to the SSO record we might be overriding username or email
|
|
|
|
unless user.new_record?
|
|
|
|
change_external_attributes_and_override(sso_record, user)
|
2014-02-24 22:30:49 -05:00
|
|
|
end
|
|
|
|
|
2015-05-19 12:16:02 -04:00
|
|
|
if sso_record && (user = sso_record.user) && !user.active && !require_activation
|
2014-02-25 18:28:03 -05:00
|
|
|
user.active = true
|
2014-06-02 03:32:39 -04:00
|
|
|
user.save!
|
2015-03-20 13:03:24 -04:00
|
|
|
user.enqueue_welcome_message('welcome_user') unless suppress_welcome_message
|
2017-06-14 13:20:18 -04:00
|
|
|
user.set_automatic_groups
|
2014-02-25 18:28:03 -05:00
|
|
|
end
|
2014-04-15 01:53:48 -04:00
|
|
|
|
2017-07-27 21:20:09 -04:00
|
|
|
custom_fields.each do |k, v|
|
2014-04-21 23:52:13 -04:00
|
|
|
user.custom_fields[k] = v
|
|
|
|
end
|
|
|
|
|
2015-02-23 15:58:45 -05:00
|
|
|
user.ip_address = ip_address
|
2016-05-17 03:31:34 -04:00
|
|
|
|
2014-11-26 20:39:00 -05:00
|
|
|
user.admin = admin unless admin.nil?
|
|
|
|
user.moderator = moderator unless moderator.nil?
|
|
|
|
|
2017-01-31 19:42:27 -05:00
|
|
|
user.title = title unless title.nil?
|
|
|
|
|
2014-02-27 19:48:46 -05:00
|
|
|
# optionally save the user and sso_record if they have changed
|
2016-08-28 21:28:19 -04:00
|
|
|
user.user_avatar.save! if user.user_avatar
|
2014-02-27 19:48:46 -05:00
|
|
|
user.save!
|
2016-05-17 03:31:34 -04:00
|
|
|
|
2016-08-01 01:29:28 -04:00
|
|
|
if bio && (user.user_profile.bio_raw.blank? || SiteSetting.sso_overrides_bio)
|
|
|
|
user.user_profile.bio_raw = bio
|
|
|
|
user.user_profile.save!
|
|
|
|
end
|
|
|
|
|
2016-05-17 03:31:34 -04:00
|
|
|
unless admin.nil? && moderator.nil?
|
|
|
|
Group.refresh_automatic_groups!(:admins, :moderators, :staff)
|
|
|
|
end
|
|
|
|
|
2014-02-27 19:48:46 -05:00
|
|
|
sso_record.save!
|
2014-02-25 18:28:03 -05:00
|
|
|
|
2016-11-11 00:57:31 -05:00
|
|
|
if sso_record.user
|
|
|
|
apply_group_rules(sso_record.user)
|
|
|
|
end
|
|
|
|
|
2014-02-24 22:30:49 -05:00
|
|
|
sso_record && sso_record.user
|
|
|
|
end
|
2014-04-15 01:53:48 -04:00
|
|
|
|
2014-02-27 19:48:46 -05:00
|
|
|
private
|
2014-04-15 01:53:48 -04:00
|
|
|
|
2016-11-11 00:57:31 -05:00
|
|
|
def apply_group_rules(user)
|
|
|
|
if add_groups
|
2017-08-02 11:30:23 -04:00
|
|
|
split = add_groups.split(",").map(&:downcase)
|
2016-11-11 00:57:31 -05:00
|
|
|
if split.length > 0
|
2017-08-11 18:09:22 -04:00
|
|
|
Group.where('LOWER(name) in (?) AND NOT automatic', split).pluck(:id).each do |id|
|
2016-11-11 00:57:31 -05:00
|
|
|
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
|
2017-08-11 18:09:22 -04:00
|
|
|
split = remove_groups.split(",").map(&:downcase)
|
2016-11-11 00:57:31 -05:00
|
|
|
if split.length > 0
|
|
|
|
GroupUser
|
2017-07-27 21:20:09 -04:00
|
|
|
.where(user_id: user.id)
|
2017-08-11 18:09:22 -04:00
|
|
|
.where('group_id IN (SELECT id FROM groups WHERE LOWER(name) in (?))', split)
|
2017-07-27 21:20:09 -04:00
|
|
|
.destroy_all
|
2016-11-11 00:57:31 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-02-23 15:58:45 -05:00
|
|
|
def match_email_or_create_user(ip_address)
|
2016-02-24 15:57:01 -05:00
|
|
|
unless user = User.find_by_email(email)
|
|
|
|
try_name = name.presence
|
|
|
|
try_username = username.presence
|
|
|
|
|
|
|
|
user_params = {
|
|
|
|
email: email,
|
|
|
|
name: try_name || User.suggest_name(try_username || email),
|
|
|
|
username: UserNameSuggester.suggest(try_username || try_name || email),
|
|
|
|
ip_address: ip_address
|
|
|
|
}
|
|
|
|
|
|
|
|
user = User.create!(user_params)
|
2017-11-07 06:38:36 -05:00
|
|
|
|
|
|
|
if SiteSetting.verbose_sso_logging
|
|
|
|
Rails.logger.warn("Verbose SSO log: New User (user_id: #{user.id}) Created with #{user_params}")
|
|
|
|
end
|
2016-02-24 15:57:01 -05:00
|
|
|
end
|
2014-02-24 22:30:49 -05:00
|
|
|
|
2016-02-24 15:57:01 -05:00
|
|
|
if user
|
2014-02-27 19:48:46 -05:00
|
|
|
if sso_record = user.single_sign_on_record
|
|
|
|
sso_record.last_payload = unsigned_payload
|
|
|
|
sso_record.external_id = external_id
|
|
|
|
else
|
2017-11-07 05:38:38 -05:00
|
|
|
if avatar_url.present?
|
|
|
|
Jobs.enqueue(:download_avatar_from_url,
|
|
|
|
url: avatar_url,
|
|
|
|
user_id: user.id,
|
|
|
|
override_gravatar: SiteSetting.sso_overrides_avatar
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
user.create_single_sign_on_record!(
|
2016-10-24 13:55:30 -04:00
|
|
|
last_payload: unsigned_payload,
|
|
|
|
external_id: external_id,
|
|
|
|
external_username: username,
|
|
|
|
external_email: email,
|
|
|
|
external_name: name,
|
|
|
|
external_avatar_url: avatar_url
|
|
|
|
)
|
2014-02-27 19:48:46 -05:00
|
|
|
end
|
|
|
|
end
|
2014-04-15 01:53:48 -04:00
|
|
|
|
2014-02-27 19:48:46 -05:00
|
|
|
user
|
|
|
|
end
|
2014-04-15 01:53:48 -04:00
|
|
|
|
2014-02-27 19:48:46 -05:00
|
|
|
def change_external_attributes_and_override(sso_record, user)
|
2017-11-08 09:55:15 -05:00
|
|
|
if SiteSetting.sso_overrides_email && user.email != Email.downcase(email)
|
2014-02-27 19:48:46 -05:00
|
|
|
user.email = email
|
2017-05-16 16:18:18 -04:00
|
|
|
user.active = false if require_activation
|
2014-02-27 19:48:46 -05:00
|
|
|
end
|
2014-04-15 01:53:48 -04:00
|
|
|
|
2015-08-23 20:24:09 -04:00
|
|
|
if SiteSetting.sso_overrides_username && user.username != username && username.present?
|
2015-03-26 19:10:53 -04:00
|
|
|
user.username = UserNameSuggester.suggest(username || name || email, user.username)
|
2014-02-27 19:48:46 -05:00
|
|
|
end
|
2014-04-15 01:53:48 -04:00
|
|
|
|
2015-08-23 20:24:09 -04:00
|
|
|
if SiteSetting.sso_overrides_name && user.name != name && name.present?
|
2015-05-06 23:52:26 -04:00
|
|
|
user.name = name || User.suggest_name(username.blank? ? email : username)
|
2014-02-27 19:48:46 -05:00
|
|
|
end
|
2014-04-15 01:53:48 -04:00
|
|
|
|
2016-09-15 19:44:45 -04:00
|
|
|
avatar_missing = user.uploaded_avatar_id.nil? || !Upload.exists?(user.uploaded_avatar_id)
|
2015-01-28 10:47:59 -05:00
|
|
|
|
2016-09-15 19:44:45 -04:00
|
|
|
if (avatar_missing || avatar_force_update || SiteSetting.sso_overrides_avatar) && avatar_url.present?
|
2016-10-24 13:55:30 -04:00
|
|
|
avatar_changed = sso_record.external_avatar_url != avatar_url
|
2016-09-15 19:44:45 -04:00
|
|
|
|
2016-10-24 13:55:30 -04:00
|
|
|
if avatar_force_update || avatar_changed || avatar_missing
|
2017-01-19 00:22:24 -05:00
|
|
|
Jobs.enqueue(:download_avatar_from_url, url: avatar_url, user_id: user.id, override_gravatar: SiteSetting.sso_overrides_avatar)
|
2016-10-24 13:55:30 -04:00
|
|
|
end
|
2014-08-19 03:49:14 -04:00
|
|
|
end
|
|
|
|
|
2014-02-27 19:48:46 -05:00
|
|
|
# change external attributes for sso record
|
|
|
|
sso_record.external_username = username
|
|
|
|
sso_record.external_email = email
|
|
|
|
sso_record.external_name = name
|
2014-08-19 03:49:14 -04:00
|
|
|
sso_record.external_avatar_url = avatar_url
|
2014-02-27 19:48:46 -05:00
|
|
|
end
|
2014-04-15 01:53:48 -04:00
|
|
|
end
|