As you advance through your Symfony2 developer life, you will probably encounter the need to create a custom Symfony2 password encoder for you project. One of the most common reasons to do this, is when you migrate from an old project (different technology) and you have to keep users together with their working passwords. As you probably cannot find out the plain passwords to be able to just save them to your new database, you will need to replicate the algorithm used to encode them so they will keep working when the transition is over.

How to Create a Custom Symfony2 Password Encoder

In order to add a new, custom, password encoder to your Symfony2 project, you will need to create the encoder class, register it as a service and then specify it in the security.yml configuration file of your project.

Below you will find the necessary code to implement this:

 

AppBundle/Security/Core/Encoder/MyPasswordEncoder.php

<?php

namespace AppBundle\Security\Core\Encoder;

use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;

class MyPasswordEncoder extends BasePasswordEncoder
{
    private $ignorePasswordCase;

    /**
     * Constructor.
     *
     * @param bool $ignorePasswordCase Compare password case-insensitive
     */
    public function __construct($ignorePasswordCase = false)
    {
        $this->ignorePasswordCase = $ignorePasswordCase;
    }

    /**
     * {@inheritdoc}
     */
    public function encodePassword($raw, $salt)
    {
        if ($this->isPasswordTooLong($raw)) {
            throw new BadCredentialsException('Invalid password.');
        }

        return sha1($this->mergePasswordAndSalt($raw, $salt));
    }

    /**
     * {@inheritdoc}
     */
    public function isPasswordValid($encoded, $raw, $salt)
    {
        if ($this->isPasswordTooLong($raw)) {
            return false;
        }

        try {
            $pass2 = $this->encodePassword($raw, $salt);
        } catch (BadCredentialsException $e) {
            return false;
        }

        if (!$this->ignorePasswordCase) {
            return $this->comparePasswords($encoded, $pass2);
        }

        return $this->comparePasswords(strtolower($encoded), strtolower($pass2));
    }
    
    /**
     * Merges a password and a salt.
     *
     * @param string $password the password to be used
     * @param string $salt     the salt to be used
     *
     * @return string a merged password and salt
     *
     * @throws \InvalidArgumentException
     */
    protected function mergePasswordAndSalt($password, $salt)
    {
        if (empty($salt)) {
            return $password;
        }

        return $salt.$password;
    }
}

 

app/config/services.yml

services:
    app.my_password_encoder:
        class: AppBundle\Security\Core\Encoder\MyPasswordEncoder

 

app/config/security.yml

security:
    encoders:
        FOS\UserBundle\Model\UserInterface:
            id: app.my_password_encoder