1

I am using devise for authentication in a rails app. I want to add validation for some password complexity rules. It seems I don't have access to the raw password at the model level before it has been hashed. As such, I cannot validate that the raw password provided conforms to the password complexity rules that I have set. The only other way I can do this is at the controller-level. However, I'm afraid that that approach will pollute my controller. Any ideas about how I can perform the validation without having to install any other gem?

monk
  • 87
  • 1
  • 3
  • 10

2 Answers2

2

Here is a simple method of adding a password strength / complexity requirement at the model level.

#app/models/user.rb

validate :password_complexity

def password_complexity
  if password.present?
     if !password.match(/^(?=.*[a-z])(?=.*[A-Z])/) 
       errors.add :password, "Password complexity requirement not met"
     end
  end
end

Duplication: Devise custom password validation leads invalid user in console

Official docs: https://github.com/heartcombo/devise/wiki/How-To:-Set-up-simple-password-complexity-requirements

Roshan
  • 905
  • 9
  • 21
  • Hey, I tried this but ran into a small problem: `password` is actually the `encrypted_password`. Therefore, with this approach, it appears that I'd be validating the encrypted_password instead of the raw password. – monk Jul 28 '17 at 12:50
  • This is also written in the Devise page itself: https://github.com/plataformatec/devise/wiki/How-To:-Set-up-simple-password-complexity-requirements @monk - did it work for you? – dowi Dec 23 '19 at 12:46
  • how is this supposed to work if password is encrypted hash? – LE-HU Apr 04 '22 at 22:37
1

The best option for create complex passwords without additional gems and it also works on rails 6.0.3.2 ruby 2.7.1 https://github.com/heartcombo/devise/wiki/How-To:-Set-up-simple-password-complexity-requirements

Solution from Devise wiki (above link)

Here is a simple method of adding a password strength / complexity requirement to devise without using devise security extension (using extension is recommended.)

Example: add the following line to app/models/user.rb. Edit Regex to your liking

  validate :password_complexity
  
  def password_complexity
    # Regexp extracted from https://stackoverflow.com/questions/19605150/regex-for-password-must-contain-at-least-eight-characters-at-least-one-number-a
    return if password.blank? || password =~ /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,70}$/

    errors.add :password, 'Complexity requirement not met. Length should be 8-70 characters and include: 1 uppercase, 1 lowercase, 1 digit and 1 special character'
  end

Afterwards, password created by the user (or admin) must meet the regex requirements.

If the password length is checked by another method (such as config.password_length), this suits better:

  def password_complexity
    # Regexp extracted from https://stackoverflow.com/questions/19605150/regex-for-password-must-contain-at-least-eight-characters-at-least-one-number-a
    return if password.blank? || password =~ /(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-])/

    errors.add :password, 'Complexity requirement not met. Please use: 1 uppercase, 1 lowercase, 1 digit and 1 special character'
  end
Michał Zalewski
  • 3,123
  • 2
  • 24
  • 37
Nezir
  • 6,727
  • 12
  • 54
  • 78