Skip to content
Share this..

Heavy duty password validation in CakePHP

2008 August 5
by Eddie

When validating passwords for new users or changing passwords for existent users there are three main concerns.

  1. You want passwords to match
  2. You want passwords to be ‘strong’ (meaning complex)
  3. You want to store the passwords under some encryption

*Strong in this case means a minimum of 8 characters with no whitespace. It must contain upper case and lower case letters, and at least 1 digit or special character.

If your using 1.2 RC1 or higher, jump to here.

The caveat there is obvious, if your using one way encryption like md5, you must validate before you encrypt. Using the built in var $validate will gooey this all up, forcing you to hash before you save and then trying instead to validate the hashed password.

So instead I wrote a very simple function for use in the user model to validate against all three of these concerns.

If you just want to get some regular expressions to use in PHP or other languages, read this article.

Otherwise you may find this implementation useful.

This article is outdated for newer releases of CakePHP. Instead please see my article on validation in CakePHP 1.2

The User Controller and Registration Action

First we’ll have a look in the users controller’s registration action. You’ll notice we don’t mess with the password or validation, and just call our save method as normal.

in app/controllers/user_controller.php

   	if ($this->User->save($this->data)) { 
           /*
            * Data was saved successfully
            */					
		$this->Session->setFlash('The User has been registered, please login');
		$this->redirect('/');
	}

Wow, thats almost like a fresh baked action.. good sign.

The Model and Validate function

Now we leverage a built in function call validates() to check for our pattern, check for matching passwords, and finally hash the prevailing password before saving.

In app/models/user.php

/*
* This method gets called automagiclly for us, and does 3 things
* validates against a regular expression, ensuring it is 'strong'
* confirms the user entered the same password twice
* if both above passs, it hashes the surviving password to be saved
*/
	function validates($options = array())
	{
		$pass=$this->validatePassword();
		return $pass;
	} 
	function validatePassword(){	
		//die($this->data['User']['password'].' :: '.$this->data['User']['confirmpassword']);
		if(isset($this->data['User']['confirmpassword'])){
			if(!preg_match('/(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/',$this->data['User']['password'])){
				//doesnt mneet our 1 upper, one lower, 1 digit or special character require,ent
				$this->invalidate('password');
		    	$this->data['User']['password']=null;
			}elseif($this->data['User']['password']!=$this->data['User']['confirmpassword']){
		    	$this->invalidate('checkpassword');
		    	//they didnt condifrm password
			}else{
				//hash passwordbefore saving
				$this->data['User']['password']=md5($this->data['User']['password']);		   					
			}
 
		}
		 $errors = $this->invalidFields();
 
		 return count($errors) == 0;
	}

So the idea is that we call the models save method, which in turn calls our validates method. The alidates method will print cause one of two error messages, or allow the successful save.

So where do those two error messages go? But in our views of course. Since I’m using the register action for this example, I will stick with my register view


The Registration View and Dual Validation Error messages


So we have two text boxes, password and confirm password.

We also use 2 error messages, one for bad pattern matching or ‘weak ‘ password the other for missing password confirmation, or bad password confirmation.

in app/views/users/register.ctp

<div class="required"> 
	<?php echo $form->label('User/password', 'Password');?>
 	<?php echo $form->password('User/password', array('size' => '30'));?>
	<?php echo $form->error('User/password', 'The password must contain both upper case and lower case characters with at least 1 digit or special character');?>
</div>
<div class="required"> 
	<?php echo $form->label('User/confirmpassword', 'Confirm Password');?>
 	<?php echo $form->password('User/confirmpassword', array('size' => '30'));?>
	<?php echo $form->error('User/checkpassword', 'Please Be Sure Passwords Match.');?>
</div>


1.2 Users


For CakePHP 1.2 we can follow a slightly different, and in my opinion an preferable way.
1.2 Does a nice job of allowing for custom Validation. You can set criteria within your model, and even set all error messages to prevent typos and redundant data. Best of all we can call a function to run in place of a rule for more complex actions (like checking for match then hashing)

Read my more recent article ‘Complex Validation with CakePHP 1.2

7 Responses leave one →
  1. August 6, 2008

    When overriding a framework method, make sure to use the same method signature as the original method, otherwise you may get an unwanted effect 😉 In your case this means to use the following signature:

    validates($options = array())

  2. Eddie permalink*
    August 6, 2008

    @Daniel
    Much appreciated! I’ll make the change in my code and the post.

  3. August 19, 2008

    Is this for CakePHP 1.1? The $validate methods for 1.2 are a lot cleaner :-)

  4. Eddie permalink*
    August 23, 2008

    @Richard

    This works on 1.1 or 1.2
    I’m not sure I understand your meaning, the $validate variable in the models? How would you match 2 passwords, check for a high-security pattern, and then finally hash? If you have a sweeter way, please share :)

  5. Eddie permalink*
    September 7, 2008

    Apologies:

    A few poster comments were lost this last week due to a DB restore.

    Please do not take offense, and re-post at will.

  6. September 29, 2008

    I just had to do this myself but followed some other tutes so went a different route:

    I placed treatment of the password, hashing and so forth in beforeSave().

    Used a function placed in app_model to see if the passwords match:
    http://bakery.cakephp.org/articles/view/using-equalto-validation-to-compare-two-form-fields

    Then placed the regex for testing quality of the password in the validate rules:
    ‘password’ => array(‘isRequired’ => array(‘rule’ => array(‘custom’, ‘/(?=^.{7,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/’),
    ‘required’ => true,
    ‘allowEmpty’ => false,
    ‘on’ => ‘create’,
    ‘message’ => ‘Password should be at least 7 characters, must have at least 1 upper case, lower case and numeric or special character.’),
    ‘identicalFieldValues’ => array(‘rule’ => array(‘identicalFieldValues’, ‘password_confirm’ ),
    ‘message’ => ‘Passwords do not match.’,
    ‘on’ => ‘create’))

    Also used multiple validation sets which were handy:
    http://snook.ca/archives/cakephp/multiple_validation_sets_cakephp/

    Using 1.2, no auth component.

Trackbacks and Pingbacks

  1. Validating Complex Passwords | Edward A. Webb (.com)

Leave a Reply

Note: You can use basic XHTML in your comments. Your email address will never be published.

Subscribe to this comment feed via RSS