vendor/symfony/security-http/EventListener/PasswordMigratingListener.php line 45

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Security\Http\EventListener;
  11. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  12. use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface;
  13. use Symfony\Component\PasswordHasher\PasswordHasherInterface;
  14. use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
  15. use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
  16. use Symfony\Component\Security\Http\Authenticator\Passport\Badge\PasswordUpgradeBadge;
  17. use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
  18. use Symfony\Component\Security\Http\Authenticator\Passport\UserPassportInterface;
  19. use Symfony\Component\Security\Http\Event\LoginSuccessEvent;
  20. /**
  21. * @author Wouter de Jong <wouter@wouterj.nl>
  22. *
  23. * @final
  24. */
  25. class PasswordMigratingListener implements EventSubscriberInterface
  26. {
  27. private $hasherFactory;
  28. /**
  29. * @param PasswordHasherFactoryInterface $hasherFactory
  30. */
  31. public function __construct($hasherFactory)
  32. {
  33. if ($hasherFactory instanceof EncoderFactoryInterface) {
  34. trigger_deprecation('symfony/security-core', '5.3', 'Passing a "%s" instance to the "%s" constructor is deprecated, use "%s" instead.', EncoderFactoryInterface::class, __CLASS__, PasswordHasherFactoryInterface::class);
  35. }
  36. $this->hasherFactory = $hasherFactory;
  37. }
  38. public function onLoginSuccess(LoginSuccessEvent $event): void
  39. {
  40. $passport = $event->getPassport();
  41. if (!$passport instanceof UserPassportInterface || !$passport->hasBadge(PasswordUpgradeBadge::class)) {
  42. return;
  43. }
  44. /** @var PasswordUpgradeBadge $badge */
  45. $badge = $passport->getBadge(PasswordUpgradeBadge::class);
  46. $plaintextPassword = $badge->getAndErasePlaintextPassword();
  47. if ('' === $plaintextPassword) {
  48. return;
  49. }
  50. $user = $passport->getUser();
  51. if (null === $user->getPassword()) {
  52. return;
  53. }
  54. $passwordHasher = $this->hasherFactory instanceof EncoderFactoryInterface ? $this->hasherFactory->getEncoder($user) : $this->hasherFactory->getPasswordHasher($user);
  55. if (!$passwordHasher->needsRehash($user->getPassword())) {
  56. return;
  57. }
  58. $passwordUpgrader = $badge->getPasswordUpgrader();
  59. if (null === $passwordUpgrader) {
  60. if (!$passport->hasBadge(UserBadge::class)) {
  61. return;
  62. }
  63. /** @var UserBadge $userBadge */
  64. $userBadge = $passport->getBadge(UserBadge::class);
  65. $userLoader = $userBadge->getUserLoader();
  66. if (\is_array($userLoader) && $userLoader[0] instanceof PasswordUpgraderInterface) {
  67. $passwordUpgrader = $userLoader[0];
  68. } elseif (!$userLoader instanceof \Closure
  69. || !($passwordUpgrader = (new \ReflectionFunction($userLoader))->getClosureThis()) instanceof PasswordUpgraderInterface
  70. ) {
  71. return;
  72. }
  73. }
  74. $passwordUpgrader->upgradePassword($user, $passwordHasher instanceof PasswordHasherInterface ? $passwordHasher->hash($plaintextPassword, $user->getSalt()) : $passwordHasher->encodePassword($plaintextPassword, $user->getSalt()));
  75. }
  76. public static function getSubscribedEvents(): array
  77. {
  78. return [LoginSuccessEvent::class => 'onLoginSuccess'];
  79. }
  80. }