1

I have a form built with some custom validators and they work like a charm, but I am having trouble adding in a new validator that works slightly different to the others.

Basically I need to check data from the form against a value I can usually extract from an Entity.

In this case, I need to grab the users password salt ( using $user->getSalt() ). the problem seems to be that the CallbackValidator class cannot accept any other data, other than $form.

My code:

    $user = $this->get('security.context')->getToken()->getUser();

    $form = $this->createFormBuilder($user)
            ->add('password', 'password')
            ->add('newPassword', 'password', array('label' => 'New Password', 'property_path' => false))
            ->add('confirmPassword', 'password', array('label' => 'Confirm Password', 'property_path' => false))
            ->addValidator(new CallbackValidator(function($form)
            {
                $encoder = new MessageDigestPasswordEncoder('sha1', false, 1);
                $password = $encoder->encodePassword($form['password']->getData(), $user->getSalt());

                if($password != $user->getPassword()) {
                    $form['password']->addError(new FormError('Incorrect password'));
                }
                if($form['confirmPassword']->getData() != $form['newPassword']->getData()) {
                    $form['confirmPassword']->addError(new FormError('Passwords must match.'));
                }
                if($form['newPassword']->getData() == '') {
                    $form['newPassword']->addError(new FormError('Password cannot be blank.'));
                }
            }))
            ->getForm();

Now, this is the error I get:

Fatal error: Call to a member function getSalt() on a non-object in /Sites/src/UserBundle/Controller/DashboardController.php on line 57

Line 57 being:

$password = $encoder->encodePassword($form['password']->getData(), $user->getSalt());

I have tried various things to try and pass the salt to the CallbackValidator and so far the only way is to add it into the form as a hiddne field BUT this is not acceptable as it is a security risk and I would also need to add the hashed password as a hidden field in order to match the input against.

There must be a simpler way to do this?

1 Answer 1

6

Your $user variable coming from $this->get('security.context')->getToken()->getUser(); is not defined in the scope of the anonymous function.

Contrary to languages like javascript that inherits from parent scope (automatic closure), you need to ask explicitly php to do it. The use keyword is especially made for that: http://php.net/manual/en/functions.anonymous.php

$user = new User;
function($form) use($user) { 

};

Here is a better explanation :) Javascript closures vs PHP closures, what's the difference?

So all you should have to do is modify your code like that:

$user = $this->get('security.context')->getToken()->getUser();

$form = $this->createFormBuilder($user)
        ->add('password', 'password')
        ->add('newPassword', 'password', array('label' => 'New Password', 'property_path' => false))
        ->add('confirmPassword', 'password', array('label' => 'Confirm Password', 'property_path' => false))
        ->addValidator(new CallbackValidator(function($form) use($user)
        {
            $encoder = new MessageDigestPasswordEncoder('sha1', false, 1);
            $password = $encoder->encodePassword($form['password']->getData(), $user->getSalt());

            if($password != $user->getPassword()) {
                $form['password']->addError(new FormError('Incorrect password'));
            }
            if($form['confirmPassword']->getData() != $form['newPassword']->getData()) {
                $form['confirmPassword']->addError(new FormError('Passwords must match.'));
            }
            if($form['newPassword']->getData() == '') {
                $form['newPassword']->addError(new FormError('Password cannot be blank.'));
            }
        }))
        ->getForm();
Sign up to request clarification or add additional context in comments.

3 Comments

Super, that seems to of helped..ish! I am now having trouble with the validator it self. It seems that $user->getPAssword() is fetching the unencrypted password (no idea how, i have it set to sha1) so I tried to compared $form['password']->getData() to the user password but not mater what I typed, it validated it, argh!
The Form binding will write the 'password' field value in $user->password. So $user->getPassword() is exactly the same as $form['password']->getdata() once you bind it. You should remove the ->add('password', 'password') line so that the form doesn't update the $user->password value.
Haha, I literally just figured that out and fixed it!! Just came back to give you a tick :D

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.