Module: AuthenticatesWithTwoFactor

Extended by:
ActiveSupport::Concern
Included in:
SessionsController
Defined in:
app/controllers/concerns/authenticates_with_two_factor.rb

Overview

AuthenticatesWithTwoFactor

Controller concern to handle two-factor authentication

Instance Method Summary collapse

Instance Method Details

#authenticate_with_two_factorObject



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'app/controllers/concerns/authenticates_with_two_factor.rb', line 43

def authenticate_with_two_factor
  user = self.resource = find_user
  return handle_locked_user(user) unless user.can?(:log_in)
  return handle_changed_user(user) if user_password_changed?(user)

  if user_params[:otp_attempt].present? && session[:otp_user_id]
    authenticate_with_two_factor_via_otp(user)
  elsif user_params[:device_response].present? && session[:otp_user_id]
    authenticate_with_two_factor_via_webauthn(user)
  elsif user && user.valid_password?(user_params[:password])
    prompt_for_two_factor(user)
  end
rescue ActiveRecord::RecordInvalid => e
  # We expect User to always be valid.
  # Otherwise, raise internal server error instead of unprocessable entity to improve observability/alerting
  if e.record.is_a?(User)
    raise e.message
  else
    raise e
  end
end

#handle_locked_user(user) ⇒ Object



33
34
35
36
37
# File 'app/controllers/concerns/authenticates_with_two_factor.rb', line 33

def handle_locked_user(user)
  clear_two_factor_attempt!

  locked_user_redirect(user)
end

#locked_user_redirect(user) ⇒ Object



39
40
41
# File 'app/controllers/concerns/authenticates_with_two_factor.rb', line 39

def locked_user_redirect(user)
  redirect_to new_user_session_path, alert: locked_user_redirect_alert(user)
end

#prompt_for_two_factor(user) ⇒ Object

Store the user’s ID in the session for later retrieval and render the two factor code prompt

The user must have been authenticated with a valid login and password before calling this method!

user - User record

Returns nil



18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'app/controllers/concerns/authenticates_with_two_factor.rb', line 18

def prompt_for_two_factor(user)
  # Set @user for Devise views
  @user = user # rubocop:disable Gitlab/ModuleWithInstanceVariables

  return handle_locked_user(user) unless user.can?(:log_in)

  session[:otp_user_id] = user.id
  session[:user_password_hash] = Digest::SHA256.hexdigest(user.encrypted_password)

  add_gon_variables
  setup_webauthn_authentication(user)

  render 'devise/sessions/two_factor'
end