superadmin: check complexity password server side
This commit is contained in:
parent
94b3ec942b
commit
15a395fbc7
4 changed files with 59 additions and 4 deletions
|
@ -28,6 +28,14 @@ class SuperAdmin < ApplicationRecord
|
|||
devise :rememberable, :trackable, :validatable, :lockable, :async, :recoverable,
|
||||
:two_factor_authenticatable, :otp_secret_encryption_key => Rails.application.secrets.otp_secret_key
|
||||
|
||||
validate :password_complexity, if: -> (u) { Devise.password_length.include?(u.password.try(:size)) }
|
||||
|
||||
def password_complexity
|
||||
if password.present? && ZxcvbnService.new(password).score < PASSWORD_COMPLEXITY_FOR_ADMIN
|
||||
errors.add(:password, :not_strong)
|
||||
end
|
||||
end
|
||||
|
||||
def enable_otp!
|
||||
self.otp_secret = SuperAdmin.generate_otp_secret
|
||||
self.otp_required_for_login = true
|
||||
|
|
|
@ -60,11 +60,15 @@ fr:
|
|||
|
||||
activerecord:
|
||||
attributes:
|
||||
default_attributes: &default_attributes
|
||||
password: 'Le mot de passe'
|
||||
user:
|
||||
siret: 'Numéro SIRET'
|
||||
password: 'Le mot de passe'
|
||||
<< : *default_attributes
|
||||
instructeur:
|
||||
password: 'Le mot de passe'
|
||||
<< : *default_attributes
|
||||
super_admin:
|
||||
<< : *default_attributes
|
||||
errors:
|
||||
messages:
|
||||
not_a_phone: 'Numéro de téléphone invalide'
|
||||
|
@ -80,7 +84,7 @@ fr:
|
|||
email:
|
||||
invalid: invalide
|
||||
taken: déjà utilisé
|
||||
password:
|
||||
password: &password
|
||||
too_short: 'est trop court'
|
||||
not_strong: 'n’est pas assez complexe'
|
||||
password_confirmation:
|
||||
|
@ -96,6 +100,10 @@ fr:
|
|||
taken: déjà utilisé
|
||||
password:
|
||||
too_short: 'est trop court'
|
||||
super_admin:
|
||||
attributes:
|
||||
password:
|
||||
<< : *password
|
||||
procedure:
|
||||
attributes:
|
||||
path:
|
||||
|
|
|
@ -2,7 +2,7 @@ FactoryBot.define do
|
|||
sequence(:super_admin_email) { |n| "plop#{n}@plop.com" }
|
||||
factory :super_admin do
|
||||
email { generate(:super_admin_email) }
|
||||
password { 'my-s3cure-p4ssword' }
|
||||
password { '{My-$3cure-p4ssWord}' }
|
||||
otp_required_for_login { true }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -61,4 +61,43 @@ describe SuperAdmin, type: :model do
|
|||
expect { subject }.to change { super_admin.reload.otp_secret }.to(nil)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#password_complexity' do
|
||||
# This password list is sorted by password complexity, according to zxcvbn (used for complexity evaluation)
|
||||
# 0 - too guessable: risky password. (guesses < 10^3)
|
||||
# 1 - very guessable: protection from throttled online attacks. (guesses < 10^6)
|
||||
# 2 - somewhat guessable: protection from unthrottled online attacks. (guesses < 10^8)
|
||||
# 3 - safely unguessable: moderate protection from offline slow-hash scenario. (guesses < 10^10)
|
||||
# 4 - very unguessable: strong protection from offline slow-hash scenario. (guesses >= 10^10)
|
||||
passwords = ['pass', '12pass23', 'démarches ', 'démarches-simple', '{My-$3cure-p4ssWord}']
|
||||
min_complexity = PASSWORD_COMPLEXITY_FOR_ADMIN
|
||||
|
||||
let(:email) { 'mail@beta.gouv.fr' }
|
||||
let(:super_admin) { build(:super_admin, email: email, password: password) }
|
||||
|
||||
subject do
|
||||
super_admin.save
|
||||
super_admin.errors.full_messages
|
||||
end
|
||||
|
||||
context 'when password is too short' do
|
||||
let(:password) { 's' * (PASSWORD_MIN_LENGTH - 1) }
|
||||
|
||||
it { expect(subject).to eq(["Le mot de passe est trop court"]) }
|
||||
end
|
||||
|
||||
context 'when password is too simple' do
|
||||
passwords[0..(min_complexity - 1)].each do |password|
|
||||
let(:password) { password }
|
||||
|
||||
it { expect(subject).to eq(["Le mot de passe n’est pas assez complexe"]) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when password is acceptable' do
|
||||
let(:password) { passwords[min_complexity] }
|
||||
|
||||
it { expect(subject).to eq([]) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue