Lock auth provider changes behind `ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH=true`

glitch-soc/security/f96e71352244b1fb43fe1cdf6ec7608f7486d29d
Claire 2024-02-09 15:06:07 +01:00
parent c459107df4
commit c0c6082213
1 changed files with 33 additions and 9 deletions

View File

@ -29,6 +29,7 @@ module User::Omniauthable
# Note that this may leave zombie accounts (with no associated identity) which
# can be cleaned up at a later date.
user = signed_in_resource || identity.user
user ||= reattach_for_oauth(auth)
user ||= create_for_oauth(auth)
if identity.user.nil?
@ -39,19 +40,33 @@ module User::Omniauthable
user
end
def reattach_for_oauth(auth)
# If allowed, check if a user exists with the provided email address,
# and return it if they does not have an associated identity with the
# current authentication provider.
# This can be used to provide a choice of alternative auth providers
# or provide smooth gradual transition between multiple auth providers,
# but this is discouraged because any insecure provider will put *all*
# local users at risk, regardless of which provider they registered with.
return unless ENV['ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH'] == 'true'
email, email_is_verified = email_from_oauth(auth)
return unless email_is_verified
user = User.find_by(email: email)
return if user.nil? || Identity.exists?(provider: auth.provider, user_id: user.id)
user
end
def create_for_oauth(auth)
# Check if the user exists with provided email. If no email was provided,
# Create a user for the given auth params. If no email was provided,
# we assign a temporary email and ask the user to verify it on
# the next step via Auth::SetupController.show
strategy = Devise.omniauth_configs[auth.provider.to_sym].strategy
assume_verified = strategy&.security&.assume_email_is_verified
email_is_verified = auth.info.verified || auth.info.verified_email || auth.info.email_verified || assume_verified
email = auth.info.verified_email || auth.info.email
user = User.find_by(email: email) if email_is_verified
return user unless user.nil? && !Identity.exists?(provider: auth.provider, user_id: user.id)
email, email_is_verified = email_from_oauth(auth)
user = User.new(user_params_from_auth(email, auth))
@ -68,6 +83,15 @@ module User::Omniauthable
private
def email_from_oauth(auth)
strategy = Devise.omniauth_configs[auth.provider.to_sym].strategy
assume_verified = strategy&.security&.assume_email_is_verified
email_is_verified = auth.info.verified || auth.info.verified_email || auth.info.email_verified || assume_verified
email = auth.info.verified_email || auth.info.email
[email, email_is_verified]
end
def user_params_from_auth(email, auth)
{
email: email || "#{TEMP_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com",