mirror of
https://github.com/discourse/discourse.git
synced 2024-12-05 09:43:53 +08:00
cdf4d7156e
This allows authenticators to instruct the Auth::Result to override attributes without using the general site settings. This provides an easy migration path for auth plugins which offer their own "overrides email", "overrides username" or "overrides name" settings. With this new api, they can set `overrides_*` on the result object, and the attribute will be overriden regardless of the general site setting. ManagedAuthenticator is updated to use this new API. Plugins which consume ManagedAuthenticator will instantly take advantage of this change.
216 lines
5.0 KiB
Ruby
216 lines
5.0 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class Auth::Result
|
|
ATTRIBUTES = [
|
|
:user,
|
|
:name,
|
|
:username,
|
|
:email,
|
|
:email_valid,
|
|
:extra_data,
|
|
:awaiting_activation,
|
|
:awaiting_approval,
|
|
:authenticated,
|
|
:authenticator_name,
|
|
:requires_invite,
|
|
:not_allowed_from_ip_address,
|
|
:admin_not_allowed_from_ip_address,
|
|
:skip_email_validation,
|
|
:destination_url,
|
|
:omniauth_disallow_totp,
|
|
:failed,
|
|
:failed_reason,
|
|
:failed_code,
|
|
:associated_groups,
|
|
:overrides_email,
|
|
:overrides_username,
|
|
:overrides_name,
|
|
]
|
|
|
|
attr_accessor *ATTRIBUTES
|
|
|
|
# These are stored in the session during
|
|
# account creation. The user cannot read or modify them
|
|
SESSION_ATTRIBUTES = [
|
|
:email,
|
|
:username,
|
|
:email_valid,
|
|
:name,
|
|
:authenticator_name,
|
|
:extra_data,
|
|
:skip_email_validation,
|
|
:associated_groups,
|
|
:overrides_email,
|
|
:overrides_username,
|
|
:overrides_name,
|
|
]
|
|
|
|
def [](key)
|
|
key = key.to_sym
|
|
public_send(key) if ATTRIBUTES.include?(key)
|
|
end
|
|
|
|
def initialize
|
|
@failed = false
|
|
end
|
|
|
|
def email
|
|
@email&.downcase
|
|
end
|
|
|
|
def email_valid=(val)
|
|
if !val.in? [true, false, nil]
|
|
raise ArgumentError, "email_valid should be boolean or nil"
|
|
end
|
|
@email_valid = !!val
|
|
end
|
|
|
|
def failed?
|
|
!!@failed
|
|
end
|
|
|
|
def session_data
|
|
SESSION_ATTRIBUTES.map { |att| [att, public_send(att)] }.to_h
|
|
end
|
|
|
|
def self.from_session_data(data, user:)
|
|
result = new
|
|
data = data.symbolize_keys
|
|
SESSION_ATTRIBUTES.each { |att| result.public_send("#{att}=", data[att]) }
|
|
result.user = user
|
|
result
|
|
end
|
|
|
|
def apply_user_attributes!
|
|
change_made = false
|
|
if (SiteSetting.auth_overrides_username? || overrides_username) && username.present?
|
|
change_made = UsernameChanger.override(user, username)
|
|
end
|
|
|
|
if (SiteSetting.auth_overrides_email || overrides_email || user&.email&.ends_with?(".invalid")) &&
|
|
email_valid &&
|
|
email.present? &&
|
|
user.email != Email.downcase(email)
|
|
user.email = email
|
|
change_made = true
|
|
end
|
|
|
|
if (SiteSetting.auth_overrides_name || overrides_name) && name.present? && user.name != name
|
|
user.name = name
|
|
change_made = true
|
|
end
|
|
|
|
change_made
|
|
end
|
|
|
|
def apply_associated_attributes!
|
|
if authenticator&.provides_groups? && !associated_groups.nil?
|
|
associated_group_ids = []
|
|
|
|
associated_groups.uniq.each do |associated_group|
|
|
begin
|
|
associated_group = AssociatedGroup.find_or_create_by(
|
|
name: associated_group[:name],
|
|
provider_id: associated_group[:id],
|
|
provider_name: extra_data[:provider]
|
|
)
|
|
rescue ActiveRecord::RecordNotUnique
|
|
retry
|
|
end
|
|
|
|
associated_group_ids.push(associated_group.id)
|
|
end
|
|
|
|
user.update(associated_group_ids: associated_group_ids)
|
|
AssociatedGroup.where(id: associated_group_ids).update_all("last_used = CURRENT_TIMESTAMP")
|
|
end
|
|
end
|
|
|
|
def can_edit_name
|
|
!(SiteSetting.auth_overrides_name || overrides_name)
|
|
end
|
|
|
|
def can_edit_username
|
|
!(SiteSetting.auth_overrides_username || overrides_username)
|
|
end
|
|
|
|
def to_client_hash
|
|
if requires_invite
|
|
return { requires_invite: true }
|
|
end
|
|
|
|
if user&.suspended?
|
|
return {
|
|
suspended: true,
|
|
suspended_message: user.suspended_message
|
|
}
|
|
end
|
|
|
|
if omniauth_disallow_totp
|
|
return {
|
|
omniauth_disallow_totp: !!omniauth_disallow_totp,
|
|
email: email
|
|
}
|
|
end
|
|
|
|
if user
|
|
result = {
|
|
authenticated: !!authenticated,
|
|
awaiting_activation: !!awaiting_activation,
|
|
awaiting_approval: !!awaiting_approval,
|
|
not_allowed_from_ip_address: !!not_allowed_from_ip_address,
|
|
admin_not_allowed_from_ip_address: !!admin_not_allowed_from_ip_address
|
|
}
|
|
|
|
result[:destination_url] = destination_url if authenticated && destination_url.present?
|
|
|
|
return result
|
|
end
|
|
|
|
result = {
|
|
email: email,
|
|
username: resolve_username,
|
|
auth_provider: authenticator_name,
|
|
email_valid: !!email_valid,
|
|
can_edit_username: can_edit_username,
|
|
can_edit_name: can_edit_name
|
|
}
|
|
|
|
result[:destination_url] = destination_url if destination_url.present?
|
|
|
|
if SiteSetting.enable_names?
|
|
result[:name] = name.presence
|
|
result[:name] ||= User.suggest_name(username || email) if can_edit_name
|
|
end
|
|
|
|
result
|
|
end
|
|
|
|
private
|
|
|
|
def staged_user
|
|
return @staged_user if defined?(@staged_user)
|
|
if email.present? && email_valid
|
|
@staged_user = User.where(staged: true).find_by_email(email)
|
|
end
|
|
end
|
|
|
|
def username_suggester_attributes
|
|
[username, name, email]
|
|
end
|
|
|
|
def authenticator
|
|
@authenticator ||= Discourse.enabled_authenticators.find { |a| a.name == authenticator_name }
|
|
end
|
|
|
|
def resolve_username
|
|
if staged_user
|
|
if !username.present? || UserNameSuggester.fix_username(username) == staged_user.username
|
|
return staged_user.username
|
|
end
|
|
end
|
|
|
|
UserNameSuggester.suggest(*username_suggester_attributes)
|
|
end
|
|
end
|