2014-02-24 22:30:49 -05:00
|
|
|
require_dependency 'single_sign_on'
|
|
|
|
class DiscourseSingleSignOn < SingleSignOn
|
|
|
|
def self.sso_url
|
|
|
|
SiteSetting.sso_url
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.sso_secret
|
|
|
|
SiteSetting.sso_secret
|
|
|
|
end
|
|
|
|
|
2014-02-25 17:58:30 -05:00
|
|
|
def self.generate_url(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-02-24 22:30:49 -05:00
|
|
|
sso.to_url
|
|
|
|
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
|
|
|
|
|
|
|
|
def lookup_or_create_user
|
|
|
|
sso_record = SingleSignOnRecord.where(external_id: external_id).first
|
2014-02-27 19:48:46 -05:00
|
|
|
|
|
|
|
if sso_record && user = sso_record.user
|
2014-02-24 22:30:49 -05:00
|
|
|
sso_record.last_payload = unsigned_payload
|
|
|
|
else
|
2014-02-27 19:48:46 -05:00
|
|
|
user = match_email_or_create_user
|
|
|
|
sso_record = user.single_sign_on_record
|
|
|
|
end
|
|
|
|
|
|
|
|
# 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
|
|
|
|
|
2014-02-25 18:28:03 -05:00
|
|
|
if sso_record && (user = sso_record.user) && !user.active
|
|
|
|
user.active = true
|
|
|
|
user.save
|
|
|
|
user.enqueue_welcome_message('welcome_user')
|
|
|
|
end
|
2014-02-27 19:48:46 -05:00
|
|
|
|
|
|
|
# optionally save the user and sso_record if they have changed
|
|
|
|
user.save!
|
|
|
|
sso_record.save!
|
2014-02-25 18:28:03 -05:00
|
|
|
|
2014-02-24 22:30:49 -05:00
|
|
|
sso_record && sso_record.user
|
|
|
|
end
|
2014-02-27 19:48:46 -05:00
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def match_email_or_create_user
|
|
|
|
user = User.where(email: Email.downcase(email)).first
|
|
|
|
|
|
|
|
user_params = {
|
|
|
|
email: email,
|
|
|
|
name: User.suggest_name(name || username || email),
|
|
|
|
username: UserNameSuggester.suggest(username || name || email),
|
|
|
|
}
|
2014-02-24 22:30:49 -05:00
|
|
|
|
2014-02-27 19:48:46 -05:00
|
|
|
if user || user = User.create(user_params)
|
|
|
|
if sso_record = user.single_sign_on_record
|
|
|
|
sso_record.last_payload = unsigned_payload
|
|
|
|
sso_record.external_id = external_id
|
|
|
|
else
|
|
|
|
sso_record = user.create_single_sign_on_record(last_payload: unsigned_payload,
|
|
|
|
external_id: external_id,
|
|
|
|
external_username: username,
|
|
|
|
external_email: email,
|
|
|
|
external_name: name)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
user
|
|
|
|
end
|
|
|
|
|
|
|
|
def change_external_attributes_and_override(sso_record, user)
|
|
|
|
if SiteSetting.sso_overrides_email && email != sso_record.external_email
|
|
|
|
# set the user's email to whatever came in the payload
|
|
|
|
user.email = email
|
|
|
|
end
|
|
|
|
|
|
|
|
if SiteSetting.sso_overrides_username && username != sso_record.external_username && user.username != username
|
|
|
|
# we have an external username change, and the user's current username doesn't match
|
|
|
|
# run it through the UserNameSuggester to override it
|
|
|
|
user.username = UserNameSuggester.suggest(username || name || email)
|
|
|
|
end
|
|
|
|
|
|
|
|
if SiteSetting.sso_overrides_name && name != sso_record.external_name && user.name != name
|
|
|
|
# we have an external name change, and the user's current name doesn't match
|
|
|
|
# run it through the name suggester to override it
|
|
|
|
user.name = User.suggest_name(name || username || email)
|
|
|
|
end
|
|
|
|
|
|
|
|
# change external attributes for sso record
|
|
|
|
sso_record.external_username = username
|
|
|
|
sso_record.external_email = email
|
|
|
|
sso_record.external_name = name
|
|
|
|
end
|
|
|
|
end
|