summaryrefslogtreecommitdiffstats
path: root/Http/RememberMe
diff options
context:
space:
mode:
Diffstat (limited to 'Http/RememberMe')
-rw-r--r--Http/RememberMe/AbstractRememberMeServices.php27
-rw-r--r--Http/RememberMe/PersistentTokenBasedRememberMeServices.php55
-rw-r--r--Http/RememberMe/RememberMeServicesInterface.php6
-rw-r--r--Http/RememberMe/ResponseListener.php39
-rw-r--r--Http/RememberMe/TokenBasedRememberMeServices.php2
5 files changed, 89 insertions, 40 deletions
diff --git a/Http/RememberMe/AbstractRememberMeServices.php b/Http/RememberMe/AbstractRememberMeServices.php
index d61a6ce..ae61dd7 100644
--- a/Http/RememberMe/AbstractRememberMeServices.php
+++ b/Http/RememberMe/AbstractRememberMeServices.php
@@ -22,7 +22,7 @@ use Symfony\Component\Security\Core\Exception\CookieTheftException;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Cookie;
-use Symfony\Component\HttpKernel\Log\LoggerInterface;
+use Psr\Log\LoggerInterface;
/**
* Base class implementing the RememberMeServicesInterface
@@ -47,6 +47,8 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface
* @param string $providerKey
* @param array $options
* @param LoggerInterface $logger
+ *
+ * @throws \InvalidArgumentException
*/
public function __construct(array $userProviders, $key, $providerKey, array $options = array(), LoggerInterface $logger = null)
{
@@ -89,9 +91,11 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface
*
* @param Request $request
*
- * @return TokenInterface
+ * @return TokenInterface|null
+ *
+ * @throws CookieTheftException
*/
- public final function autoLogin(Request $request)
+ final public function autoLogin(Request $request)
{
if (null === $cookie = $request->cookies->get($this->options['name'])) {
return;
@@ -125,7 +129,7 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface
}
} catch (UnsupportedUserException $unSupported) {
if (null !== $this->logger) {
- $this->logger->warn('User class for remember-me cookie not supported.');
+ $this->logger->warning('User class for remember-me cookie not supported.');
}
} catch (AuthenticationException $invalid) {
if (null !== $this->logger) {
@@ -156,7 +160,7 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface
*
* @param Request $request
*/
- public final function loginFail(Request $request)
+ final public function loginFail(Request $request)
{
$this->cancelCookie($request);
$this->onLoginFail($request);
@@ -170,8 +174,11 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface
* @param Response $response
* @param TokenInterface $token The token that resulted in a successful authentication
*/
- public final function loginSuccess(Request $request, Response $response, TokenInterface $token)
+ final public function loginSuccess(Request $request, Response $response, TokenInterface $token)
{
+ // Make sure any old remember-me cookies are cancelled
+ $this->cancelCookie($request);
+
if (!$token->getUser() instanceof UserInterface) {
if (null !== $this->logger) {
$this->logger->debug('Remember-me ignores token since it does not contain a UserInterface implementation.');
@@ -192,6 +199,12 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface
$this->logger->debug('Remember-me was requested; setting cookie.');
}
+ // Remove attribute from request that sets a NULL cookie.
+ // It was set by $this->cancelCookie()
+ // (cancelCookie does other things too for some RememberMeServices
+ // so we should still call it at the start of this method)
+ $request->attributes->remove(self::COOKIE_ATTR_NAME);
+
$this->onLoginSuccess($request, $response, $token);
}
@@ -221,7 +234,7 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface
*/
abstract protected function onLoginSuccess(Request $request, Response $response, TokenInterface $token);
- protected final function getUserProvider($class)
+ final protected function getUserProvider($class)
{
foreach ($this->userProviders as $provider) {
if ($provider->supportsClass($class)) {
diff --git a/Http/RememberMe/PersistentTokenBasedRememberMeServices.php b/Http/RememberMe/PersistentTokenBasedRememberMeServices.php
index 8944672..9f4013d 100644
--- a/Http/RememberMe/PersistentTokenBasedRememberMeServices.php
+++ b/Http/RememberMe/PersistentTokenBasedRememberMeServices.php
@@ -19,6 +19,7 @@ use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\CookieTheftException;
use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Util\SecureRandomInterface;
/**
* Concrete implementation of the RememberMeServicesInterface which needs
@@ -30,6 +31,24 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices
{
private $tokenProvider;
+ private $secureRandom;
+
+ /**
+ * Constructor.
+ *
+ * @param array $userProviders
+ * @param string $key
+ * @param string $providerKey
+ * @param array $options
+ * @param LoggerInterface $logger
+ * @param SecureRandomInterface $secureRandom
+ */
+ public function __construct(array $userProviders, $key, $providerKey, array $options = array(), LoggerInterface $logger = null, SecureRandomInterface $secureRandom)
+ {
+ parent::__construct($userProviders, $key, $providerKey, $options, $logger);
+
+ $this->secureRandom = $secureRandom;
+ }
/**
* Sets the token provider
@@ -44,10 +63,12 @@ class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices
/**
* {@inheritDoc}
*/
- public function logout(Request $request, Response $response, TokenInterface $token)
+ protected function cancelCookie(Request $request)
{
- parent::logout($request, $response, $token);
+ // Delete cookie on the client
+ parent::cancelCookie($request);
+ // Delete cookie from the tokenProvider
if (null !== ($cookie = $request->cookies->get($this->options['name']))
&& count($parts = $this->decodeCookie($cookie)) === 2
) {
@@ -69,8 +90,6 @@ class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices
$persistentToken = $this->tokenProvider->loadTokenBySeries($series);
if ($persistentToken->getTokenValue() !== $tokenValue) {
- $this->tokenProvider->deleteTokenBySeries($series);
-
throw new CookieTheftException('This token was already used. The account is possibly compromised.');
}
@@ -79,7 +98,7 @@ class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices
}
$series = $persistentToken->getSeries();
- $tokenValue = $this->generateRandomValue();
+ $tokenValue = $this->secureRandom->nextBytes(64);
$this->tokenProvider->updateToken($series, $tokenValue, new \DateTime());
$request->attributes->set(self::COOKIE_ATTR_NAME,
new Cookie(
@@ -101,8 +120,8 @@ class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices
*/
protected function onLoginSuccess(Request $request, Response $response, TokenInterface $token)
{
- $series = $this->generateRandomValue();
- $tokenValue = $this->generateRandomValue();
+ $series = $this->secureRandom->nextBytes(64);
+ $tokenValue = $this->secureRandom->nextBytes(64);
$this->tokenProvider->createNewToken(
new PersistentToken(
@@ -126,26 +145,4 @@ class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices
)
);
}
-
- /**
- * Generates a cryptographically strong random value
- *
- * @return string
- */
- protected function generateRandomValue()
- {
- if (function_exists('openssl_random_pseudo_bytes')) {
- $bytes = openssl_random_pseudo_bytes(64, $strong);
-
- if (true === $strong && false !== $bytes) {
- return base64_encode($bytes);
- }
- }
-
- if (null !== $this->logger) {
- $this->logger->warn('Could not produce a cryptographically strong random value. Please install/update the OpenSSL extension.');
- }
-
- return base64_encode(hash('sha512', uniqid(mt_rand(), true), true));
- }
}
diff --git a/Http/RememberMe/RememberMeServicesInterface.php b/Http/RememberMe/RememberMeServicesInterface.php
index 0497c69..a00dcef 100644
--- a/Http/RememberMe/RememberMeServicesInterface.php
+++ b/Http/RememberMe/RememberMeServicesInterface.php
@@ -51,7 +51,7 @@ interface RememberMeServicesInterface
*
* @return TokenInterface
*/
- function autoLogin(Request $request);
+ public function autoLogin(Request $request);
/**
* Called whenever an interactive authentication attempt was made, but the
@@ -61,7 +61,7 @@ interface RememberMeServicesInterface
*
* @param Request $request
*/
- function loginFail(Request $request);
+ public function loginFail(Request $request);
/**
* Called whenever an interactive authentication attempt is successful
@@ -78,5 +78,5 @@ interface RememberMeServicesInterface
* @param Response $response
* @param TokenInterface $token
*/
- function loginSuccess(Request $request, Response $response, TokenInterface $token);
+ public function loginSuccess(Request $request, Response $response, TokenInterface $token);
}
diff --git a/Http/RememberMe/ResponseListener.php b/Http/RememberMe/ResponseListener.php
new file mode 100644
index 0000000..03c71c7
--- /dev/null
+++ b/Http/RememberMe/ResponseListener.php
@@ -0,0 +1,39 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\RememberMe;
+
+use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Adds remember-me cookies to the Response.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class ResponseListener implements EventSubscriberInterface
+{
+ public function onKernelResponse(FilterResponseEvent $event)
+ {
+ $request = $event->getRequest();
+ $response = $event->getResponse();
+
+ if ($request->attributes->has(RememberMeServicesInterface::COOKIE_ATTR_NAME)) {
+ $response->headers->setCookie($request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME));
+ }
+ }
+
+ public static function getSubscribedEvents()
+ {
+ return array(KernelEvents::RESPONSE => 'onKernelResponse');
+ }
+}
diff --git a/Http/RememberMe/TokenBasedRememberMeServices.php b/Http/RememberMe/TokenBasedRememberMeServices.php
index bd828f2..5a66fe4 100644
--- a/Http/RememberMe/TokenBasedRememberMeServices.php
+++ b/Http/RememberMe/TokenBasedRememberMeServices.php
@@ -43,7 +43,7 @@ class TokenBasedRememberMeServices extends AbstractRememberMeServices
$user = $this->getUserProvider($class)->loadUserByUsername($username);
} catch (\Exception $ex) {
if (!$ex instanceof AuthenticationException) {
- $ex = new AuthenticationException($ex->getMessage(), null, $ex->getCode(), $ex);
+ $ex = new AuthenticationException($ex->getMessage(), $ex->getCode(), $ex);
}
throw $ex;