1

I have a problem with the typical form to change the password in which I first put you to put your current password.

The theory is very simple and is explained in the symfony doc but it gives me an error like the current password is incorrect

My Model:

namespace BackendBundle\Form\Model;

use Symfony\Component\Security\Core\Validator\Constraints as SecurityAssert;
use Symfony\Component\Validator\Constraints as Assert;

class ChangePassword
{
/**
 * @SecurityAssert\UserPassword(
 *     message = "Error al poner la contraseña actual"
 * )
 */
 protected $oldPassword;

/**
 * @Assert\Length(
 *     min = 6,
 *     minMessage = "El password tiene que tener al menos 6 caracteres"
 * )
 */
 protected $password;


   /////
public function getOldPassword() {
    return $this->oldPassword;
}

public function setOldPassword($oldPassword) {
    $this->oldPassword = $oldPassword;
}
  /////
public function getPassword() {
    return $this->oldPassword;
}

public function setPassword($oldPassword) {
    $this->oldPassword = $oldPassword;
}
}

The fomType:

->add('oldPassword', PasswordType::class, array(
                'label' => 'Ponga su password actual',
                'mapped' => false,
                ))
->add('password', RepeatedType::class, array(
                "required" => "required",
                'type' => PasswordType::class,
                'invalid_message' => 'Los dos password deben coincidir',
                'first_options' => array('label' => 'Password nuevo', "attr" 
=> array("class" => "form-password form-control")),
                'second_options' => array('label' => 'Repita el Password nuevo', "attr" => array("class" => "form-password form-control"))
                    )
            )

​ And little else must be done (I think) in addition to the controler create the view with the form and then collect the data of the new password, etc, but as I say, I sent error of not valid field that checks the password and I do not know if it's because the password I keep it encrypted My security.yml I have it as

encoders:
    BackendBundle\Entity\Users:
        algorithm: bcrypt
        cost: 6

My action Controller:

   public function passAction(Request $request) {
    $changePasswordModel = new ChangePassword();
    $form = $this->createForm(ChangePasswordType::class, $changePasswordModel);

    $form->handleRequest($request);

    if ($form->isSubmitted()) {

        if ($form->isValid()) {

            $user = $this->getUser(); //metemos como id la del usuario sacado de su sesion
            $encoder = $this->container->get('security.encoder_factory')->getEncoder($user);
            $password = $encoder->encodePassword($changePasswordModel->getPassword(), $user->getSalt());
            $user->setPassword($password);
            $em->persist($user);
            $flush = $em->flush();
            if ($flush === null) {
                $this->session->getFlashBag()->add('success', 'El usuario se ha editado correctamente');
                return $this->redirectToRoute("others_show"); //redirigimos la pagina si se incluido correctamete
            } else {
                $this->session->getFlashBag()->add('warning', 'Error al editar el password');
            }
        } else {
            dump($form->getErrors());
            $this->session->getFlashBag()->add('warning', 'El password no se ha editado por un error en el formulario !');
        }
    }

    return $this->render('BackendBundle:Others:editPass.html.twig', array(
                'form' => $form->createView(),
    ));
}

It tells me that the form is not correct because the old password is incorrect. What could be wrong?

3 Answers3

2

You don't need to check the validity of the old password yourself. Symfony does this for you, when you call form->isValid(). So you can drop this:

    $currentPassword = $form->get("oldPassword")->getData();

    $encoder = $this->container->get('security.encoder_factory')->getEncoder($user);
    $isValid = $encoder->isPasswordValid($user->getPassword(), $currentPassword, $user->getSalt());
    $encoderService = $this->container->get('security.password_encoder');
    $match = $encoderService->isPasswordValid($user, $currentPassword);
    dump($match);

Instead, start your Controller like this:

public function passAction(Request $request) {

    $changePasswordModel = new PasswordChange();
    $form = $this->createForm(PasswordChangeType::class, $changePasswordModel);

    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) { // will check if old password was valid
        $user = $this->getUser(); //metemos como id la del usuario sacado de su sesion
        $encoder = $this->container->get('security.encoder_factory')->getEncoder($user);
        $password = $encoder->encodePassword($changePasswordModel->getPassword(), $user->getSalt());
        $user->setPassword($password);
        // go on with saving $user to database
Spunc
  • 338
  • 1
  • 14
  • Thank you very much, but unfortunately I am still generating the same error, incorrect old password. I had previously tried the same thing that is detailed in this answer https://stackoverflow.com/questions/9129784/implement-change-password-in-symfony2 – Carlos Salgado Feb 04 '18 at 16:35
  • Edited version of my answer should solve the problem. But also have a look at my comment to your additional information. There is a typo that will also be a problem. – Spunc Feb 05 '18 at 19:36
  • Thank you very much again for your help Spunc, I have edited my question and I have put the code with your contributions, but still giving me an error, as if @SecurityAssert \ UserPassword did not work correctly – Carlos Salgado Feb 08 '18 at 12:05
  • 1
    After reviewing your code, I saw that at least two things must be changed: #1 Your `getPassword()` and `setPassword()` of your `ChangePassword` class are incorrect. They read and write `$oldPassword`. #2 In your FormType, remove: `'mapped' => false` - you want it to be mapped. – Spunc Feb 09 '18 at 09:16
1

Thank you very much @Spunc for your help, I've finally gotten it to work correctly ;-)

I put the correct complete code in case there are other users with problems. Thanks again

passControler

namespace BackendBundle\Controller;

use BackendBundle\Entity\Users;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\Session;

class PassController extends Controller {
public function passAction(Request $request) {
    $changePasswordModel = new ChangePassword();
    $form = $this->createForm(ChangePasswordType::class, $changePasswordModel);

    $form->handleRequest($request);

    if ($form->isSubmitted()) {

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $user = $this->getUser(); //metemos como id la del usuario sacado de su sesion
            $encoder = $this->container->get('security.encoder_factory')->getEncoder($user);
            $password = $encoder->encodePassword($changePasswordModel->getPassword(), $user->getSalt());
            $user->setPassword($password);
            $em->persist($user);
            $flush = $em->flush();
            if ($flush === null) {
                $this->session->getFlashBag()->add('success', 'El usuario se ha editado correctamente');
                return $this->redirectToRoute("others_show"); //redirigimos la pagina si se incluido correctamete
            } else {
                $this->session->getFlashBag()->add('warning', 'Error al editar el password');
            }
        } else {
           // dump($form->getErrors());
            $this->session->getFlashBag()->add('warning', 'El password no se ha editado por un error en el formulario !');
        }
    }

    return $this->render('BackendBundle:Others:editPass.html.twig', array(
                'form' => $form->createView(),
    ));
}
}

model ChangePassword

namespace BackendBundle\Form\Model;

use Symfony\Component\Security\Core\Validator\Constraints as SecurityAssert;
use Symfony\Component\Validator\Constraints as Assert;

class ChangePassword {

/**
 * @SecurityAssert\UserPassword(
 *     message = "Error al poner la contraseña actual"
 * )
 */
protected $oldPassword;

/**
 * @Assert\Length(
 *     min = 6,
 *     minMessage = "El password tiene que tener al menos 6 caracteres"
 * )
 */
protected $password;


public function getOldPassword() {
    return $this->oldPassword;
}

public function setOldPassword($oldPassword) {
    $this->oldPassword = $oldPassword;
    return $this;
}


public function getPassword() {
    return $this->password;
}

public function setPassword($password) {
    $this->password = $password;
    return $this;
}

}

ChangePasswordType

namespace BackendBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;

class ChangePasswordType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{

    $builder
                ->add('oldPassword', PasswordType::class, array(
                'label' => 'Ponga su password actual',
                ))
            ->add('password', RepeatedType::class, array(
                "required" => "required",
                'type' => PasswordType::class,
                'invalid_message' => 'Los dos password deben coincidir',
                'first_options' => array('label' => 'Password nuevo', "attr" => array("class" => "form-password form-control")),
                'second_options' => array('label' => 'Repita el Password nuevo', "attr" => array("class" => "form-password form-control"))
                    )
            )
    ;
}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => 'Acme\UserBundle\Form\Model\ChangePassword',
    ));
}

public function getName()
{
    return 'change_passwd';
}
}
0

I had the same problem with the "@SecurityAssert\UserPassword" assertion. I startet in my form with

"mapped" => false

That fixed my issue. Thank's a lot. Just one remark for the future visitors of the problem. The signiture of for the password encoder has changed.

In Symfony 4.4 a setup like this will encode the new password correctly

$user->setPassword(
    $passwordEncoder->encodePassword( $user,
    $changePasswordModel->getPassword()
) );