Skip to content
Snippets Groups Projects
Commit 23b997ae authored by Eugen Rochko's avatar Eugen Rochko
Browse files

Split 2FA login into two prompts

parent 36c57ef8
No related branches found
No related tags found
No related merge requests found
......@@ -5,18 +5,33 @@ class Auth::SessionsController < Devise::SessionsController
layout 'auth'
before_action :configure_sign_in_params, only: [:create]
skip_before_action :require_no_authentication, only: [:create]
prepend_before_action :authenticate_with_two_factor, if: :two_factor_enabled?, only: [:create]
def create
super do |resource|
remember_me(resource)
flash[:notice] = nil
end
end
def destroy
super
flash[:notice] = nil
end
protected
def configure_sign_in_params
devise_parameter_sanitizer.permit(:sign_in, keys: [:otp_attempt])
def find_user
if session[:otp_user_id]
User.find(session[:otp_user_id])
elsif user_params[:email]
User.find_by(email: user_params[:email])
end
end
def user_params
params.require(:user).permit(:email, :password, :otp_attempt)
end
def after_sign_in_path_for(_resource)
......@@ -28,4 +43,38 @@ class Auth::SessionsController < Devise::SessionsController
last_url || root_path
end
end
def two_factor_enabled?
find_user.try(:otp_required_for_login?)
end
def valid_otp_attempt?(user)
user.validate_and_consume_otp!(user_params[:otp_attempt])
end
def authenticate_with_two_factor
user = self.resource = find_user
if user_params[:otp_attempt].present? && session[:otp_user_id]
authenticate_with_two_factor_via_otp(user)
elsif user && user.valid_password?(user_params[:password])
prompt_for_two_factor(user)
end
end
def authenticate_with_two_factor_via_otp(user)
if valid_otp_attempt?(user)
session.delete(:otp_user_id)
remember_me(user)
sign_in(user)
else
flash.now[:alert] = I18n.t('users.invalid_otp_token')
prompt_for_two_factor(user)
end
end
def prompt_for_two_factor(user)
session[:otp_user_id] = user.id
render :two_factor
end
end
......@@ -4,7 +4,6 @@
= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f|
= f.input :email, autofocus: true, placeholder: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }
= f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.password') }
= f.input :otp_attempt, placeholder: t('simple_form.labels.defaults.otp_attempt'), input_html: { 'aria-label' => t('simple_form.labels.defaults.otp_attempt') }
.actions
= f.button :button, t('auth.login'), type: :submit
......
- content_for :page_title do
= t('auth.login')
= simple_form_for(resource, as: resource_name, url: session_path(resource_name), method: :post) do |f|
= f.input :otp_attempt, placeholder: t('simple_form.labels.defaults.otp_attempt'), input_html: { 'aria-label' => t('simple_form.labels.defaults.otp_attempt') }, required: true, autofocus: true, autocomplete: 'off'
.actions
= f.button :button, t('auth.login'), type: :submit
.form-footer= render "auth/shared/links"
......@@ -114,5 +114,6 @@ en:
instructions_html: "<strong>Scan this QR code into Google Authenticator or a similiar app on your phone</strong>. From now on, that app will generate tokens that you will have to enter when logging in."
users:
invalid_email: The e-mail address is invalid
invalid_otp_token: Invalid two-factor code
will_paginate:
page_gap: "&hellip;"
......@@ -21,7 +21,7 @@ en:
locked: Make account private
new_password: New password
note: Bio
otp_attempt: If enabled, two-factor token
otp_attempt: Two-factor code
password: Password
username: Username
interactions:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment