vendor/symfony/src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     1 <?php
       
     2 
       
     3 namespace Symfony\Component\Security\Http\RememberMe;
       
     4 
       
     5 use Symfony\Component\Security\Core\Authentication\RememberMe\TokenProviderInterface;
       
     6 use Symfony\Component\HttpFoundation\Cookie;
       
     7 use Symfony\Component\HttpFoundation\Response;
       
     8 use Symfony\Component\HttpFoundation\Request;
       
     9 use Symfony\Component\Security\Core\Exception\AuthenticationException;
       
    10 use Symfony\Component\Security\Core\Exception\CookieTheftException;
       
    11 use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken;
       
    12 use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
       
    13 use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
       
    14 
       
    15 /*
       
    16  * This file is part of the Symfony package.
       
    17  *
       
    18  * (c) Fabien Potencier <fabien@symfony.com>
       
    19  *
       
    20  * For the full copyright and license information, please view the LICENSE
       
    21  * file that was distributed with this source code.
       
    22  */
       
    23 
       
    24 /**
       
    25  * Concrete implementation of the RememberMeServicesInterface which needs
       
    26  * an implementation of TokenProviderInterface for providing remember-me
       
    27  * capabilities.
       
    28  *
       
    29  * @author Johannes M. Schmitt <schmittjoh@gmail.com>
       
    30  */
       
    31 class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices
       
    32 {
       
    33     private $tokenProvider;
       
    34 
       
    35     /**
       
    36      * Sets the token provider
       
    37      *
       
    38      * @param TokenProviderInterface $tokenProvider
       
    39      * @return void
       
    40      */
       
    41     public function setTokenProvider(TokenProviderInterface $tokenProvider)
       
    42     {
       
    43         $this->tokenProvider = $tokenProvider;
       
    44     }
       
    45 
       
    46     /**
       
    47      * {@inheritDoc}
       
    48      */
       
    49     public function logout(Request $request, Response $response, TokenInterface $token)
       
    50     {
       
    51         parent::logout($request, $response, $token);
       
    52 
       
    53         if (null !== ($cookie = $request->cookies->get($this->options['name']))
       
    54             && count($parts = $this->decodeCookie($cookie)) === 2
       
    55         ) {
       
    56             list($series, $tokenValue) = $parts;
       
    57             $this->tokenProvider->deleteTokenBySeries($series);
       
    58         }
       
    59     }
       
    60 
       
    61     /**
       
    62      * {@inheritDoc}
       
    63      */
       
    64     protected function processAutoLoginCookie(array $cookieParts, Request $request)
       
    65     {
       
    66         if (count($cookieParts) !== 2) {
       
    67             throw new AuthenticationException('The cookie is invalid.');
       
    68         }
       
    69 
       
    70         list($series, $tokenValue) = $cookieParts;
       
    71         $persistentToken = $this->tokenProvider->loadTokenBySeries($series);
       
    72 
       
    73         if ($persistentToken->getTokenValue() !== $tokenValue) {
       
    74             $this->tokenProvider->deleteTokenBySeries($series);
       
    75 
       
    76             throw new CookieTheftException('This token was already used. The account is possibly compromised.');
       
    77         }
       
    78 
       
    79         if ($persistentToken->getLastUsed()->getTimestamp() + $this->options['lifetime'] < time()) {
       
    80             throw new AuthenticationException('The cookie has expired.');
       
    81         }
       
    82 
       
    83         $series = $persistentToken->getSeries();
       
    84         $tokenValue = $this->generateRandomValue();
       
    85         $this->tokenProvider->updateToken($series, $tokenValue, new \DateTime());
       
    86         $request->attributes->set(self::COOKIE_ATTR_NAME,
       
    87             new Cookie(
       
    88                 $this->options['name'],
       
    89                 $this->encodeCookie(array($series, $tokenValue)),
       
    90                 time() + $this->options['lifetime'],
       
    91                 $this->options['path'],
       
    92                 $this->options['domain'],
       
    93                 $this->options['secure'],
       
    94                 $this->options['httponly']
       
    95             )
       
    96         );
       
    97 
       
    98         return $this->getUserProvider($persistentToken->getClass())->loadUserByUsername($persistentToken->getUsername());
       
    99     }
       
   100 
       
   101     /**
       
   102      * {@inheritDoc}
       
   103      */
       
   104     protected function onLoginSuccess(Request $request, Response $response, TokenInterface $token)
       
   105     {
       
   106         $series = $this->generateRandomValue();
       
   107         $tokenValue = $this->generateRandomValue();
       
   108 
       
   109         $this->tokenProvider->createNewToken(
       
   110             new PersistentToken(
       
   111                 get_class($user = $token->getUser()),
       
   112                 $user->getUsername(),
       
   113                 $series,
       
   114                 $tokenValue,
       
   115                 new \DateTime()
       
   116             )
       
   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 
       
   132     /**
       
   133      * Generates a cryptographically strong random value
       
   134      *
       
   135      * @return string
       
   136      */
       
   137     protected function generateRandomValue()
       
   138     {
       
   139         if (function_exists('openssl_random_pseudo_bytes')) {
       
   140             $bytes = openssl_random_pseudo_bytes(64, $strong);
       
   141 
       
   142             if (true === $strong && false !== $bytes) {
       
   143                 return base64_encode($bytes);
       
   144             }
       
   145         }
       
   146 
       
   147         if (null !== $this->logger) {
       
   148             $this->logger->warn('Could not produce a cryptographically strong random value. Please install/update the OpenSSL extension.');
       
   149         }
       
   150 
       
   151         return base64_encode(hash('sha512', uniqid(mt_rand(), true), true));
       
   152     }
       
   153 }