Password validation when changing password in CakePHP 3

Welcome to our blog!
May 13, 2014
Show all

Password validation when changing password in CakePHP 3

cakephp3

Save and validate passwords correctly  in CakePHP 3

There are many ways of validating the passwords during the “change password” process. We believe that the best way of doing this is by using the core functionalities that the CakePHP team provides, so let’s see how we managed to complete the task.

For the example we are going to create 3 password fields: one for the old password, one for the new password and one password field for matching control.

First we have to create the “Change password” form. Nevertheless we are going to update only the passwords we have to pass the User object to the view.

public function change_password() { 
    $user =$this->Users->get($this->Auth->user('id')); 
    $this->set('user',$user);
}

Lets create the view file

<div class="users form large-9 medium-9 columns">
<?= $this->Form->create() ?>
<fieldset>
    <legend><?= __('Change password') ?></legend>
    <?= $this->Form->input('old_password',['type' => 'password' , 'label'=>'Old password'])?>
    <?= $this->Form->input('password1',['type'=>'password' ,'label'=>'Password']) ?>
    <?= $this->Form->input('password2',['type' => 'password' , 'label'=>'Repeat password'])?>
</fieldset>
<?= $this->Form->button(__('Save')) ?>
<?= $this->Form->end() ?>

The tricky part 🙂 …
We have to prepare the validation rules before creating the functionalities for saving the Users object. For doing this we need to add some code to the UsersTable class. We need to add some additional dependencies in the beginning of the file

use Cake\Auth\DefaultPasswordHasher;
use Cake\Validation\Validator;
public function validationPassword(Validator $validator )
    {

        $validator
            ->add('old_password','custom',[
                'rule'=>  function($value, $context){
                    $user = $this->get($context['data']['id']);
                    if ($user) {
                        if ((new DefaultPasswordHasher)->check($value, $user->password)) {
                            return true;
                        }
                    }
                    return false;
                },
                'message'=>'The old password does not match the current password!',
            ])
            ->notEmpty('old_password');

        $validator
            ->add('password1', [
                'length' => [
                    'rule' => ['minLength', 6],
                    'message' => 'The password have to be at least 6 characters!',
                ]
            ])
            ->add('password1',[
                'match'=>[
                    'rule'=> ['compareWith','password2'],
                    'message'=>'The passwords does not match!',
                ]
            ])
            ->notEmpty('password1');
        $validator
            ->add('password2', [
                'length' => [
                    'rule' => ['minLength', 6],
                    'message' => 'The password have to be at least 6 characters!',
                ]
            ])
            ->add('password2',[
                'match'=>[
                    'rule'=> ['compareWith','password1'],
                    'message'=>'The passwords does not match!',
                ]
            ])
            ->notEmpty('password2');

        return $validator;
    }

The password by default is saved in hashed format. The hashing functionalities are located in the DefaultPasswordHasher class. When you save the passwords you have to compare the password strings and you have to be sure that both strings are hashed the same way. So the way to validate this is by using custom validation rule. You have to get the user entity by using the $context.

To validate the new passwords you have to implement the built in validation rule “compareWith”. Make sure both the passwords are present.

Now lets get back to the UsersController class. We have to add the update functionality. To use the custom validation rule we created in the UsersTable we need to add some more code in the patchEntity method like this:

public function change_password()
    {
        $user =$this->Users->get($this->Auth->user('id'));
        if (!empty($this->request->data)) {
            $user = $this->Users->patchEntity($user, [
                    'old_password'  => $this->request->data['old_password'],
                    'password'      => $this->request->data['password1'],
                    'password1'     => $this->request->data['password1'],
                    'password2'     => $this->request->data['password2']
                ],
                ['validate' => 'password']
            );
            if ($this->Users->save($user)) {
                $this->Flash->success('The password is successfully changed');
                $this->redirect('/index');
            } else {
                $this->Flash->error('There was an error during the save!');
            }
        }
        $this->set('user',$user);
    }

The ‘validate’ =>’password’ part of the code is the equivalent of calling the ‘validationPassword’ method in the UsersTable. If you write something like ‘validate’ =>’someOtherMethod’ you should create ‘validationSomeOtherMethod’.

Enjoy!

10 Comments

  1. mark says:

    Or you could use the PasswordableBehavior which exists since 2.0 and also applies to a very DRY and clean way in 3.x 🙂
    https://github.com/dereuromark/cakephp-tools/blob/master/src/Model/Behavior/PasswordableBehavior.php

  2. Thanks for writing this tutorial. I was able to add password resetting very quickly to my Cake app.

  3. kibria says:

    I used in 3.1 it works fine. But when i used it again in 3.3, it do not show the error messge but everything work ok.

  4. Joe Naylor says:

    You’ll need to create the form with $user to see the validation errors:
    Form->create($user) ?>

  5. Beatriz says:

    Good!!! Thanks for this tutorial. Too Easy!

  6. Its like you learn my mind! You seem to grasp so much approximately this, such as
    you wrote the e-book in it or something. I feel that you simply could do with a few percent
    to force the message house a bit, however instead of that, this is magnificent blog.

    A great read. I will definitely be back.

  7. I’ve been surfing online more than 4 hours today, yet I never found any interesting article like yours.
    It’s pretty worth enough for me. In my opinion, if all webmasters and bloggers
    made good content as you did, the internet will be a lot more useful than ever before.

  8. BobbuBrowne says:

    Hello! Cool post, amazing!!!

  9. admin says:

    Thanks everyone

  10. Pratiksha says:

    Thanks man its really very helpful.i had wested alot of my time for this.You have solved my problem

Leave a Reply

Your email address will not be published. Required fields are marked *