PersistentTokenBasedRememberMeServices.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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\RememberMe;
  11. use Psr\Log\LoggerInterface;
  12. use Symfony\Component\HttpFoundation\Cookie;
  13. use Symfony\Component\HttpFoundation\Request;
  14. use Symfony\Component\HttpFoundation\Response;
  15. use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken;
  16. use Symfony\Component\Security\Core\Authentication\RememberMe\TokenProviderInterface;
  17. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  18. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  19. use Symfony\Component\Security\Core\Exception\CookieTheftException;
  20. use Symfony\Component\Security\Core\Util\SecureRandomInterface;
  21. /**
  22. * Concrete implementation of the RememberMeServicesInterface which needs
  23. * an implementation of TokenProviderInterface for providing remember-me
  24. * capabilities.
  25. *
  26. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  27. */
  28. class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices
  29. {
  30. private $tokenProvider;
  31. /**
  32. * Note: The $secureRandom parameter is deprecated since version 2.8 and will be removed in 3.0.
  33. *
  34. * @param array $userProviders
  35. * @param string $secret
  36. * @param string $providerKey
  37. * @param array $options
  38. * @param LoggerInterface $logger
  39. * @param SecureRandomInterface $secureRandom
  40. */
  41. public function __construct(array $userProviders, $secret, $providerKey, array $options = array(), LoggerInterface $logger = null, SecureRandomInterface $secureRandom = null)
  42. {
  43. if (null !== $secureRandom) {
  44. @trigger_error('The $secureRandom parameter in '.__METHOD__.' is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
  45. }
  46. parent::__construct($userProviders, $secret, $providerKey, $options, $logger);
  47. }
  48. public function setTokenProvider(TokenProviderInterface $tokenProvider)
  49. {
  50. $this->tokenProvider = $tokenProvider;
  51. }
  52. /**
  53. * {@inheritdoc}
  54. */
  55. protected function cancelCookie(Request $request)
  56. {
  57. // Delete cookie on the client
  58. parent::cancelCookie($request);
  59. // Delete cookie from the tokenProvider
  60. if (null !== ($cookie = $request->cookies->get($this->options['name']))
  61. && 2 === \count($parts = $this->decodeCookie($cookie))
  62. ) {
  63. list($series) = $parts;
  64. $this->tokenProvider->deleteTokenBySeries($series);
  65. }
  66. }
  67. /**
  68. * {@inheritdoc}
  69. */
  70. protected function processAutoLoginCookie(array $cookieParts, Request $request)
  71. {
  72. if (2 !== \count($cookieParts)) {
  73. throw new AuthenticationException('The cookie is invalid.');
  74. }
  75. list($series, $tokenValue) = $cookieParts;
  76. $persistentToken = $this->tokenProvider->loadTokenBySeries($series);
  77. if (!hash_equals($persistentToken->getTokenValue(), $tokenValue)) {
  78. throw new CookieTheftException('This token was already used. The account is possibly compromised.');
  79. }
  80. if ($persistentToken->getLastUsed()->getTimestamp() + $this->options['lifetime'] < time()) {
  81. throw new AuthenticationException('The cookie has expired.');
  82. }
  83. $tokenValue = base64_encode(random_bytes(64));
  84. $this->tokenProvider->updateToken($series, $tokenValue, new \DateTime());
  85. $request->attributes->set(self::COOKIE_ATTR_NAME,
  86. new Cookie(
  87. $this->options['name'],
  88. $this->encodeCookie(array($series, $tokenValue)),
  89. time() + $this->options['lifetime'],
  90. $this->options['path'],
  91. $this->options['domain'],
  92. $this->options['secure'],
  93. $this->options['httponly']
  94. )
  95. );
  96. return $this->getUserProvider($persistentToken->getClass())->loadUserByUsername($persistentToken->getUsername());
  97. }
  98. /**
  99. * {@inheritdoc}
  100. */
  101. protected function onLoginSuccess(Request $request, Response $response, TokenInterface $token)
  102. {
  103. $series = base64_encode(random_bytes(64));
  104. $tokenValue = base64_encode(random_bytes(64));
  105. $this->tokenProvider->createNewToken(
  106. new PersistentToken(
  107. \get_class($user = $token->getUser()),
  108. $user->getUsername(),
  109. $series,
  110. $tokenValue,
  111. new \DateTime()
  112. )
  113. );
  114. $response->headers->setCookie(
  115. new Cookie(
  116. $this->options['name'],
  117. $this->encodeCookie(array($series, $tokenValue)),
  118. time() + $this->options['lifetime'],
  119. $this->options['path'],
  120. $this->options['domain'],
  121. $this->options['secure'],
  122. $this->options['httponly']
  123. )
  124. );
  125. }
  126. }