Expand Up @@ -121,12 +121,12 @@ the given password is valid. This functionality is offered by the:class: `Symfony\\ Component\\ Security\\ Core\\ Authentication\\ Provider\\ DaoAuthenticationProvider `. It fetches the user's data from a:class: `Symfony\\ Component\\ Security\\ Core\\ User\\ UserProviderInterface `, uses a:class: `Symfony\\ Component\\ Security \\ Core \\ Encoder \\ PasswordEncoderInterface ` uses a:class: `Symfony\\ Component\\ PasswordHasher \\ Hasher \\ UserPasswordHasherInterface ` to create a hash of the password and returns an authenticated token if the password was valid:: use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface; use Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider; use Symfony\Component\Security\Core\Encoder\EncoderFactory; use Symfony\Component\Security\Core\User\InMemoryUserProvider; use Symfony\Component\Security\Core\User\UserChecker; Expand All @@ -145,14 +145,14 @@ password was valid:: // for some extra checks: is account enabled, locked, expired, etc. $userChecker = new UserChecker(); // an array of passwordencoders (see below) $encoderFactory = newEncoderFactory (...); // an array of passwordhashers (see below) $hasherFactory = newPasswordHasherFactoryInterface (...); $daoProvider = new DaoAuthenticationProvider( $userProvider, $userChecker, 'secured_area', $encoderFactory $hasherFactory ); $daoProvider->authenticate($unauthenticatedToken); Expand All @@ -165,96 +165,105 @@ password was valid:: It is also possible to let multiple user providers try to find the user's data, using the:class: `Symfony\\ Component\\ Security\\ Core\\ User\\ ChainUserProvider `. The Password Encoder Factory ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. _the-password-encoder-factory : The Password Hasher Factory ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The:class: `Symfony\\ Component\\ Security\\ Core\\ Authentication\\ Provider\\ DaoAuthenticationProvider ` usesan encoder factory to create a passwordencoder for a given type of user. This allows you to use differentencoding strategies for differenttypes of users. The default:class: `Symfony\\ Component\\ Security \\ Core \\ Encoder \\ EncoderFactory `receives an array ofencoders :: usesa factory to create a passwordhasher for a given type of user. This allows you to use differenthashing strategies for different types of users. The default:class: `Symfony\\ Component\\ PasswordHasher \\ Hasher \\ PasswordHasherFactory ` receives an array ofhashers :: use Acme\Entity\LegacyUser; use Symfony\Component\Security\Core\Encoder\EncoderFactory ; use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder ; use Symfony\Component\PasswordHasher\Hasher\MessageDigestPasswordHasher ; use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactory ; use Symfony\Component\Security\Core\User\InMemoryUser; $defaultEncoder = newMessageDigestPasswordEncoder ('sha512', true, 5000); $weakEncoder = newMessageDigestPasswordEncoder ('md5', true, 1); $defaultHasher = newMessageDigestPasswordHasher ('sha512', true, 5000); $weakHasher = newMessageDigestPasswordHasher ('md5', true, 1); $encoders = [ InMemoryUser::class => $defaultEncoder , LegacyUser::class => $weakEncoder , $hashers = [ InMemoryUser::class => $defaultHasher , LegacyUser::class => $weakHasher , // ... ]; $encoderFactory = newEncoderFactory($encoders ); $hasherFactory = newPasswordHasherFactory($hashers ); Eachencoder should implement:class: `Symfony\\ Component\\ Security \\ Core \\ Encoder \\ PasswordEncoderInterface ` Eachhasher should implement:class: `Symfony\\ Component\\ PasswordHasher \\ Hasher \\ UserPasswordHasherInterface ` or be an array with a ``class `` and an ``arguments `` key, which allows the encoder factory to construct the encoder only when it is needed. hasher factory to construct the hasher only when it is needed. .. _creating-a-custom-password-encoder : Creating a custom PasswordEncoder ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Creating a custom PasswordHasher ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There are many built-in passwordencoders . But if you need to create your There are many built-in passwordhasher . But if you need to create your own, it needs to follow these rules: #. The class must implement:class: `Symfony\\ Component\\ Security \\ Core \\ Encoder \\ PasswordEncoderInterface ` (you can also extend:class: `Symfony\\ Component\\ Security \\ Core \\ Encoder \\ BasePasswordEncoder `); #. The class must implement:class: `Symfony\\ Component\\ PasswordHasher \\ Hasher \\ UserPasswordHasherInterface ` (you can also extend:class: `Symfony\\ Component\\ PasswordHasher \\ Hasher \\ UserPasswordHasher `); #. The implementations of :method: `Symfony\\ Component\\ Security \\ Core \\ Encoder \\ PasswordEncoderInterface::encodePassword `:method: `Symfony\\ Component\\ PasswordHasher \\ Hasher \\ UserPasswordHasherInterface::hashPassword ` and :method: `Symfony\\ Component\\ Security \\ Core \\ Encoder \\ PasswordEncoderInterface ::isPasswordValid `:method: `Symfony\\ Component\\ PasswordHasher \\ Hasher \\ UserPasswordHasherInterface ::isPasswordValid ` must first of all make sure the password is not too long, i.e. the password length is no longer than 4096 characters. This is for security reasons (see `CVE-2013-5750 `_), and you can use the :method: `Symfony\\ Component\\ Security \\ Core \\ Encoder \\ BasePasswordEncoder ::isPasswordTooLong `:method: `Symfony\\ Component\\ PasswordHasher \\ Hasher \\ CheckPasswordLengthTrait ::isPasswordTooLong ` method for this check:: use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder; use Symfony\Component\PasswordHasher\Hasher\CheckPasswordLengthTrait; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasher; use Symfony\Component\Security\Core\Exception\BadCredentialsException; classFoobarEncoder extendsBasePasswordEncoder classFoobarHasher extendsUserPasswordHasher { public function encodePassword($raw, $salt) use CheckPasswordLengthTrait; public function hashPassword(UserInterface $user, string $plainPassword): string { if ($this->isPasswordTooLong($raw )) { if ($this->isPasswordTooLong($user->getPassword() )) { throw new BadCredentialsException('Invalid password.'); } // ... } public function isPasswordValid($encoded, $raw, $salt ) public function isPasswordValid(UserInterface $user, string $plainPassword ) { if ($this->isPasswordTooLong($raw )) { if ($this->isPasswordTooLong($user->getPassword() )) { return false; } // ... } } Using Password Encoders ~~~~~~~~~~~~~~~~~~~~~~~ .. _using-password-encoders : When the:method: `Symfony\\ Component\\ Security\\ Core\\ Encoder\\ EncoderFactory::getEncoder ` method of the password encoder factory is called with the user object as its first argument, it will return an encoder of type:class: `Symfony\\ Component\\ Security\\ Core\\ Encoder\\ PasswordEncoderInterface ` which should be used to encode this user's password:: Using Password Hashers ~~~~~~~~~~~~~~~~~~~~~~ When the:method: `Symfony\\ Component\\ PasswordHasher\\ Hasher\\ PasswordHasherFactory::getPasswordHasher ` method of the password hasher factory is called with the user object as its first argument, it will return a hasher of type:class: `Symfony\\ Component\\ PasswordHasher\\ PasswordHasherInterface ` which should be used to hash this user's password:: // a Acme\Entity\LegacyUser instance $user = ...; // the password that was submitted, e.g. when registering $plainPassword = ...; $encoder = $encoderFactory->getEncoder ($user); $hasher = $hasherFactory->getPasswordHasher ($user); // returns $weakEncoder (see above) $encodedPassword = $encoder->encodePassword($plainPassword , $user->getSalt() ); // returns $weakHasher (see above) $hashedPassword = $hasher->hashPassword($user , $plainPassword ); $user->setPassword($encodedPassword ); $user->setPassword($hashedPassword ); // ... save the user Expand All @@ -267,11 +276,7 @@ in) is correct, you can use:: // the submitted password, e.g. from the login form $plainPassword = ...; $validPassword = $encoder->isPasswordValid( $user->getPassword(), // the encoded password $plainPassword, // the submitted password $user->getSalt() ); $validPassword = $hasher->isPasswordValid($user, $plainPassword); Authentication Events --------------------- Expand Down