vendor/symfony/security-http/Authenticator/RememberMeAuthenticator.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\Authenticator;
  11. use Psr\Log\LoggerInterface;
  12. use Symfony\Component\HttpFoundation\Request;
  13. use Symfony\Component\HttpFoundation\Response;
  14. use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
  15. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  16. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  17. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  18. use Symfony\Component\Security\Core\Exception\CookieTheftException;
  19. use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
  20. use Symfony\Component\Security\Core\Exception\UserNotFoundException;
  21. use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
  22. use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
  23. use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
  24. use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
  25. use Symfony\Component\Security\Http\RememberMe\RememberMeDetails;
  26. use Symfony\Component\Security\Http\RememberMe\RememberMeHandlerInterface;
  27. use Symfony\Component\Security\Http\RememberMe\ResponseListener;
  28. /**
  29. * The RememberMe *Authenticator* performs remember me authentication.
  30. *
  31. * This authenticator is executed whenever a user's session
  32. * expired and a remember-me cookie was found. This authenticator
  33. * then "re-authenticates" the user using the information in the
  34. * cookie.
  35. *
  36. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  37. * @author Wouter de Jong <wouter@wouterj.nl>
  38. *
  39. * @final
  40. */
  41. class RememberMeAuthenticator implements InteractiveAuthenticatorInterface
  42. {
  43. private $rememberMeHandler;
  44. private $secret;
  45. private $tokenStorage;
  46. private $cookieName;
  47. private $logger;
  48. public function __construct(RememberMeHandlerInterface $rememberMeHandler, string $secret, TokenStorageInterface $tokenStorage, string $cookieName, ?LoggerInterface $logger = null)
  49. {
  50. $this->rememberMeHandler = $rememberMeHandler;
  51. $this->secret = $secret;
  52. $this->tokenStorage = $tokenStorage;
  53. $this->cookieName = $cookieName;
  54. $this->logger = $logger;
  55. }
  56. public function supports(Request $request): ?bool
  57. {
  58. // do not overwrite already stored tokens (i.e. from the session)
  59. if (null !== $this->tokenStorage->getToken()) {
  60. return false;
  61. }
  62. if (($cookie = $request->attributes->get(ResponseListener::COOKIE_ATTR_NAME)) && null === $cookie->getValue()) {
  63. return false;
  64. }
  65. if (!$request->cookies->has($this->cookieName) || !\is_scalar($request->cookies->all()[$this->cookieName] ?: null)) {
  66. return false;
  67. }
  68. if (null !== $this->logger) {
  69. $this->logger->debug('Remember-me cookie detected.');
  70. }
  71. // the `null` return value indicates that this authenticator supports lazy firewalls
  72. return null;
  73. }
  74. public function authenticate(Request $request): PassportInterface
  75. {
  76. $rawCookie = $request->cookies->get($this->cookieName);
  77. if (!$rawCookie) {
  78. throw new \LogicException('No remember-me cookie is found.');
  79. }
  80. $rememberMeCookie = RememberMeDetails::fromRawCookie($rawCookie);
  81. return new SelfValidatingPassport(new UserBadge($rememberMeCookie->getUserIdentifier(), function () use ($rememberMeCookie) {
  82. return $this->rememberMeHandler->consumeRememberMeCookie($rememberMeCookie);
  83. }));
  84. }
  85. /**
  86. * @deprecated since Symfony 5.4, use {@link createToken()} instead
  87. */
  88. public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface
  89. {
  90. trigger_deprecation('symfony/security-http', '5.4', 'Method "%s()" is deprecated, use "%s::createToken()" instead.', __METHOD__, __CLASS__);
  91. return $this->createToken($passport, $firewallName);
  92. }
  93. public function createToken(Passport $passport, string $firewallName): TokenInterface
  94. {
  95. return new RememberMeToken($passport->getUser(), $firewallName, $this->secret);
  96. }
  97. public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
  98. {
  99. return null; // let the original request continue
  100. }
  101. public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
  102. {
  103. if (null !== $this->logger) {
  104. if ($exception instanceof UserNotFoundException) {
  105. $this->logger->info('User for remember-me cookie not found.', ['exception' => $exception]);
  106. } elseif ($exception instanceof UnsupportedUserException) {
  107. $this->logger->warning('User class for remember-me cookie not supported.', ['exception' => $exception]);
  108. } elseif (!$exception instanceof CookieTheftException) {
  109. $this->logger->debug('Remember me authentication failed.', ['exception' => $exception]);
  110. }
  111. }
  112. return null;
  113. }
  114. public function isInteractive(): bool
  115. {
  116. return true;
  117. }
  118. }