PersistentTokenBasedRememberMeServices.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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 Symfony\Component\Security\Core\Authentication\RememberMe\TokenProviderInterface;
  12. use Symfony\Component\HttpFoundation\Cookie;
  13. use Symfony\Component\HttpFoundation\Response;
  14. use Symfony\Component\HttpFoundation\Request;
  15. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  16. use Symfony\Component\Security\Core\Exception\CookieTheftException;
  17. use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken;
  18. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  19. use Symfony\Component\Security\Core\Util\SecureRandomInterface;
  20. use Psr\Log\LoggerInterface;
  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. private $secureRandom;
  32. /**
  33. * Constructor.
  34. *
  35. * @param array $userProviders
  36. * @param string $key
  37. * @param string $providerKey
  38. * @param array $options
  39. * @param LoggerInterface $logger
  40. * @param SecureRandomInterface $secureRandom
  41. */
  42. public function __construct(array $userProviders, $key, $providerKey, array $options = array(), LoggerInterface $logger = null, SecureRandomInterface $secureRandom)
  43. {
  44. parent::__construct($userProviders, $key, $providerKey, $options, $logger);
  45. $this->secureRandom = $secureRandom;
  46. }
  47. /**
  48. * Sets the token provider
  49. *
  50. * @param TokenProviderInterface $tokenProvider
  51. */
  52. public function setTokenProvider(TokenProviderInterface $tokenProvider)
  53. {
  54. $this->tokenProvider = $tokenProvider;
  55. }
  56. /**
  57. * {@inheritDoc}
  58. */
  59. protected function cancelCookie(Request $request)
  60. {
  61. // Delete cookie on the client
  62. parent::cancelCookie($request);
  63. // Delete cookie from the tokenProvider
  64. if (null !== ($cookie = $request->cookies->get($this->options['name']))
  65. && count($parts = $this->decodeCookie($cookie)) === 2
  66. ) {
  67. list($series, $tokenValue) = $parts;
  68. $this->tokenProvider->deleteTokenBySeries($series);
  69. }
  70. }
  71. /**
  72. * {@inheritDoc}
  73. */
  74. protected function processAutoLoginCookie(array $cookieParts, Request $request)
  75. {
  76. if (count($cookieParts) !== 2) {
  77. throw new AuthenticationException('The cookie is invalid.');
  78. }
  79. list($series, $tokenValue) = $cookieParts;
  80. $persistentToken = $this->tokenProvider->loadTokenBySeries($series);
  81. if ($persistentToken->getTokenValue() !== $tokenValue) {
  82. throw new CookieTheftException('This token was already used. The account is possibly compromised.');
  83. }
  84. if ($persistentToken->getLastUsed()->getTimestamp() + $this->options['lifetime'] < time()) {
  85. throw new AuthenticationException('The cookie has expired.');
  86. }
  87. $series = $persistentToken->getSeries();
  88. $tokenValue = base64_encode($this->secureRandom->nextBytes(64));
  89. $this->tokenProvider->updateToken($series, $tokenValue, new \DateTime());
  90. $request->attributes->set(self::COOKIE_ATTR_NAME,
  91. new Cookie(
  92. $this->options['name'],
  93. $this->encodeCookie(array($series, $tokenValue)),
  94. time() + $this->options['lifetime'],
  95. $this->options['path'],
  96. $this->options['domain'],
  97. $this->options['secure'],
  98. $this->options['httponly']
  99. )
  100. );
  101. return $this->getUserProvider($persistentToken->getClass())->loadUserByUsername($persistentToken->getUsername());
  102. }
  103. /**
  104. * {@inheritDoc}
  105. */
  106. protected function onLoginSuccess(Request $request, Response $response, TokenInterface $token)
  107. {
  108. $series = base64_encode($this->secureRandom->nextBytes(64));
  109. $tokenValue = base64_encode($this->secureRandom->nextBytes(64));
  110. $this->tokenProvider->createNewToken(
  111. new PersistentToken(
  112. get_class($user = $token->getUser()),
  113. $user->getUsername(),
  114. $series,
  115. $tokenValue,
  116. new \DateTime()
  117. )
  118. );
  119. $response->headers->setCookie(
  120. new Cookie(
  121. $this->options['name'],
  122. $this->encodeCookie(array($series, $tokenValue)),
  123. time() + $this->options['lifetime'],
  124. $this->options['path'],
  125. $this->options['domain'],
  126. $this->options['secure'],
  127. $this->options['httponly']
  128. )
  129. );
  130. }
  131. }