Added optional two-factor authentication

This commit is contained in:
Eugen Rochko 2017-01-27 20:28:46 +01:00
parent 237cb41ab4
commit ba192f12e3
16 changed files with 146 additions and 15 deletions

View file

@ -7,6 +7,18 @@ code {
max-width: 400px;
padding: 20px;
margin: 0 auto;
p {
font-size: 14px;
line-height: 18px;
color: $color2;
margin-bottom: 20px;
strong {
color: $color5;
font-weight: 500;
}
}
}
.simple_form {
@ -118,7 +130,7 @@ code {
margin-top: 30px;
}
button {
button, .block-button {
display: block;
width: 100%;
border: 0;
@ -128,6 +140,9 @@ code {
font-size: 18px;
padding: 10px;
text-transform: uppercase;
text-decoration: none;
text-align: center;
box-sizing: border-box;
cursor: pointer;
font-weight: 500;
outline: 0;
@ -176,7 +191,7 @@ code {
text-align: center;
a {
color: white;
color: $color5;
text-decoration: none;
&:hover {
@ -200,3 +215,16 @@ code {
font-weight: 500;
}
}
.qr-code {
background: #fff;
padding: 4px;
margin-bottom: 20px;
box-shadow: 0 0 15px rgba($color8, 0.2);
display: inline-block;
svg {
display: block;
margin: 0;
}
}

View file

@ -5,6 +5,8 @@ class Auth::SessionsController < Devise::SessionsController
layout 'auth'
before_action :configure_sign_in_params, only: [:create]
def create
super do |resource|
remember_me(resource)
@ -13,6 +15,10 @@ class Auth::SessionsController < Devise::SessionsController
protected
def configure_sign_in_params
devise_parameter_sanitizer.permit(:sign_in, keys: [:otp_attempt])
end
def after_sign_in_path_for(_resource)
last_url = stored_location_for(:user)

View file

@ -0,0 +1,28 @@
# frozen_string_literal: true
class Settings::TwoFactorAuthsController < ApplicationController
layout 'auth'
before_action :authenticate_user!
def show
return unless current_user.otp_required_for_login
@qrcode = RQRCode::QRCode.new(current_user.otp_provisioning_uri(current_user.email, issuer: Rails.configuration.x.local_domain))
end
def enable
current_user.otp_required_for_login = true
current_user.otp_secret = User.generate_otp_secret
current_user.save!
redirect_to settings_two_factor_auth_path
end
def disable
current_user.otp_required_for_login = false
current_user.save!
redirect_to settings_two_factor_auth_path
end
end

View file

@ -3,7 +3,9 @@
class User < ApplicationRecord
include Settings::Extend
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable
devise :registerable, :recoverable,
:rememberable, :trackable, :validatable, :confirmable,
:two_factor_authenticatable, otp_secret_encryption_key: ENV['OTP_SECRET']
belongs_to :account, inverse_of: :user
accepts_nested_attributes_for :account

View file

@ -4,6 +4,7 @@
= 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

View file

@ -5,4 +5,6 @@
%li= link_to t('settings.preferences'), settings_preferences_path
- if controller_name != 'registrations'
%li= link_to t('auth.change_password'), edit_user_registration_path
%li= link_to t('settings.back'), root_path
- if controller_name != 'two_factor_auths'
%li= link_to t('settings.two_factor_auth'), settings_two_factor_auth_path
%li= link_to t('settings.back'), root_path

View file

@ -0,0 +1,17 @@
- content_for :page_title do
= t('settings.two_factor_auth')
- if current_user.otp_required_for_login
%p= t('two_factor_auth.instructions_html')
.qr-code= raw @qrcode.as_svg(padding: 0, module_size: 5)
.simple_form
= link_to t('two_factor_auth.disable'), disable_settings_two_factor_auth_path, data: { method: 'POST' }, class: 'block-button'
- else
%p= t('two_factor_auth.description_html')
.simple_form
= link_to t('two_factor_auth.enable'), enable_settings_two_factor_auth_path, data: { method: 'POST' }, class: 'block-button'
.form-footer= render "settings/shared/links"