Session: add trusted_device cookie
This commit is contained in:
parent
5690599289
commit
0d8d2de5a6
7 changed files with 133 additions and 8 deletions
|
@ -1,12 +1,17 @@
|
|||
require 'zxcvbn'
|
||||
|
||||
class Administrateurs::ActivateController < ApplicationController
|
||||
include TrustedDeviceConcern
|
||||
|
||||
layout "new_application"
|
||||
|
||||
def new
|
||||
@administrateur = Administrateur.find_inactive_by_token(params[:token])
|
||||
|
||||
if !@administrateur
|
||||
if @administrateur
|
||||
# the administrateur activates its account from an email
|
||||
trust_device
|
||||
else
|
||||
flash.alert = "Le lien de validation d'administrateur a expiré, #{helpers.contact_link('contactez-nous', tags: 'lien expiré')} pour obtenir un nouveau lien."
|
||||
redirect_to root_path
|
||||
end
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
class Gestionnaires::ActivateController < ApplicationController
|
||||
include TrustedDeviceConcern
|
||||
|
||||
layout "new_application"
|
||||
|
||||
def new
|
||||
@gestionnaire = Gestionnaire.with_reset_password_token(params[:token])
|
||||
|
||||
if !@gestionnaire
|
||||
if @gestionnaire
|
||||
# the gestionnaire activates its account from an email
|
||||
trust_device
|
||||
else
|
||||
flash.alert = "Le lien de validation du compte instructeur a expiré, #{helpers.contact_link('contactez-nous', tags: 'lien expiré')} pour obtenir un nouveau lien."
|
||||
redirect_to root_path
|
||||
end
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
class Users::SessionsController < Sessions::SessionsController
|
||||
include TrustedDeviceConcern
|
||||
include ActionView::Helpers::DateHelper
|
||||
|
||||
layout "new_application"
|
||||
|
||||
# GET /resource/sign_in
|
||||
|
@ -24,14 +27,17 @@ class Users::SessionsController < Sessions::SessionsController
|
|||
end
|
||||
|
||||
if gestionnaire_signed_in?
|
||||
gestionnaire = current_gestionnaire
|
||||
if trusted_device?
|
||||
redirect_to gestionnaire_procedures_path
|
||||
else
|
||||
gestionnaire = current_gestionnaire
|
||||
login_token = gestionnaire.login_token!
|
||||
GestionnaireMailer.send_login_token(gestionnaire, login_token).deliver_later
|
||||
|
||||
login_token = gestionnaire.login_token!
|
||||
GestionnaireMailer.send_login_token(gestionnaire, login_token).deliver_later
|
||||
[:user, :gestionnaire, :administrateur].each { |role| sign_out(role) }
|
||||
|
||||
[:user, :gestionnaire, :administrateur].each { |role| sign_out(role) }
|
||||
|
||||
redirect_to link_sent_path(email: gestionnaire.email)
|
||||
redirect_to link_sent_path(email: gestionnaire.email)
|
||||
end
|
||||
elsif user_signed_in?
|
||||
redirect_to after_sign_in_path_for(:user)
|
||||
else
|
||||
|
@ -79,6 +85,9 @@ class Users::SessionsController < Sessions::SessionsController
|
|||
def sign_in_by_link
|
||||
gestionnaire = Gestionnaire.find(params[:id])
|
||||
if gestionnaire&.login_token_valid?(params[:jeton])
|
||||
trust_device
|
||||
flash.notice = "Merci d’avoir confirmé votre connexion. Votre navigateur est maintenant authentifié pour #{TRUSTED_DEVICE_PERIOD.to_i / ActiveSupport::Duration::SECONDS_PER_DAY} jours."
|
||||
|
||||
user = User.find_by(email: gestionnaire.email)
|
||||
administrateur = Administrateur.find_by(email: gestionnaire.email)
|
||||
[user, gestionnaire, administrateur].compact.each { |resource| sign_in(resource) }
|
||||
|
|
25
app/models/concerns/trusted_device_concern.rb
Normal file
25
app/models/concerns/trusted_device_concern.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
module TrustedDeviceConcern
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
TRUSTED_DEVICE_COOKIE_NAME = :trusted_device
|
||||
TRUSTED_DEVICE_PERIOD = 1.month
|
||||
|
||||
def trust_device
|
||||
cookies.encrypted[TRUSTED_DEVICE_COOKIE_NAME] = {
|
||||
value: JSON.generate({ created_at: Time.zone.now }),
|
||||
expires: TRUSTED_DEVICE_PERIOD,
|
||||
httponly: true
|
||||
}
|
||||
end
|
||||
|
||||
def trusted_device?
|
||||
trusted_device_cookie.present? &&
|
||||
Time.zone.now - TRUSTED_DEVICE_PERIOD < JSON.parse(trusted_device_cookie)['created_at']
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def trusted_device_cookie
|
||||
cookies.encrypted[TRUSTED_DEVICE_COOKIE_NAME]
|
||||
end
|
||||
end
|
20
spec/controllers/administrateur/activate_controller_spec.rb
Normal file
20
spec/controllers/administrateur/activate_controller_spec.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
describe Administrateurs::ActivateController, type: :controller do
|
||||
describe '#new' do
|
||||
let(:admin) { create(:administrateur) }
|
||||
let(:token) { admin.send(:set_reset_password_token) }
|
||||
|
||||
before { allow(controller).to receive(:trust_device) }
|
||||
|
||||
context 'when the token is ok' do
|
||||
before { get :new, params: { token: token } }
|
||||
|
||||
it { expect(controller).to have_received(:trust_device) }
|
||||
end
|
||||
|
||||
context 'when the token is bad' do
|
||||
before { get :new, params: { token: 'bad' } }
|
||||
|
||||
it { expect(controller).not_to have_received(:trust_device) }
|
||||
end
|
||||
end
|
||||
end
|
20
spec/controllers/gestionnaires/activate_controller_spec.rb
Normal file
20
spec/controllers/gestionnaires/activate_controller_spec.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
describe Gestionnaires::ActivateController, type: :controller do
|
||||
describe '#new' do
|
||||
let(:gestionnaire) { create(:gestionnaire) }
|
||||
let(:token) { gestionnaire.send(:set_reset_password_token) }
|
||||
|
||||
before { allow(controller).to receive(:trust_device) }
|
||||
|
||||
context 'when the token is ok' do
|
||||
before { get :new, params: { token: token } }
|
||||
|
||||
it { expect(controller).to have_received(:trust_device) }
|
||||
end
|
||||
|
||||
context 'when the token is bad' do
|
||||
before { get :new, params: { token: 'bad' } }
|
||||
|
||||
it { expect(controller).not_to have_received(:trust_device) }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -48,6 +48,20 @@ describe Users::SessionsController, type: :controller do
|
|||
expect(subject.current_administrateur).to be(nil)
|
||||
end
|
||||
|
||||
context 'when the device is trusted' do
|
||||
before do
|
||||
allow(controller).to receive(:trusted_device?).and_return(true)
|
||||
post :create, params: { user: { email: gestionnaire.email, password: gestionnaire.password } }
|
||||
end
|
||||
|
||||
it 'directly log the gestionnaire' do
|
||||
expect(subject).to redirect_to gestionnaire_procedures_path
|
||||
expect(subject.current_user).to be(nil)
|
||||
expect(subject.current_gestionnaire).to eq(gestionnaire)
|
||||
expect(subject.current_administrateur).to be(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context 'signs administrateur in' do
|
||||
# an admin has always an gestionnaire role
|
||||
before { gestionnaire }
|
||||
|
@ -237,6 +251,7 @@ describe Users::SessionsController, type: :controller do
|
|||
context 'when the gestionnaire has non other account' do
|
||||
let(:gestionnaire) { create(:gestionnaire) }
|
||||
before do
|
||||
allow(controller).to receive(:trust_device)
|
||||
post :sign_in_by_link, params: { id: gestionnaire.id, login_token: login_token }
|
||||
end
|
||||
|
||||
|
@ -245,6 +260,7 @@ describe Users::SessionsController, type: :controller do
|
|||
|
||||
it { is_expected.to redirect_to gestionnaire_procedures_path }
|
||||
it { expect(controller.current_gestionnaire).to eq(gestionnaire) }
|
||||
it { expect(controller).to have_received(:trust_device) }
|
||||
end
|
||||
|
||||
context 'when the token is invalid' do
|
||||
|
@ -252,6 +268,7 @@ describe Users::SessionsController, type: :controller do
|
|||
|
||||
it { is_expected.to redirect_to new_user_session_path }
|
||||
it { expect(controller.current_gestionnaire).to be_nil }
|
||||
it { expect(controller).not_to have_received(:trust_device) }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -276,4 +293,28 @@ describe Users::SessionsController, type: :controller do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#trust_device and #trusted_device?' do
|
||||
subject { controller.trusted_device? }
|
||||
|
||||
context 'when the trusted cookie is not present' do
|
||||
it { is_expected.to be false }
|
||||
end
|
||||
|
||||
context 'when the cookie is outdated' do
|
||||
before do
|
||||
Timecop.freeze(Time.zone.now - TrustedDeviceConcern::TRUSTED_DEVICE_PERIOD - 1.minute)
|
||||
controller.trust_device
|
||||
Timecop.return
|
||||
end
|
||||
|
||||
it { is_expected.to be false }
|
||||
end
|
||||
|
||||
context 'when the cookie is ok' do
|
||||
before { controller.trust_device }
|
||||
|
||||
it { is_expected.to be true }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue