18

So I have interesting password validation requirements:

  • When a user signs up, I want them to have to type in password and confirm and be between 6..40 (GOT THIS WORKING 100%)

  • When a user updates their profile, the same validation rules apply (GOT THIS WORKING 100%)

  • When an admin adds a user, they only have to enter the password once and it should be validated (NOT WORKIG)

  • When an admin edits a user and the password field is blank, it shouldn't update the password, if they type something, it should be validated. (PARTIAL WORKING)

    validates :password, :presence => true,
                       :confirmation => true,
                       :length => {:within => 6..40},
                       :unless => :force_submit
    

The only cases I can't cover are when an admin adds a user, it is not validated and when an admin edits a user (and types in a password) it is not validated.

the :force_submit is passed in from the admin form, so the password isn't validated. (So the case of an updating empty password works)

Any ideas/magic?

JJD
  • 47,369
  • 53
  • 194
  • 328
Chris Muench
  • 17,552
  • 67
  • 200
  • 345

4 Answers4

39

Building slightly on the accepted answer, here's the code that I used in a Rails project at work. (Note: We're using devise to handle user authentication, and devise_invitable to create new users.)

PASSWORD_FORMAT = /\A
  (?=.{8,})          # Must contain 8 or more characters
  (?=.*\d)           # Must contain a digit
  (?=.*[a-z])        # Must contain a lower case character
  (?=.*[A-Z])        # Must contain an upper case character
  (?=.*[[:^alnum:]]) # Must contain a symbol
/x

validates :password, 
  presence: true, 
  length: { in: Devise.password_length }, 
  format: { with: PASSWORD_FORMAT }, 
  confirmation: true, 
  on: :create 

validates :password, 
  allow_nil: true, 
  length: { in: Devise.password_length }, 
  format: { with: PASSWORD_FORMAT }, 
  confirmation: true, 
  on: :update
Tom Lord
  • 25,770
  • 4
  • 47
  • 72
  • Perfect! I want to add one more to the password format: Must not contain repeating or sequential characters of 3 or more (ex. 123, abc, zzz, 555). How can I? – Arif Nov 25 '16 at 10:15
  • 2
    @Arif to be honest, my actual recommendation from a security standpoint would be to just use a robust library such as [zxcvbn](https://github.com/envato/zxcvbn-ruby) to check password entropy, rather than trying to re-implement a secure check yourself. – Tom Lord Nov 25 '16 at 10:31
  • 2
    However, if you have a specific, well defined list of "security requirements" (for example, if a client insists that your password policies match their arbitrary standards), then my suggestion would be to write a [custom validator class](http://guides.rubyonrails.org/active_record_validations.html#performing-custom-validations) to handle each scenario explicitly. (Don't neglect to add unit tests!) – Tom Lord Nov 25 '16 at 10:34
31

The below seem to meet my requirements...I am actually now requiring a confirmation for all users.. (It makes the view cleaner). But on an update I am allowing blanks.

  validates :password, :presence => true,
                       :confirmation => true,
                       :length => {:within => 6..40},
                       :on => :create
  validates :password, :confirmation => true,
                       :length => {:within => 6..40},
                       :allow_blank => true,
                       :on => :update
Chris Muench
  • 17,552
  • 67
  • 200
  • 345
  • 1
    I do not understand how this will solve the third requirement of the question. This requirement seems to ask that the admin can leave the password field blank, but edit another field and save the user, without changing the password. The above code seems to allow the user object to be saved, but will change the password to a blank? – Obromios Apr 07 '15 at 23:34
  • The above code does not solve requirement #3, but nor does it behave in the way you describe. All this code does is allows you to UPDATE a user (e.g. change their name, or address, or email, etc) without supplying a password. Although it could be done, I honestly don't think requirement #3 is a good idea anyway - password confirmations are a very simple + effective safety net. – Tom Lord Nov 10 '15 at 14:35
0

this works for blank password on update action:

validates :password, :presence => true, :on => :update,
 :if => lambda{ !password.nil? }

validates :password,
  :confirmation => true,
  :length => { :minimum => 6},
  :if => lambda{ new_record? || !password.nil? }
0

yet another variant

validates_presence_of :password_digest

validates_length_of :password, minimum: 6, if: Proc.new { |user| user.password.present? }
achempion
  • 784
  • 6
  • 14
  • As it stands, this answer is weak. Can you explain what makes this answer different or preferable to other answers? – neontapir Sep 22 '14 at 18:41