discourse/app/services/user_authenticator.rb
Chris Alberti 375a36e2ef
Don't require password to create users with previous authentication (#32201)
Don't require password to create users with previous authentication in
the session, regardless of email/email verification during user creation

Before my changes we were calling `user.password_required!` in
`UserAuthenticator.authenticated?` based on whether authentication
session data contained a matching email address and email verified
externally. I believe `authenticated?` is intended for our own email
validation during the activation process, but shouldn't be a gate for
password requirement.

Even when we were setting `user.password_required`, then during user
creation we were creating random passwords to get around the blank
password restriction when creating accounts with external auth.

After my change we can remove the random password creation because we no
longer require a password when the session has previous authentication
info at all.

Looks like this extra password requirement may have been introduced as a
side effect during a previous refactor of `UserController` here:
51eff92170
Before that change, password requirement was simply based on whether
session[:authentication] existed, but after that change it was based on
the email/email_valid fields as well.
2025-04-15 10:35:49 -05:00

70 lines
1.6 KiB
Ruby

# frozen_string_literal: true
class UserAuthenticator
def initialize(
user,
session,
authenticator_finder: Users::OmniauthCallbacksController,
require_password: true
)
@user = user
@session = session
if session&.dig(:authentication) && session[:authentication].is_a?(Hash)
@auth_result = Auth::Result.from_session_data(session[:authentication], user: user)
end
@authenticator_finder = authenticator_finder
@require_password = require_password
end
def start
if authenticated?
@user.active = true
@auth_result.apply_user_attributes!
end
@user.password_required! if !@auth_result && @require_password
@user.skip_email_validation = true if @auth_result && @auth_result.skip_email_validation
end
def has_authenticator?
!!authenticator
end
def finish
if authenticator
authenticator.after_create_account(@user, @auth_result)
confirm_email
end
if @session&.dig(:authentication)
@session[:authentication] = @auth_result = nil
@session[:authenticated_with_oauth] = true
end
end
def email_valid?
@auth_result&.email_valid
end
def authenticated?
return false if !@auth_result
return false if @auth_result&.email&.downcase != @user.email.downcase
return false if !@auth_result.email_valid
true
end
private
def confirm_email
@user.activate if authenticated?
end
def authenticator
if authenticator_name
@authenticator ||= @authenticator_finder.find_authenticator(authenticator_name)
end
end
def authenticator_name
@auth_result&.authenticator_name
end
end