1
votes

I have an old Symfony 2 application with fos user that contains passwords encoded with the sha512 algorithm.

I would like after migrating the table users to the new application symfony 4 with fos user 2.1 to be able to modify the password with the algorithm bcrypt when the user is logging with a listener.

It is possible under Symfony to have several encoders but the problem is that we can not duplicate the same encoder with different algorithm like:

    encoders:
        FOS\UserBundle\Model\UserInterface: sha512
        FOS\UserBundle\Model\UserInterface: bcrypt

or with this code, I have this error message:

Unrecognized option "FOS\UserBundle\Model\UserInterface" under "security.encoders.old"

    encoders:
        old:
            FOS\UserBundle\Model\UserInterface:
            algorithm: sha512
        new:
            FOS\UserBundle\Model\UserInterface:
            algorithm: bcrypt
2

2 Answers

2
votes

Update to Symfony 4.4, which was released earlier this week.

4.4 has support for Password Migrations.

Declare your encoder as "auto", so Symfony will always pick the best possible encoder for a new password, and pick the appropriate one for old passwords:

encoders:
        FOS\UserBundle\Model\UserInterface:
            algorithm: auto
            cost: 14

Then make your UserRepository implement PasswordUpgraderInterface. This interface includes a method upgradePassword() which is called whenever a hash needs to be upgraded to a newer algorithm.

The example implementation from the docs goes like this:

// ...
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;

class UserRepository extends EntityRepository implements PasswordUpgraderInterface
{
    // ...

    public function upgradePassword(UserInterface $user, string $newEncodedPassword): void
    {
        // this code is only an example; the exact code will depend on
        // your own application needs
        $user->setPassword($newEncodedPassword);
        $this->getEntityManager()->flush($user);
    }
}

Adjust this to your use case, and you'll be able to keep your password hashed updated to the latest hashing algorithm transparently as the users log in to your application.

Since modern hashing algorithms store the hash on the same field than the hashed password, if your old hashing mechanism depended on a separate hash field, you can set null it during this process, since it's no longer necessary.

1
votes

Good news for this new feature. So I migrated to version 4.4.

I changed the custom user provider of Fos User with:


use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;

public function upgradePassword(SecurityUserInterface $user, string $newEncodedPassword): void
    {
        // set the new encoded password on the User object
        $user->setPassword($newEncodedPassword);
        //you can set salt to null because the new encoders use algorithms without the salt
        $user->setSalt(null);
        // store the new password
        $this->userManager->updateUser($user);
    }

And that works!

But a problem with Fos User bundle, when a user modifies his password this creates a new salt which is not used. The main thing is that it works.