summaryrefslogtreecommitdiffstats
path: root/Http
diff options
context:
space:
mode:
Diffstat (limited to 'Http')
-rw-r--r--Http/.gitignore3
-rw-r--r--Http/AccessMap.php6
-rw-r--r--Http/Authentication/SimpleAuthenticationHandler.php106
-rw-r--r--Http/Firewall.php28
-rw-r--r--Http/Firewall/AbstractAuthenticationListener.php8
-rw-r--r--Http/Firewall/ContextListener.php5
-rw-r--r--Http/Firewall/DigestAuthenticationListener.php3
-rw-r--r--Http/Firewall/ExceptionListener.php14
-rw-r--r--Http/Firewall/LogoutListener.php30
-rw-r--r--Http/Firewall/SimpleFormAuthenticationListener.php123
-rw-r--r--Http/Firewall/SimplePreAuthenticationListener.php115
-rw-r--r--Http/Firewall/SwitchUserListener.php4
-rw-r--r--Http/Firewall/UsernamePasswordFormAuthenticationListener.php20
-rw-r--r--Http/HttpUtils.php2
-rw-r--r--Http/LICENSE19
-rw-r--r--Http/README.md23
-rw-r--r--Http/RememberMe/ResponseListener.php3
-rw-r--r--Http/RememberMe/TokenBasedRememberMeServices.php30
-rw-r--r--Http/Tests/AccessMapTest.php51
-rw-r--r--Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php174
-rw-r--r--Http/Tests/Authentication/DefaultAuthenticationSuccessHandlerTest.php169
-rw-r--r--Http/Tests/Authentication/SimpleAuthenticationHandlerTest.php194
-rw-r--r--Http/Tests/EntryPoint/BasicAuthenticationEntryPointTest.php43
-rw-r--r--Http/Tests/EntryPoint/DigestAuthenticationEntryPointTest.php56
-rw-r--r--Http/Tests/EntryPoint/FormAuthenticationEntryPointTest.php67
-rw-r--r--Http/Tests/EntryPoint/RetryAuthenticationEntryPointTest.php64
-rw-r--r--Http/Tests/Firewall/AbstractPreAuthenticatedListenerTest.php252
-rw-r--r--Http/Tests/Firewall/AccessListenerTest.php208
-rw-r--r--Http/Tests/Firewall/AnonymousAuthenticationListenerTest.php68
-rw-r--r--Http/Tests/Firewall/BasicAuthenticationListenerTest.php249
-rw-r--r--Http/Tests/Firewall/ChannelListenerTest.php180
-rw-r--r--Http/Tests/Firewall/ContextListenerTest.php248
-rw-r--r--Http/Tests/Firewall/DigestDataTest.php181
-rw-r--r--Http/Tests/Firewall/ExceptionListenerTest.php184
-rw-r--r--Http/Tests/Firewall/LogoutListenerTest.php237
-rw-r--r--Http/Tests/Firewall/RememberMeListenerTest.php184
-rw-r--r--Http/Tests/Firewall/SwitchUserListenerTest.php202
-rw-r--r--Http/Tests/Firewall/X509AuthenticationListenerTest.php123
-rw-r--r--Http/Tests/FirewallMapTest.php117
-rw-r--r--Http/Tests/FirewallTest.php108
-rw-r--r--Http/Tests/HttpUtilsTest.php266
-rw-r--r--Http/Tests/Logout/CookieClearingLogoutHandlerTest.php49
-rw-r--r--Http/Tests/Logout/DefaultLogoutSuccessHandlerTest.php34
-rw-r--r--Http/Tests/Logout/SessionLogoutHandlerTest.php40
-rw-r--r--Http/Tests/RememberMe/AbstractRememberMeServicesTest.php261
-rw-r--r--Http/Tests/RememberMe/PersistentTokenBasedRememberMeServicesTest.php328
-rw-r--r--Http/Tests/RememberMe/ResponseListenerTest.php102
-rw-r--r--Http/Tests/RememberMe/TokenBasedRememberMeServicesTest.php270
-rw-r--r--Http/Tests/Session/SessionAuthenticationStrategyTest.php90
-rw-r--r--Http/composer.json44
-rw-r--r--Http/phpunit.xml.dist33
51 files changed, 5350 insertions, 68 deletions
diff --git a/Http/.gitignore b/Http/.gitignore
new file mode 100644
index 0000000..c49a5d8
--- /dev/null
+++ b/Http/.gitignore
@@ -0,0 +1,3 @@
+vendor/
+composer.lock
+phpunit.xml
diff --git a/Http/AccessMap.php b/Http/AccessMap.php
index 14fcbe1..116874a 100644
--- a/Http/AccessMap.php
+++ b/Http/AccessMap.php
@@ -28,12 +28,12 @@ class AccessMap implements AccessMapInterface
* Constructor.
*
* @param RequestMatcherInterface $requestMatcher A RequestMatcherInterface instance
- * @param array $roles An array of roles needed to access the resource
+ * @param array $attributes An array of attributes to pass to the access decision manager (like roles)
* @param string|null $channel The channel to enforce (http, https, or null)
*/
- public function add(RequestMatcherInterface $requestMatcher, array $roles = array(), $channel = null)
+ public function add(RequestMatcherInterface $requestMatcher, array $attributes = array(), $channel = null)
{
- $this->map[] = array($requestMatcher, $roles, $channel);
+ $this->map[] = array($requestMatcher, $attributes, $channel);
}
/**
diff --git a/Http/Authentication/SimpleAuthenticationHandler.php b/Http/Authentication/SimpleAuthenticationHandler.php
new file mode 100644
index 0000000..09a55ef
--- /dev/null
+++ b/Http/Authentication/SimpleAuthenticationHandler.php
@@ -0,0 +1,106 @@
+<?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\Authentication;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Psr\Log\LoggerInterface;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface;
+
+/**
+ * Class to proxy authentication success/failure handlers
+ *
+ * Events are sent to the SimpleAuthenticatorInterface if it implements
+ * the right interface, otherwise (or if it fails to return a Response)
+ * the default handlers are triggered.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class SimpleAuthenticationHandler implements AuthenticationFailureHandlerInterface, AuthenticationSuccessHandlerInterface
+{
+ protected $successHandler;
+ protected $failureHandler;
+ protected $simpleAuthenticator;
+ protected $logger;
+
+ /**
+ * Constructor.
+ *
+ * @param SimpleAuthenticatorInterface $authenticator SimpleAuthenticatorInterface instance
+ * @param AuthenticationSuccessHandlerInterface $successHandler Default success handler
+ * @param AuthenticationFailureHandlerInterface $failureHandler Default failure handler
+ * @param LoggerInterface $logger Optional logger
+ */
+ public function __construct(SimpleAuthenticatorInterface $authenticator, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, LoggerInterface $logger = null)
+ {
+ $this->simpleAuthenticator = $authenticator;
+ $this->successHandler = $successHandler;
+ $this->failureHandler = $failureHandler;
+ $this->logger = $logger;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function onAuthenticationSuccess(Request $request, TokenInterface $token)
+ {
+ if ($this->simpleAuthenticator instanceof AuthenticationSuccessHandlerInterface) {
+ if ($this->logger) {
+ $this->logger->debug(sprintf('Using the %s object as authentication success handler', get_class($this->simpleAuthenticator)));
+ }
+
+ $response = $this->simpleAuthenticator->onAuthenticationSuccess($request, $token);
+ if ($response instanceof Response) {
+ return $response;
+ }
+
+ if (null !== $response) {
+ throw new \UnexpectedValueException(sprintf('The %s::onAuthenticationSuccess method must return null to use the default success handler, or a Response object', get_class($this->simpleAuthenticator)));
+ }
+ }
+
+ if ($this->logger) {
+ $this->logger->debug('Fallback to the default authentication success handler');
+ }
+
+ return $this->successHandler->onAuthenticationSuccess($request, $token);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
+ {
+ if ($this->simpleAuthenticator instanceof AuthenticationFailureHandlerInterface) {
+ if ($this->logger) {
+ $this->logger->debug(sprintf('Using the %s object as authentication failure handler', get_class($this->simpleAuthenticator)));
+ }
+
+ $response = $this->simpleAuthenticator->onAuthenticationFailure($request, $exception);
+ if ($response instanceof Response) {
+ return $response;
+ }
+
+ if (null !== $response) {
+ throw new \UnexpectedValueException(sprintf('The %s::onAuthenticationFailure method must return null to use the default failure handler, or a Response object', get_class($this->simpleAuthenticator)));
+ }
+ }
+
+ if ($this->logger) {
+ $this->logger->debug('Fallback to the default authentication failure handler');
+ }
+
+ return $this->failureHandler->onAuthenticationFailure($request, $exception);
+ }
+}
diff --git a/Http/Firewall.php b/Http/Firewall.php
index 7499c6f..7bad47a 100644
--- a/Http/Firewall.php
+++ b/Http/Firewall.php
@@ -11,9 +11,9 @@
namespace Symfony\Component\Security\Http;
-use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@@ -31,6 +31,7 @@ class Firewall implements EventSubscriberInterface
{
private $map;
private $dispatcher;
+ private $exceptionListeners;
/**
* Constructor.
@@ -42,6 +43,7 @@ class Firewall implements EventSubscriberInterface
{
$this->map = $map;
$this->dispatcher = $dispatcher;
+ $this->exceptionListeners = new \SplObjectStorage();
}
/**
@@ -51,14 +53,15 @@ class Firewall implements EventSubscriberInterface
*/
public function onKernelRequest(GetResponseEvent $event)
{
- if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
+ if (!$event->isMasterRequest()) {
return;
}
// register listeners for this firewall
- list($listeners, $exception) = $this->map->getListeners($event->getRequest());
- if (null !== $exception) {
- $exception->register($this->dispatcher);
+ list($listeners, $exceptionListener) = $this->map->getListeners($event->getRequest());
+ if (null !== $exceptionListener) {
+ $this->exceptionListeners[$event->getRequest()] = $exceptionListener;
+ $exceptionListener->register($this->dispatcher);
}
// initiate the listener chain
@@ -71,11 +74,24 @@ class Firewall implements EventSubscriberInterface
}
}
+ public function onKernelFinishRequest(FinishRequestEvent $event)
+ {
+ $request = $event->getRequest();
+
+ if (isset($this->exceptionListeners[$request])) {
+ $this->exceptionListeners[$request]->unregister($this->dispatcher);
+ unset($this->exceptionListeners[$request]);
+ }
+ }
+
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents()
{
- return array(KernelEvents::REQUEST => array('onKernelRequest', 8));
+ return array(
+ KernelEvents::REQUEST => array('onKernelRequest', 8),
+ KernelEvents::FINISH_REQUEST => 'onKernelFinishRequest',
+ );
}
}
diff --git a/Http/Firewall/AbstractAuthenticationListener.php b/Http/Firewall/AbstractAuthenticationListener.php
index f71089f..f1be39e 100644
--- a/Http/Firewall/AbstractAuthenticationListener.php
+++ b/Http/Firewall/AbstractAuthenticationListener.php
@@ -149,14 +149,14 @@ abstract class AbstractAuthenticationListener implements ListenerInterface
if ($returnValue instanceof TokenInterface) {
$this->sessionStrategy->onAuthentication($request, $returnValue);
- $response = $this->onSuccess($event, $request, $returnValue);
+ $response = $this->onSuccess($request, $returnValue);
} elseif ($returnValue instanceof Response) {
$response = $returnValue;
} else {
throw new \RuntimeException('attemptAuthentication() must either return a Response, an implementation of TokenInterface, or null.');
}
} catch (AuthenticationException $e) {
- $response = $this->onFailure($event, $request, $e);
+ $response = $this->onFailure($request, $e);
}
$event->setResponse($response);
@@ -189,7 +189,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface
*/
abstract protected function attemptAuthentication(Request $request);
- private function onFailure(GetResponseEvent $event, Request $request, AuthenticationException $failed)
+ private function onFailure(Request $request, AuthenticationException $failed)
{
if (null !== $this->logger) {
$this->logger->info(sprintf('Authentication request failed: %s', $failed->getMessage()));
@@ -209,7 +209,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface
return $response;
}
- private function onSuccess(GetResponseEvent $event, Request $request, TokenInterface $token)
+ private function onSuccess(Request $request, TokenInterface $token)
{
if (null !== $this->logger) {
$this->logger->info(sprintf('User "%s" has been authenticated successfully', $token->getUsername()));
diff --git a/Http/Firewall/ContextListener.php b/Http/Firewall/ContextListener.php
index 3ea6512..1c97df6 100644
--- a/Http/Firewall/ContextListener.php
+++ b/Http/Firewall/ContextListener.php
@@ -11,7 +11,6 @@
namespace Symfony\Component\Security\Http\Firewall;
-use Symfony\Component\HttpKernel\HttpKernelInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
@@ -66,7 +65,7 @@ class ContextListener implements ListenerInterface
*/
public function handle(GetResponseEvent $event)
{
- if (!$this->registered && null !== $this->dispatcher && HttpKernelInterface::MASTER_REQUEST === $event->getRequestType()) {
+ if (!$this->registered && null !== $this->dispatcher && $event->isMasterRequest()) {
$this->dispatcher->addListener(KernelEvents::RESPONSE, array($this, 'onKernelResponse'));
$this->registered = true;
}
@@ -106,7 +105,7 @@ class ContextListener implements ListenerInterface
*/
public function onKernelResponse(FilterResponseEvent $event)
{
- if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
+ if (!$event->isMasterRequest()) {
return;
}
diff --git a/Http/Firewall/DigestAuthenticationListener.php b/Http/Firewall/DigestAuthenticationListener.php
index ea85e77..a5e0222 100644
--- a/Http/Firewall/DigestAuthenticationListener.php
+++ b/Http/Firewall/DigestAuthenticationListener.php
@@ -139,7 +139,7 @@ class DigestAuthenticationListener implements ListenerInterface
class DigestData
{
- private $elements;
+ private $elements = array();
private $header;
private $nonceExpiryTime;
@@ -147,7 +147,6 @@ class DigestData
{
$this->header = $header;
preg_match_all('/(\w+)=("((?:[^"\\\\]|\\\\.)+)"|([^\s,$]+))/', $header, $matches, PREG_SET_ORDER);
- $this->elements = array();
foreach ($matches as $match) {
if (isset($match[1]) && isset($match[3])) {
$this->elements[$match[1]] = isset($match[4]) ? $match[4] : $match[3];
diff --git a/Http/Firewall/ExceptionListener.php b/Http/Firewall/ExceptionListener.php
index fac5dc1..8f54f8d 100644
--- a/Http/Firewall/ExceptionListener.php
+++ b/Http/Firewall/ExceptionListener.php
@@ -70,16 +70,22 @@ class ExceptionListener
}
/**
+ * Unregisters the dispatcher.
+ *
+ * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
+ */
+ public function unregister(EventDispatcherInterface $dispatcher)
+ {
+ $dispatcher->removeListener(KernelEvents::EXCEPTION, array($this, 'onKernelException'));
+ }
+
+ /**
* Handles security related exceptions.
*
* @param GetResponseForExceptionEvent $event An GetResponseForExceptionEvent instance
*/
public function onKernelException(GetResponseForExceptionEvent $event)
{
- // we need to remove ourselves as the exception listener can be
- // different depending on the Request
- $event->getDispatcher()->removeListener(KernelEvents::EXCEPTION, array($this, 'onKernelException'));
-
$exception = $event->getException();
do {
if ($exception instanceof AuthenticationException) {
diff --git a/Http/Firewall/LogoutListener.php b/Http/Firewall/LogoutListener.php
index 5a68670..3a45e37 100644
--- a/Http/Firewall/LogoutListener.php
+++ b/Http/Firewall/LogoutListener.php
@@ -11,12 +11,16 @@
namespace Symfony\Component\Security\Http\Firewall;
+use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\Security\Core\Exception\InvalidArgumentException;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Core\Exception\LogoutException;
+use Symfony\Component\Security\Csrf\CsrfToken;
+use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Http\HttpUtils;
use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface;
use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface;
@@ -33,19 +37,25 @@ class LogoutListener implements ListenerInterface
private $handlers;
private $successHandler;
private $httpUtils;
- private $csrfProvider;
+ private $csrfTokenManager;
/**
* Constructor.
*
* @param SecurityContextInterface $securityContext
- * @param HttpUtils $httpUtils An HttpUtilsInterface instance
- * @param LogoutSuccessHandlerInterface $successHandler A LogoutSuccessHandlerInterface instance
- * @param array $options An array of options to process a logout attempt
- * @param CsrfProviderInterface $csrfProvider A CsrfProviderInterface instance
+ * @param HttpUtils $httpUtils An HttpUtilsInterface instance
+ * @param LogoutSuccessHandlerInterface $successHandler A LogoutSuccessHandlerInterface instance
+ * @param array $options An array of options to process a logout attempt
+ * @param CsrfTokenManagerInterface $csrfTokenManager A CsrfTokenManagerInterface instance
*/
- public function __construct(SecurityContextInterface $securityContext, HttpUtils $httpUtils, LogoutSuccessHandlerInterface $successHandler, array $options = array(), CsrfProviderInterface $csrfProvider = null)
+ public function __construct(SecurityContextInterface $securityContext, HttpUtils $httpUtils, LogoutSuccessHandlerInterface $successHandler, array $options = array(), $csrfTokenManager = null)
{
+ if ($csrfTokenManager instanceof CsrfProviderInterface) {
+ $csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager);
+ } elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) {
+ throw new InvalidArgumentException('The CSRF token manager should be an instance of CsrfProviderInterface or CsrfTokenManagerInterface.');
+ }
+
$this->securityContext = $securityContext;
$this->httpUtils = $httpUtils;
$this->options = array_merge(array(
@@ -54,7 +64,7 @@ class LogoutListener implements ListenerInterface
'logout_path' => '/logout',
), $options);
$this->successHandler = $successHandler;
- $this->csrfProvider = $csrfProvider;
+ $this->csrfTokenManager = $csrfTokenManager;
$this->handlers = array();
}
@@ -71,7 +81,7 @@ class LogoutListener implements ListenerInterface
/**
* Performs the logout if requested.
*
- * If a CsrfProviderInterface instance is available, it will be used to
+ * If a CsrfTokenManagerInterface instance is available, it will be used to
* validate the request.
*
* @param GetResponseEvent $event A GetResponseEvent instance
@@ -87,10 +97,10 @@ class LogoutListener implements ListenerInterface
return;
}
- if (null !== $this->csrfProvider) {
+ if (null !== $this->csrfTokenManager) {
$csrfToken = $request->get($this->options['csrf_parameter'], null, true);
- if (false === $this->csrfProvider->isCsrfTokenValid($this->options['intention'], $csrfToken)) {
+ if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['intention'], $csrfToken))) {
throw new LogoutException('Invalid CSRF token.');
}
}
diff --git a/Http/Firewall/SimpleFormAuthenticationListener.php b/Http/Firewall/SimpleFormAuthenticationListener.php
new file mode 100644
index 0000000..5b905df
--- /dev/null
+++ b/Http/Firewall/SimpleFormAuthenticationListener.php
@@ -0,0 +1,123 @@
+<?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\Firewall;
+
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter;
+use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Security\Core\Exception\InvalidArgumentException;
+use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
+use Symfony\Component\Security\Csrf\CsrfToken;
+use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
+use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
+use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
+use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
+use Symfony\Component\Security\Core\Authentication\SimpleFormAuthenticatorInterface;
+use Symfony\Component\Security\Core\SecurityContextInterface;
+use Symfony\Component\Security\Http\HttpUtils;
+use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
+use Psr\Log\LoggerInterface;
+
+/**
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class SimpleFormAuthenticationListener extends AbstractAuthenticationListener
+{
+ private $simpleAuthenticator;
+ private $csrfTokenManager;
+
+ /**
+ * Constructor.
+ *
+ * @param SecurityContextInterface $securityContext A SecurityContext instance
+ * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance
+ * @param SessionAuthenticationStrategyInterface $sessionStrategy
+ * @param HttpUtils $httpUtils An HttpUtilsInterface instance
+ * @param string $providerKey
+ * @param AuthenticationSuccessHandlerInterface $successHandler
+ * @param AuthenticationFailureHandlerInterface $failureHandler
+ * @param array $options An array of options for the processing of a
+ * successful, or failed authentication attempt
+ * @param LoggerInterface $logger A LoggerInterface instance
+ * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
+ * @param CsrfTokenManagerInterface $csrfTokenManager A CsrfTokenManagerInterface instance
+ * @param SimpleFormAuthenticatorInterface $simpleAuthenticator A SimpleFormAuthenticatorInterface instance
+ *
+ * @throws \InvalidArgumentException In case no simple authenticator is provided
+ * @throws InvalidArgumentException In case an invalid CSRF token manager is passed
+ */
+ public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, $csrfTokenManager = null, SimpleFormAuthenticatorInterface $simpleAuthenticator = null)
+ {
+ if (!$simpleAuthenticator) {
+ throw new \InvalidArgumentException('Missing simple authenticator');
+ }
+
+ if ($csrfTokenManager instanceof CsrfProviderInterface) {
+ $csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager);
+ } elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) {
+ throw new InvalidArgumentException('The CSRF token manager should be an instance of CsrfProviderInterface or CsrfTokenManagerInterface.');
+ }
+
+ $this->simpleAuthenticator = $simpleAuthenticator;
+ $this->csrfTokenManager = $csrfTokenManager;
+
+ $options = array_merge(array(
+ 'username_parameter' => '_username',
+ 'password_parameter' => '_password',
+ 'csrf_parameter' => '_csrf_token',
+ 'intention' => 'authenticate',
+ 'post_only' => true,
+ ), $options);
+ parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, $options, $logger, $dispatcher);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function requiresAuthentication(Request $request)
+ {
+ if ($this->options['post_only'] && !$request->isMethod('POST')) {
+ return false;
+ }
+
+ return parent::requiresAuthentication($request);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function attemptAuthentication(Request $request)
+ {
+ if (null !== $this->csrfTokenManager) {
+ $csrfToken = $request->get($this->options['csrf_parameter'], null, true);
+
+ if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['intention'], $csrfToken))) {
+ throw new InvalidCsrfTokenException('Invalid CSRF token.');
+ }
+ }
+
+ if ($this->options['post_only']) {
+ $username = trim($request->request->get($this->options['username_parameter'], null, true));
+ $password = $request->request->get($this->options['password_parameter'], null, true);
+ } else {
+ $username = trim($request->get($this->options['username_parameter'], null, true));
+ $password = $request->get($this->options['password_parameter'], null, true);
+ }
+
+ $request->getSession()->set(SecurityContextInterface::LAST_USERNAME, $username);
+
+ $token = $this->simpleAuthenticator->createToken($request, $username, $password, $this->providerKey);
+
+ return $this->authenticationManager->authenticate($token);
+ }
+}
diff --git a/Http/Firewall/SimplePreAuthenticationListener.php b/Http/Firewall/SimplePreAuthenticationListener.php
new file mode 100644
index 0000000..e80cc98
--- /dev/null
+++ b/Http/Firewall/SimplePreAuthenticationListener.php
@@ -0,0 +1,115 @@
+<?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\Firewall;
+
+use Symfony\Component\Security\Core\SecurityContextInterface;
+use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
+use Psr\Log\LoggerInterface;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface;
+use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
+use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
+
+/**
+ * SimplePreAuthenticationListener implements simple proxying to an authenticator.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class SimplePreAuthenticationListener implements ListenerInterface
+{
+ private $securityContext;
+ private $authenticationManager;
+ private $providerKey;
+ private $simpleAuthenticator;
+ private $logger;
+
+ /**
+ * Constructor.
+ *
+ * @param SecurityContextInterface $securityContext A SecurityContext instance
+ * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance
+ * @param string $providerKey
+ * @param SimplePreAuthenticatorInterface $simpleAuthenticator A SimplePreAuthenticatorInterface instance
+ * @param LoggerInterface $logger A LoggerInterface instance
+ */
+ public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, SimplePreAuthenticatorInterface $simpleAuthenticator, LoggerInterface $logger = null)
+ {
+ if (empty($providerKey)) {
+ throw new \InvalidArgumentException('$providerKey must not be empty.');
+ }
+
+ $this->securityContext = $securityContext;
+ $this->authenticationManager = $authenticationManager;
+ $this->providerKey = $providerKey;
+ $this->simpleAuthenticator = $simpleAuthenticator;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Handles basic authentication.
+ *
+ * @param GetResponseEvent $event A GetResponseEvent instance
+ */
+ public function handle(GetResponseEvent $event)
+ {
+ $request = $event->getRequest();
+
+ if (null !== $this->logger) {
+ $this->logger->info(sprintf('Attempting simple pre-authorization %s', $this->providerKey));
+ }
+
+ if (null !== $this->securityContext->getToken() && !$this->securityContext->getToken() instanceof AnonymousToken) {
+ return;
+ }
+
+ try {
+ $token = $this->simpleAuthenticator->createToken($request, $this->providerKey);
+
+ // allow null to be returned to skip authentication
+ if (null === $token) {
+ return;
+ }
+
+ $token = $this->authenticationManager->authenticate($token);
+ $this->securityContext->setToken($token);
+ } catch (AuthenticationException $e) {
+ $this->securityContext->setToken(null);
+
+ if (null !== $this->logger) {
+ $this->logger->info(sprintf('Authentication request failed: %s', $e->getMessage()));
+ }
+
+ if ($this->simpleAuthenticator instanceof AuthenticationFailureHandlerInterface) {
+ $response = $this->simpleAuthenticator->onAuthenticationFailure($request, $e);
+ if ($response instanceof Response) {
+ $event->setResponse($response);
+ } elseif (null !== $response) {
+ throw new \UnexpectedValueException(sprintf('The %s::onAuthenticationFailure method must return null or a Response object', get_class($this->simpleAuthenticator)));
+ }
+ }
+
+ return;
+ }
+
+ if ($this->simpleAuthenticator instanceof AuthenticationSuccessHandlerInterface) {
+ $response = $this->simpleAuthenticator->onAuthenticationSuccess($request, $token);
+ if ($response instanceof Response) {
+ $event->setResponse($response);
+ } elseif (null !== $response) {
+ throw new \UnexpectedValueException(sprintf('The %s::onAuthenticationSuccess method must return null or a Response object', get_class($this->simpleAuthenticator)));
+ }
+ }
+ }
+}
diff --git a/Http/Firewall/SwitchUserListener.php b/Http/Firewall/SwitchUserListener.php
index 7700096..b46b1bc 100644
--- a/Http/Firewall/SwitchUserListener.php
+++ b/Http/Firewall/SwitchUserListener.php
@@ -92,7 +92,9 @@ class SwitchUserListener implements ListenerInterface
}
}
- $request->server->set('QUERY_STRING', '');
+ $request->query->remove($this->usernameParameter);
+ $request->server->set('QUERY_STRING', http_build_query($request->query->all()));
+
$response = new RedirectResponse($request->getUri(), 302);
$event->setResponse($response);
diff --git a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php
index 2147817..36ff758 100644
--- a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php
+++ b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php
@@ -11,15 +11,19 @@
namespace Symfony\Component\Security\Http\Firewall;
+use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
use Symfony\Component\HttpFoundation\Request;
use Psr\Log\LoggerInterface;
+use Symfony\Component\Security\Csrf\CsrfToken;
+use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
use Symfony\Component\Security\Http\HttpUtils;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
+use Symfony\Component\Security\Core\Exception\InvalidArgumentException;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -32,13 +36,19 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
*/
class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationListener
{
- private $csrfProvider;
+ private $csrfTokenManager;
/**
* {@inheritdoc}
*/
- public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfProviderInterface $csrfProvider = null)
+ public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, $csrfTokenManager = null)
{
+ if ($csrfTokenManager instanceof CsrfProviderInterface) {
+ $csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager);
+ } elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) {
+ throw new InvalidArgumentException('The CSRF token manager should be an instance of CsrfProviderInterface or CsrfTokenManagerInterface.');
+ }
+
parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array(
'username_parameter' => '_username',
'password_parameter' => '_password',
@@ -47,7 +57,7 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL
'post_only' => true,
), $options), $logger, $dispatcher);
- $this->csrfProvider = $csrfProvider;
+ $this->csrfTokenManager = $csrfTokenManager;
}
/**
@@ -67,10 +77,10 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL
*/
protected function attemptAuthentication(Request $request)
{
- if (null !== $this->csrfProvider) {
+ if (null !== $this->csrfTokenManager) {
$csrfToken = $request->get($this->options['csrf_parameter'], null, true);
- if (false === $this->csrfProvider->isCsrfTokenValid($this->options['intention'], $csrfToken)) {
+ if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['intention'], $csrfToken))) {
throw new InvalidCsrfTokenException('Invalid CSRF token.');
}
}
diff --git a/Http/HttpUtils.php b/Http/HttpUtils.php
index 0f47809..a447a44 100644
--- a/Http/HttpUtils.php
+++ b/Http/HttpUtils.php
@@ -71,7 +71,7 @@ class HttpUtils
*/
public function createRequest(Request $request, $path)
{
- $newRequest = $request::create($this->generateUri($request, $path), 'get', array(), $request->cookies->all(), array(), $request->server->all());
+ $newRequest = Request::create($this->generateUri($request, $path), 'get', array(), $request->cookies->all(), array(), $request->server->all());
if ($request->hasSession()) {
$newRequest->setSession($request->getSession());
}
diff --git a/Http/LICENSE b/Http/LICENSE
new file mode 100644
index 0000000..43028bc
--- /dev/null
+++ b/Http/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2004-2015 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/Http/README.md b/Http/README.md
new file mode 100644
index 0000000..c0760d4
--- /dev/null
+++ b/Http/README.md
@@ -0,0 +1,23 @@
+Security Component - HTTP Integration
+=====================================
+
+Security provides an infrastructure for sophisticated authorization systems,
+which makes it possible to easily separate the actual authorization logic from
+so called user providers that hold the users credentials. It is inspired by
+the Java Spring framework.
+
+Resources
+---------
+
+Documentation:
+
+http://symfony.com/doc/2.5/book/security.html
+
+Tests
+-----
+
+You can run the unit tests with the following command:
+
+ $ cd path/to/Symfony/Component/Security/Http/
+ $ composer.phar install --dev
+ $ phpunit
diff --git a/Http/RememberMe/ResponseListener.php b/Http/RememberMe/ResponseListener.php
index ec5f006..4149fb6 100644
--- a/Http/RememberMe/ResponseListener.php
+++ b/Http/RememberMe/ResponseListener.php
@@ -13,7 +13,6 @@ namespace Symfony\Component\Security\Http\RememberMe;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
-use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
@@ -28,7 +27,7 @@ class ResponseListener implements EventSubscriberInterface
*/
public function onKernelResponse(FilterResponseEvent $event)
{
- if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
+ if (!$event->isMasterRequest()) {
return;
}
diff --git a/Http/RememberMe/TokenBasedRememberMeServices.php b/Http/RememberMe/TokenBasedRememberMeServices.php
index 8283a7c..9042963 100644
--- a/Http/RememberMe/TokenBasedRememberMeServices.php
+++ b/Http/RememberMe/TokenBasedRememberMeServices.php
@@ -17,6 +17,7 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
+use Symfony\Component\Security\Core\Util\StringUtils;
/**
* Concrete implementation of the RememberMeServicesInterface providing
@@ -53,7 +54,7 @@ class TokenBasedRememberMeServices extends AbstractRememberMeServices
throw new \RuntimeException(sprintf('The UserProviderInterface implementation must return an instance of UserInterface, but returned "%s".', get_class($user)));
}
- if (true !== $this->compareHashes($hash, $this->generateCookieHash($class, $username, $expires, $user->getPassword()))) {
+ if (true !== StringUtils::equals($hash, $this->generateCookieHash($class, $username, $expires, $user->getPassword()))) {
throw new AuthenticationException('The cookie\'s hash is invalid.');
}
@@ -65,31 +66,6 @@ class TokenBasedRememberMeServices extends AbstractRememberMeServices
}
/**
- * Compares two hashes using a constant-time algorithm to avoid (remote)
- * timing attacks.
- *
- * This is the same implementation as used in the BasePasswordEncoder.
- *
- * @param string $hash1 The first hash
- * @param string $hash2 The second hash
- *
- * @return bool true if the two hashes are the same, false otherwise
- */
- private function compareHashes($hash1, $hash2)
- {
- if (strlen($hash1) !== $c = strlen($hash2)) {
- return false;
- }
-
- $result = 0;
- for ($i = 0; $i < $c; $i++) {
- $result |= ord($hash1[$i]) ^ ord($hash2[$i]);
- }
-
- return 0 === $result;
- }
-
- /**
* {@inheritdoc}
*/
protected function onLoginSuccess(Request $request, Response $response, TokenInterface $token)
@@ -147,6 +123,6 @@ class TokenBasedRememberMeServices extends AbstractRememberMeServices
*/
protected function generateCookieHash($class, $username, $expires, $password)
{
- return hash('sha256', $class.$username.$expires.$password.$this->getKey());
+ return hash_hmac('sha256', $class.$username.$expires.$password, $this->getKey());
}
}
diff --git a/Http/Tests/AccessMapTest.php b/Http/Tests/AccessMapTest.php
new file mode 100644
index 0000000..d8ab7aa
--- /dev/null
+++ b/Http/Tests/AccessMapTest.php
@@ -0,0 +1,51 @@
+<?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\Tests;
+
+use Symfony\Component\Security\Http\AccessMap;
+
+class AccessMapTest extends \PHPUnit_Framework_TestCase
+{
+ public function testReturnsFirstMatchedPattern()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+ $requestMatcher1 = $this->getRequestMatcher($request, false);
+ $requestMatcher2 = $this->getRequestMatcher($request, true);
+
+ $map = new AccessMap();
+ $map->add($requestMatcher1, array('ROLE_ADMIN'), 'http');
+ $map->add($requestMatcher2, array('ROLE_USER'), 'https');
+
+ $this->assertSame(array(array('ROLE_USER'), 'https'), $map->getPatterns($request));
+ }
+
+ public function testReturnsEmptyPatternIfNoneMatched()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+ $requestMatcher = $this->getRequestMatcher($request, false);
+
+ $map = new AccessMap();
+ $map->add($requestMatcher, array('ROLE_USER'), 'https');
+
+ $this->assertSame(array(null, null), $map->getPatterns($request));
+ }
+
+ private function getRequestMatcher($request, $matches)
+ {
+ $requestMatcher = $this->getMock('Symfony\Component\HttpFoundation\RequestMatcherInterface');
+ $requestMatcher->expects($this->once())
+ ->method('matches')->with($request)
+ ->will($this->returnValue($matches));
+
+ return $requestMatcher;
+ }
+}
diff --git a/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php b/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php
new file mode 100644
index 0000000..15adcdf
--- /dev/null
+++ b/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php
@@ -0,0 +1,174 @@
+<?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\Tests\Authentication;
+
+use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler;
+use Symfony\Component\Security\Core\SecurityContextInterface;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
+class DefaultAuthenticationFailureHandlerTest extends \PHPUnit_Framework_TestCase
+{
+ private $httpKernel = null;
+
+ private $httpUtils = null;
+
+ private $logger = null;
+
+ private $request = null;
+
+ private $session = null;
+
+ private $exception = null;
+
+ protected function setUp()
+ {
+ $this->httpKernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
+ $this->httpUtils = $this->getMock('Symfony\Component\Security\Http\HttpUtils');
+ $this->logger = $this->getMock('Psr\Log\LoggerInterface');
+
+ $this->session = $this->getMock('Symfony\Component\HttpFoundation\Session\SessionInterface');
+ $this->request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+ $this->request->expects($this->any())->method('getSession')->will($this->returnValue($this->session));
+ $this->exception = $this->getMock('Symfony\Component\Security\Core\Exception\AuthenticationException');
+ }
+
+ public function testForward()
+ {
+ $options = array('failure_forward' => true);
+
+ $subRequest = $this->getRequest();
+ $subRequest->attributes->expects($this->once())
+ ->method('set')->with(SecurityContextInterface::AUTHENTICATION_ERROR, $this->exception);
+ $this->httpUtils->expects($this->once())
+ ->method('createRequest')->with($this->request, '/login')
+ ->will($this->returnValue($subRequest));
+
+ $response = $this->getMock('Symfony\Component\HttpFoundation\Response');
+ $this->httpKernel->expects($this->once())
+ ->method('handle')->with($subRequest, HttpKernelInterface::SUB_REQUEST)
+ ->will($this->returnValue($response));
+
+ $handler = new DefaultAuthenticationFailureHandler($this->httpKernel, $this->httpUtils, $options, $this->logger);
+ $result = $handler->onAuthenticationFailure($this->request, $this->exception);
+
+ $this->assertSame($response, $result);
+ }
+
+ public function testRedirect()
+ {
+ $response = $this->getMock('Symfony\Component\HttpFoundation\Response');
+ $this->httpUtils->expects($this->once())
+ ->method('createRedirectResponse')->with($this->request, '/login')
+ ->will($this->returnValue($response));
+
+ $handler = new DefaultAuthenticationFailureHandler($this->httpKernel, $this->httpUtils, array(), $this->logger);
+ $result = $handler->onAuthenticationFailure($this->request, $this->exception);
+
+ $this->assertSame($response, $result);
+ }
+
+ public function testExceptionIsPersistedInSession()
+ {
+ $this->session->expects($this->once())
+ ->method('set')->with(SecurityContextInterface::AUTHENTICATION_ERROR, $this->exception);
+
+ $handler = new DefaultAuthenticationFailureHandler($this->httpKernel, $this->httpUtils, array(), $this->logger);
+ $handler->onAuthenticationFailure($this->request, $this->exception);
+ }
+
+ public function testExceptionIsPassedInRequestOnForward()
+ {
+ $options = array('failure_forward' => true);
+
+ $subRequest = $this->getRequest();
+ $subRequest->attributes->expects($this->once())
+ ->method('set')->with(SecurityContextInterface::AUTHENTICATION_ERROR, $this->exception);
+
+ $this->httpUtils->expects($this->once())
+ ->method('createRequest')->with($this->request, '/login')
+ ->will($this->returnValue($subRequest));
+
+ $this->session->expects($this->never())->method('set');
+
+ $handler = new DefaultAuthenticationFailureHandler($this->httpKernel, $this->httpUtils, $options, $this->logger);
+ $handler->onAuthenticationFailure($this->request, $this->exception);
+ }
+
+ public function testRedirectIsLogged()
+ {
+ $this->logger->expects($this->once())->method('debug')->with('Redirecting to /login');
+
+ $handler = new DefaultAuthenticationFailureHandler($this->httpKernel, $this->httpUtils, array(), $this->logger);
+ $handler->onAuthenticationFailure($this->request, $this->exception);
+ }
+
+ public function testForwardIsLogged()
+ {
+ $options = array('failure_forward' => true);
+
+ $this->httpUtils->expects($this->once())
+ ->method('createRequest')->with($this->request, '/login')
+ ->will($this->returnValue($this->getRequest()));
+
+ $this->logger->expects($this->once())->method('debug')->with('Forwarding to /login');
+
+ $handler = new DefaultAuthenticationFailureHandler($this->httpKernel, $this->httpUtils, $options, $this->logger);
+ $handler->onAuthenticationFailure($this->request, $this->exception);
+ }
+
+ public function testFailurePathCanBeOverwritten()
+ {
+ $options = array('failure_path' => '/auth/login');
+
+ $this->httpUtils->expects($this->once())
+ ->method('createRedirectResponse')->with($this->request, '/auth/login');
+
+ $handler = new DefaultAuthenticationFailureHandler($this->httpKernel, $this->httpUtils, $options, $this->logger);
+ $handler->onAuthenticationFailure($this->request, $this->exception);
+ }
+
+ public function testFailurePathCanBeOverwrittenWithRequest()
+ {
+ $this->request->expects($this->once())
+ ->method('get')->with('_failure_path', null, true)
+ ->will($this->returnValue('/auth/login'));
+
+ $this->httpUtils->expects($this->once())
+ ->method('createRedirectResponse')->with($this->request, '/auth/login');
+
+ $handler = new DefaultAuthenticationFailureHandler($this->httpKernel, $this->httpUtils, array(), $this->logger);
+ $handler->onAuthenticationFailure($this->request, $this->exception);
+ }
+
+ public function testFailurePathParameterCanBeOverwritten()
+ {
+ $options = array('failure_path_parameter' => '_my_failure_path');
+
+ $this->request->expects($this->once())
+ ->method('get')->with('_my_failure_path', null, true)
+ ->will($this->returnValue('/auth/login'));
+
+ $this->httpUtils->expects($this->once())
+ ->method('createRedirectResponse')->with($this->request, '/auth/login');
+
+ $handler = new DefaultAuthenticationFailureHandler($this->httpKernel, $this->httpUtils, $options, $this->logger);
+ $handler->onAuthenticationFailure($this->request, $this->exception);
+ }
+
+ private function getRequest()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+ $request->attributes = $this->getMock('Symfony\Component\HttpFoundation\ParameterBag');
+
+ return $request;
+ }
+}
diff --git a/Http/Tests/Authentication/DefaultAuthenticationSuccessHandlerTest.php b/Http/Tests/Authentication/DefaultAuthenticationSuccessHandlerTest.php
new file mode 100644
index 0000000..4d1847d
--- /dev/null
+++ b/Http/Tests/Authentication/DefaultAuthenticationSuccessHandlerTest.php
@@ -0,0 +1,169 @@
+<?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\Tests\Authentication;
+
+use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler;
+
+class DefaultAuthenticationSuccessHandlerTest extends \PHPUnit_Framework_TestCase
+{
+ private $httpUtils = null;
+
+ private $request = null;
+
+ private $token = null;
+
+ protected function setUp()
+ {
+ $this->httpUtils = $this->getMock('Symfony\Component\Security\Http\HttpUtils');
+ $this->request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+ $this->request->headers = $this->getMock('Symfony\Component\HttpFoundation\HeaderBag');
+ $this->token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ }
+
+ public function testRequestIsRedirected()
+ {
+ $response = $this->expectRedirectResponse('/');
+
+ $handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, array());
+ $result = $handler->onAuthenticationSuccess($this->request, $this->token);
+
+ $this->assertSame($response, $result);
+ }
+
+ public function testDefaultTargetPathCanBeForced()
+ {
+ $options = array(
+ 'always_use_default_target_path' => true,
+ 'default_target_path' => '/dashboard',
+ );
+
+ $response = $this->expectRedirectResponse('/dashboard');
+
+ $handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, $options);
+ $result = $handler->onAuthenticationSuccess($this->request, $this->token);
+
+ $this->assertSame($response, $result);
+ }
+
+ public function testTargetPathIsPassedWithRequest()
+ {
+ $this->request->expects($this->once())
+ ->method('get')->with('_target_path')
+ ->will($this->returnValue('/dashboard'));
+
+ $response = $this->expectRedirectResponse('/dashboard');
+
+ $handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, array());
+ $result = $handler->onAuthenticationSuccess($this->request, $this->token);
+
+ $this->assertSame($response, $result);
+ }
+
+ public function testTargetPathParameterIsCustomised()
+ {
+ $options = array('target_path_parameter' => '_my_target_path');
+
+ $this->request->expects($this->once())
+ ->method('get')->with('_my_target_path')
+ ->will($this->returnValue('/dashboard'));
+
+ $response = $this->expectRedirectResponse('/dashboard');
+
+ $handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, $options);
+ $result = $handler->onAuthenticationSuccess($this->request, $this->token);
+
+ $this->assertSame($response, $result);
+ }
+
+ public function testTargetPathIsTakenFromTheSession()
+ {
+ $session = $this->getMock('Symfony\Component\HttpFoundation\Session\SessionInterface');
+ $session->expects($this->once())
+ ->method('get')->with('_security.admin.target_path')
+ ->will($this->returnValue('/admin/dashboard'));
+ $session->expects($this->once())
+ ->method('remove')->with('_security.admin.target_path');
+
+ $this->request->expects($this->any())
+ ->method('getSession')
+ ->will($this->returnValue($session));
+
+ $response = $this->expectRedirectResponse('/admin/dashboard');
+
+ $handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, array());
+ $handler->setProviderKey('admin');
+
+ $result = $handler->onAuthenticationSuccess($this->request, $this->token);
+
+ $this->assertSame($response, $result);
+ }
+
+ public function testTargetPathIsPassedAsReferer()
+ {
+ $options = array('use_referer' => true);
+
+ $this->request->headers->expects($this->once())
+ ->method('get')->with('Referer')
+ ->will($this->returnValue('/dashboard'));
+
+ $response = $this->expectRedirectResponse('/dashboard');
+
+ $handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, $options);
+ $result = $handler->onAuthenticationSuccess($this->request, $this->token);
+
+ $this->assertSame($response, $result);
+ }
+
+ public function testRefererHasToBeDifferentThatLoginUrl()
+ {
+ $options = array('use_referer' => true);
+
+ $this->request->headers->expects($this->any())
+ ->method('get')->with('Referer')
+ ->will($this->returnValue('/login'));
+
+ $this->httpUtils->expects($this->once())
+ ->method('generateUri')->with($this->request, '/login')
+ ->will($this->returnValue('/login'));
+
+ $response = $this->expectRedirectResponse('/');
+
+ $handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, $options);
+ $result = $handler->onAuthenticationSuccess($this->request, $this->token);
+
+ $this->assertSame($response, $result);
+ }
+
+ public function testRefererTargetPathIsIgnoredByDefault()
+ {
+ $this->request->headers->expects($this->never())->method('get');
+
+ $response = $this->expectRedirectResponse('/');
+
+ $handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, array());
+ $result = $handler->onAuthenticationSuccess($this->request, $this->token);
+
+ $this->assertSame($response, $result);
+ }
+
+ private function expectRedirectResponse($path)
+ {
+ $response = $this->getMock('Symfony\Component\HttpFoundation\Response');
+
+ $this->httpUtils->expects($this->once())
+ ->method('createRedirectResponse')
+ ->with($this->request, $path)
+ ->will($this->returnValue($response));
+
+ return $response;
+ }
+}
diff --git a/Http/Tests/Authentication/SimpleAuthenticationHandlerTest.php b/Http/Tests/Authentication/SimpleAuthenticationHandlerTest.php
new file mode 100644
index 0000000..97167c9
--- /dev/null
+++ b/Http/Tests/Authentication/SimpleAuthenticationHandlerTest.php
@@ -0,0 +1,194 @@
+<?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\Tests;
+
+use Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
+use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
+use Symfony\Component\Security\Http\Authentication\SimpleAuthenticationHandler;
+
+class SimpleAuthenticationHandlerTest extends \PHPUnit_Framework_TestCase
+{
+ private $successHandler;
+
+ private $failureHandler;
+
+ private $request;
+
+ private $token;
+
+ private $authenticationException;
+
+ private $response;
+
+ public function setUp()
+ {
+ $this->successHandler = $this->getMock('Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface');
+ $this->failureHandler = $this->getMock('Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface');
+
+ $this->request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+ $this->token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ // No methods are invoked on the exception; we just assert on its class
+ $this->authenticationException = new AuthenticationException();
+
+ $this->response = $this->getMock('Symfony\Component\HttpFoundation\Response');
+ }
+
+ public function testOnAuthenticationSuccessFallsBackToDefaultHandlerIfSimpleIsNotASuccessHandler()
+ {
+ $authenticator = $this->getMock('Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface');
+
+ $this->successHandler->expects($this->once())
+ ->method('onAuthenticationSuccess')
+ ->with($this->request, $this->token)
+ ->will($this->returnValue($this->response));
+
+ $handler = new SimpleAuthenticationHandler($authenticator, $this->successHandler, $this->failureHandler);
+ $result = $handler->onAuthenticationSuccess($this->request, $this->token);
+
+ $this->assertSame($this->response, $result);
+ }
+
+ public function testOnAuthenticationSuccessCallsSimpleAuthenticator()
+ {
+ $this->successHandler->expects($this->never())
+ ->method('onAuthenticationSuccess');
+
+ $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\TestSuccessHandlerInterface');
+ $authenticator->expects($this->once())
+ ->method('onAuthenticationSuccess')
+ ->with($this->request, $this->token)
+ ->will($this->returnValue($this->response));
+
+ $handler = new SimpleAuthenticationHandler($authenticator, $this->successHandler, $this->failureHandler);
+ $result = $handler->onAuthenticationSuccess($this->request, $this->token);
+
+ $this->assertSame($this->response, $result);
+ }
+
+ /**
+ * @expectedException \UnexpectedValueException
+ * @expectedExceptionMessage onAuthenticationSuccess method must return null to use the default success handler, or a Response object
+ */
+ public function testOnAuthenticationSuccessThrowsAnExceptionIfNonResponseIsReturned()
+ {
+ $this->successHandler->expects($this->never())
+ ->method('onAuthenticationSuccess');
+
+ $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\TestSuccessHandlerInterface');
+ $authenticator->expects($this->once())
+ ->method('onAuthenticationSuccess')
+ ->with($this->request, $this->token)
+ ->will($this->returnValue(new \stdClass()));
+
+ $handler = new SimpleAuthenticationHandler($authenticator, $this->successHandler, $this->failureHandler);
+ $handler->onAuthenticationSuccess($this->request, $this->token);
+ }
+
+ public function testOnAuthenticationSuccessFallsBackToDefaultHandlerIfNullIsReturned()
+ {
+ $this->successHandler->expects($this->once())
+ ->method('onAuthenticationSuccess')
+ ->with($this->request, $this->token)
+ ->will($this->returnValue($this->response));
+
+ $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\TestSuccessHandlerInterface');
+ $authenticator->expects($this->once())
+ ->method('onAuthenticationSuccess')
+ ->with($this->request, $this->token)
+ ->will($this->returnValue(null));
+
+ $handler = new SimpleAuthenticationHandler($authenticator, $this->successHandler, $this->failureHandler);
+ $result = $handler->onAuthenticationSuccess($this->request, $this->token);
+
+ $this->assertSame($this->response, $result);
+ }
+
+ public function testOnAuthenticationFailureFallsBackToDefaultHandlerIfSimpleIsNotAFailureHandler()
+ {
+ $authenticator = $this->getMock('Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface');
+
+ $this->failureHandler->expects($this->once())
+ ->method('onAuthenticationFailure')
+ ->with($this->request, $this->authenticationException)
+ ->will($this->returnValue($this->response));
+
+ $handler = new SimpleAuthenticationHandler($authenticator, $this->successHandler, $this->failureHandler);
+ $result = $handler->onAuthenticationFailure($this->request, $this->authenticationException);
+
+ $this->assertSame($this->response, $result);
+ }
+
+ public function testOnAuthenticationFailureCallsSimpleAuthenticator()
+ {
+ $this->failureHandler->expects($this->never())
+ ->method('onAuthenticationFailure');
+
+ $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\TestFailureHandlerInterface');
+ $authenticator->expects($this->once())
+ ->method('onAuthenticationFailure')
+ ->with($this->request, $this->authenticationException)
+ ->will($this->returnValue($this->response));
+
+ $handler = new SimpleAuthenticationHandler($authenticator, $this->successHandler, $this->failureHandler);
+ $result = $handler->onAuthenticationFailure($this->request, $this->authenticationException);
+
+ $this->assertSame($this->response, $result);
+ }
+
+ /**
+ * @expectedException \UnexpectedValueException
+ * @expectedExceptionMessage onAuthenticationFailure method must return null to use the default failure handler, or a Response object
+ */
+ public function testOnAuthenticationFailureThrowsAnExceptionIfNonResponseIsReturned()
+ {
+ $this->failureHandler->expects($this->never())
+ ->method('onAuthenticationFailure');
+
+ $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\TestFailureHandlerInterface');
+ $authenticator->expects($this->once())
+ ->method('onAuthenticationFailure')
+ ->with($this->request, $this->authenticationException)
+ ->will($this->returnValue(new \stdClass()));
+
+ $handler = new SimpleAuthenticationHandler($authenticator, $this->successHandler, $this->failureHandler);
+ $handler->onAuthenticationFailure($this->request, $this->authenticationException);
+ }
+
+ public function testOnAuthenticationFailureFallsBackToDefaultHandlerIfNullIsReturned()
+ {
+ $this->failureHandler->expects($this->once())
+ ->method('onAuthenticationFailure')
+ ->with($this->request, $this->authenticationException)
+ ->will($this->returnValue($this->response));
+
+ $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\TestFailureHandlerInterface');
+ $authenticator->expects($this->once())
+ ->method('onAuthenticationFailure')
+ ->with($this->request, $this->authenticationException)
+ ->will($this->returnValue(null));
+
+ $handler = new SimpleAuthenticationHandler($authenticator, $this->successHandler, $this->failureHandler);
+ $result = $handler->onAuthenticationFailure($this->request, $this->authenticationException);
+
+ $this->assertSame($this->response, $result);
+ }
+}
+
+interface TestSuccessHandlerInterface extends AuthenticationSuccessHandlerInterface, SimpleAuthenticatorInterface
+{
+}
+
+interface TestFailureHandlerInterface extends AuthenticationFailureHandlerInterface, SimpleAuthenticatorInterface
+{
+}
diff --git a/Http/Tests/EntryPoint/BasicAuthenticationEntryPointTest.php b/Http/Tests/EntryPoint/BasicAuthenticationEntryPointTest.php
new file mode 100644
index 0000000..ca5922c
--- /dev/null
+++ b/Http/Tests/EntryPoint/BasicAuthenticationEntryPointTest.php
@@ -0,0 +1,43 @@
+<?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\Tests\EntryPoint;
+
+use Symfony\Component\Security\Http\EntryPoint\BasicAuthenticationEntryPoint;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+
+class BasicAuthenticationEntryPointTest extends \PHPUnit_Framework_TestCase
+{
+ public function testStart()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+
+ $authException = new AuthenticationException('The exception message');
+
+ $entryPoint = new BasicAuthenticationEntryPoint('TheRealmName');
+ $response = $entryPoint->start($request, $authException);
+
+ $this->assertEquals('Basic realm="TheRealmName"', $response->headers->get('WWW-Authenticate'));
+ $this->assertEquals(401, $response->getStatusCode());
+ }
+
+ public function testStartWithoutAuthException()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+
+ $entryPoint = new BasicAuthenticationEntryPoint('TheRealmName');
+
+ $response = $entryPoint->start($request);
+
+ $this->assertEquals('Basic realm="TheRealmName"', $response->headers->get('WWW-Authenticate'));
+ $this->assertEquals(401, $response->getStatusCode());
+ }
+}
diff --git a/Http/Tests/EntryPoint/DigestAuthenticationEntryPointTest.php b/Http/Tests/EntryPoint/DigestAuthenticationEntryPointTest.php
new file mode 100644
index 0000000..181e340
--- /dev/null
+++ b/Http/Tests/EntryPoint/DigestAuthenticationEntryPointTest.php
@@ -0,0 +1,56 @@
+<?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\Tests\EntryPoint;
+
+use Symfony\Component\Security\Http\EntryPoint\DigestAuthenticationEntryPoint;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\Exception\NonceExpiredException;
+
+class DigestAuthenticationEntryPointTest extends \PHPUnit_Framework_TestCase
+{
+ public function testStart()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+
+ $authenticationException = new AuthenticationException('TheAuthenticationExceptionMessage');
+
+ $entryPoint = new DigestAuthenticationEntryPoint('TheRealmName', 'TheKey');
+ $response = $entryPoint->start($request, $authenticationException);
+
+ $this->assertEquals(401, $response->getStatusCode());
+ $this->assertRegExp('/^Digest realm="TheRealmName", qop="auth", nonce="[a-zA-Z0-9\/+]+={0,2}"$/', $response->headers->get('WWW-Authenticate'));
+ }
+
+ public function testStartWithNoException()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+
+ $entryPoint = new DigestAuthenticationEntryPoint('TheRealmName', 'TheKey');
+ $response = $entryPoint->start($request);
+
+ $this->assertEquals(401, $response->getStatusCode());
+ $this->assertRegExp('/^Digest realm="TheRealmName", qop="auth", nonce="[a-zA-Z0-9\/+]+={0,2}"$/', $response->headers->get('WWW-Authenticate'));
+ }
+
+ public function testStartWithNonceExpiredException()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+
+ $nonceExpiredException = new NonceExpiredException('TheNonceExpiredExceptionMessage');
+
+ $entryPoint = new DigestAuthenticationEntryPoint('TheRealmName', 'TheKey');
+ $response = $entryPoint->start($request, $nonceExpiredException);
+
+ $this->assertEquals(401, $response->getStatusCode());
+ $this->assertRegExp('/^Digest realm="TheRealmName", qop="auth", nonce="[a-zA-Z0-9\/+]+={0,2}", stale="true"$/', $response->headers->get('WWW-Authenticate'));
+ }
+}
diff --git a/Http/Tests/EntryPoint/FormAuthenticationEntryPointTest.php b/Http/Tests/EntryPoint/FormAuthenticationEntryPointTest.php
new file mode 100644
index 0000000..3acb9c2
--- /dev/null
+++ b/Http/Tests/EntryPoint/FormAuthenticationEntryPointTest.php
@@ -0,0 +1,67 @@
+<?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\Tests\EntryPoint;
+
+use Symfony\Component\Security\Http\EntryPoint\FormAuthenticationEntryPoint;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
+class FormAuthenticationEntryPointTest extends \PHPUnit_Framework_TestCase
+{
+ public function testStart()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request', array(), array(), '', false, false);
+ $response = $this->getMock('Symfony\Component\HttpFoundation\Response');
+
+ $httpKernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
+ $httpUtils = $this->getMock('Symfony\Component\Security\Http\HttpUtils');
+ $httpUtils
+ ->expects($this->once())
+ ->method('createRedirectResponse')
+ ->with($this->equalTo($request), $this->equalTo('/the/login/path'))
+ ->will($this->returnValue($response))
+ ;
+
+ $entryPoint = new FormAuthenticationEntryPoint($httpKernel, $httpUtils, '/the/login/path', false);
+
+ $this->assertEquals($response, $entryPoint->start($request));
+ }
+
+ public function testStartWithUseForward()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request', array(), array(), '', false, false);
+ $subRequest = $this->getMock('Symfony\Component\HttpFoundation\Request', array(), array(), '', false, false);
+ $response = new \Symfony\Component\HttpFoundation\Response('', 200);
+
+ $httpUtils = $this->getMock('Symfony\Component\Security\Http\HttpUtils');
+ $httpUtils
+ ->expects($this->once())
+ ->method('createRequest')
+ ->with($this->equalTo($request), $this->equalTo('/the/login/path'))
+ ->will($this->returnValue($subRequest))
+ ;
+
+ $httpKernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
+ $httpKernel
+ ->expects($this->once())
+ ->method('handle')
+ ->with($this->equalTo($subRequest), $this->equalTo(HttpKernelInterface::SUB_REQUEST))
+ ->will($this->returnValue($response))
+ ;
+
+ $entryPoint = new FormAuthenticationEntryPoint($httpKernel, $httpUtils, '/the/login/path', true);
+
+ $entryPointResponse = $entryPoint->start($request);
+
+ $this->assertEquals($response, $entryPointResponse);
+ $this->assertEquals(401, $entryPointResponse->headers->get('X-Status-Code'));
+ }
+}
diff --git a/Http/Tests/EntryPoint/RetryAuthenticationEntryPointTest.php b/Http/Tests/EntryPoint/RetryAuthenticationEntryPointTest.php
new file mode 100644
index 0000000..ff5fbc2
--- /dev/null
+++ b/Http/Tests/EntryPoint/RetryAuthenticationEntryPointTest.php
@@ -0,0 +1,64 @@
+<?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\Tests\EntryPoint;
+
+use Symfony\Component\Security\Http\EntryPoint\RetryAuthenticationEntryPoint;
+use Symfony\Component\HttpFoundation\Request;
+
+class RetryAuthenticationEntryPointTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider dataForStart
+ */
+ public function testStart($httpPort, $httpsPort, $request, $expectedUrl)
+ {
+ $entryPoint = new RetryAuthenticationEntryPoint($httpPort, $httpsPort);
+ $response = $entryPoint->start($request);
+
+ $this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $response);
+ $this->assertEquals($expectedUrl, $response->headers->get('Location'));
+ }
+
+ public function dataForStart()
+ {
+ if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
+ return array(array());
+ }
+
+ return array(
+ array(
+ 80,
+ 443,
+ Request::create('http://localhost/foo/bar?baz=bat'),
+ 'https://localhost/foo/bar?baz=bat',
+ ),
+ array(
+ 80,
+ 443,
+ Request::create('https://localhost/foo/bar?baz=bat'),
+ 'http://localhost/foo/bar?baz=bat',
+ ),
+ array(
+ 80,
+ 123,
+ Request::create('http://localhost/foo/bar?baz=bat'),
+ 'https://localhost:123/foo/bar?baz=bat',
+ ),
+ array(
+ 8080,
+ 443,
+ Request::create('https://localhost/foo/bar?baz=bat'),
+ 'http://localhost:8080/foo/bar?baz=bat',
+ ),
+ );
+ }
+}
diff --git a/Http/Tests/Firewall/AbstractPreAuthenticatedListenerTest.php b/Http/Tests/Firewall/AbstractPreAuthenticatedListenerTest.php
new file mode 100644
index 0000000..6e34532
--- /dev/null
+++ b/Http/Tests/Firewall/AbstractPreAuthenticatedListenerTest.php
@@ -0,0 +1,252 @@
+<?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\Tests\Firewall;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
+use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+
+class AbstractPreAuthenticatedListenerTest extends \PHPUnit_Framework_TestCase
+{
+ public function testHandleWithValidValues()
+ {
+ $userCredentials = array('TheUser', 'TheCredentials');
+
+ $request = new Request(array(), array(), array(), array(), array(), array());
+
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $context
+ ->expects($this->any())
+ ->method('getToken')
+ ->will($this->returnValue(null))
+ ;
+ $context
+ ->expects($this->once())
+ ->method('setToken')
+ ->with($this->equalTo($token))
+ ;
+
+ $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
+ $authenticationManager
+ ->expects($this->once())
+ ->method('authenticate')
+ ->with($this->isInstanceOf('Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken'))
+ ->will($this->returnValue($token))
+ ;
+
+ $listener = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Firewall\AbstractPreAuthenticatedListener', array(
+ $context,
+ $authenticationManager,
+ 'TheProviderKey',
+ ));
+ $listener
+ ->expects($this->once())
+ ->method('getPreAuthenticatedData')
+ ->will($this->returnValue($userCredentials));
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+
+ $listener->handle($event);
+ }
+
+ public function testHandleWhenAuthenticationFails()
+ {
+ $userCredentials = array('TheUser', 'TheCredentials');
+
+ $request = new Request(array(), array(), array(), array(), array(), array());
+
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $context
+ ->expects($this->any())
+ ->method('getToken')
+ ->will($this->returnValue(null))
+ ;
+ $context
+ ->expects($this->never())
+ ->method('setToken')
+ ;
+
+ $exception = new AuthenticationException('Authentication failed.');
+ $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
+ $authenticationManager
+ ->expects($this->once())
+ ->method('authenticate')
+ ->with($this->isInstanceOf('Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken'))
+ ->will($this->throwException($exception))
+ ;
+
+ $listener = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Firewall\AbstractPreAuthenticatedListener', array(
+ $context,
+ $authenticationManager,
+ 'TheProviderKey',
+ ));
+ $listener
+ ->expects($this->once())
+ ->method('getPreAuthenticatedData')
+ ->will($this->returnValue($userCredentials));
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+
+ $listener->handle($event);
+ }
+
+ public function testHandleWhenAuthenticationFailsWithDifferentToken()
+ {
+ $userCredentials = array('TheUser', 'TheCredentials');
+
+ $token = new UsernamePasswordToken('TheUsername', 'ThePassword', 'TheProviderKey', array('ROLE_FOO'));
+
+ $request = new Request(array(), array(), array(), array(), array(), array());
+
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $context
+ ->expects($this->any())
+ ->method('getToken')
+ ->will($this->returnValue($token))
+ ;
+ $context
+ ->expects($this->never())
+ ->method('setToken')
+ ;
+
+ $exception = new AuthenticationException('Authentication failed.');
+ $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
+ $authenticationManager
+ ->expects($this->once())
+ ->method('authenticate')
+ ->with($this->isInstanceOf('Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken'))
+ ->will($this->throwException($exception))
+ ;
+
+ $listener = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Firewall\AbstractPreAuthenticatedListener', array(
+ $context,
+ $authenticationManager,
+ 'TheProviderKey',
+ ));
+ $listener
+ ->expects($this->once())
+ ->method('getPreAuthenticatedData')
+ ->will($this->returnValue($userCredentials));
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+
+ $listener->handle($event);
+ }
+
+ public function testHandleWithASimilarAuthenticatedToken()
+ {
+ $userCredentials = array('TheUser', 'TheCredentials');
+
+ $request = new Request(array(), array(), array(), array(), array(), array());
+
+ $token = new PreAuthenticatedToken('TheUser', 'TheCredentials', 'TheProviderKey', array('ROLE_FOO'));
+
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $context
+ ->expects($this->any())
+ ->method('getToken')
+ ->will($this->returnValue($token))
+ ;
+
+ $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
+ $authenticationManager
+ ->expects($this->never())
+ ->method('authenticate')
+ ;
+
+ $listener = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Firewall\AbstractPreAuthenticatedListener', array(
+ $context,
+ $authenticationManager,
+ 'TheProviderKey',
+ ));
+ $listener
+ ->expects($this->once())
+ ->method('getPreAuthenticatedData')
+ ->will($this->returnValue($userCredentials));
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+
+ $listener->handle($event);
+ }
+
+ public function testHandleWithAnInvalidSimilarToken()
+ {
+ $userCredentials = array('TheUser', 'TheCredentials');
+
+ $request = new Request(array(), array(), array(), array(), array(), array());
+
+ $token = new PreAuthenticatedToken('AnotherUser', 'TheCredentials', 'TheProviderKey', array('ROLE_FOO'));
+
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $context
+ ->expects($this->any())
+ ->method('getToken')
+ ->will($this->returnValue($token))
+ ;
+ $context
+ ->expects($this->once())
+ ->method('setToken')
+ ->with($this->equalTo(null))
+ ;
+
+ $exception = new AuthenticationException('Authentication failed.');
+ $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
+ $authenticationManager
+ ->expects($this->once())
+ ->method('authenticate')
+ ->with($this->isInstanceOf('Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken'))
+ ->will($this->throwException($exception))
+ ;
+
+ $listener = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Firewall\AbstractPreAuthenticatedListener', array(
+ $context,
+ $authenticationManager,
+ 'TheProviderKey',
+ ));
+ $listener
+ ->expects($this->once())
+ ->method('getPreAuthenticatedData')
+ ->will($this->returnValue($userCredentials));
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+
+ $listener->handle($event);
+ }
+}
diff --git a/Http/Tests/Firewall/AccessListenerTest.php b/Http/Tests/Firewall/AccessListenerTest.php
new file mode 100644
index 0000000..f9b0f3c
--- /dev/null
+++ b/Http/Tests/Firewall/AccessListenerTest.php
@@ -0,0 +1,208 @@
+<?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\Tests\Firewall;
+
+use Symfony\Component\Security\Http\Firewall\AccessListener;
+
+class AccessListenerTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @expectedException \Symfony\Component\Security\Core\Exception\AccessDeniedException
+ */
+ public function testHandleWhenTheAccessDecisionManagerDecidesToRefuseAccess()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request', array(), array(), '', false, false);
+
+ $accessMap = $this->getMock('Symfony\Component\Security\Http\AccessMapInterface');
+ $accessMap
+ ->expects($this->any())
+ ->method('getPatterns')
+ ->with($this->equalTo($request))
+ ->will($this->returnValue(array(array('foo' => 'bar'), null)))
+ ;
+
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ $token
+ ->expects($this->any())
+ ->method('isAuthenticated')
+ ->will($this->returnValue(true))
+ ;
+
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $context
+ ->expects($this->any())
+ ->method('getToken')
+ ->will($this->returnValue($token))
+ ;
+
+ $accessDecisionManager = $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface');
+ $accessDecisionManager
+ ->expects($this->once())
+ ->method('decide')
+ ->with($this->equalTo($token), $this->equalTo(array('foo' => 'bar')), $this->equalTo($request))
+ ->will($this->returnValue(false))
+ ;
+
+ $listener = new AccessListener(
+ $context,
+ $accessDecisionManager,
+ $accessMap,
+ $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface')
+ );
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+
+ $listener->handle($event);
+ }
+
+ public function testHandleWhenTheTokenIsNotAuthenticated()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request', array(), array(), '', false, false);
+
+ $accessMap = $this->getMock('Symfony\Component\Security\Http\AccessMapInterface');
+ $accessMap
+ ->expects($this->any())
+ ->method('getPatterns')
+ ->with($this->equalTo($request))
+ ->will($this->returnValue(array(array('foo' => 'bar'), null)))
+ ;
+
+ $notAuthenticatedToken = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ $notAuthenticatedToken
+ ->expects($this->any())
+ ->method('isAuthenticated')
+ ->will($this->returnValue(false))
+ ;
+
+ $authenticatedToken = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ $authenticatedToken
+ ->expects($this->any())
+ ->method('isAuthenticated')
+ ->will($this->returnValue(true))
+ ;
+
+ $authManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
+ $authManager
+ ->expects($this->once())
+ ->method('authenticate')
+ ->with($this->equalTo($notAuthenticatedToken))
+ ->will($this->returnValue($authenticatedToken))
+ ;
+
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $context
+ ->expects($this->any())
+ ->method('getToken')
+ ->will($this->returnValue($notAuthenticatedToken))
+ ;
+ $context
+ ->expects($this->once())
+ ->method('setToken')
+ ->with($this->equalTo($authenticatedToken))
+ ;
+
+ $accessDecisionManager = $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface');
+ $accessDecisionManager
+ ->expects($this->once())
+ ->method('decide')
+ ->with($this->equalTo($authenticatedToken), $this->equalTo(array('foo' => 'bar')), $this->equalTo($request))
+ ->will($this->returnValue(true))
+ ;
+
+ $listener = new AccessListener(
+ $context,
+ $accessDecisionManager,
+ $accessMap,
+ $authManager
+ );
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+
+ $listener->handle($event);
+ }
+
+ public function testHandleWhenThereIsNoAccessMapEntryMatchingTheRequest()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request', array(), array(), '', false, false);
+
+ $accessMap = $this->getMock('Symfony\Component\Security\Http\AccessMapInterface');
+ $accessMap
+ ->expects($this->any())
+ ->method('getPatterns')
+ ->with($this->equalTo($request))
+ ->will($this->returnValue(array(null, null)))
+ ;
+
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ $token
+ ->expects($this->never())
+ ->method('isAuthenticated')
+ ;
+
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $context
+ ->expects($this->any())
+ ->method('getToken')
+ ->will($this->returnValue($token))
+ ;
+
+ $listener = new AccessListener(
+ $context,
+ $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface'),
+ $accessMap,
+ $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface')
+ );
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+
+ $listener->handle($event);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException
+ */
+ public function testHandleWhenTheSecurityContextHasNoToken()
+ {
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $context
+ ->expects($this->any())
+ ->method('getToken')
+ ->will($this->returnValue(null))
+ ;
+
+ $listener = new AccessListener(
+ $context,
+ $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface'),
+ $this->getMock('Symfony\Component\Security\Http\AccessMapInterface'),
+ $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface')
+ );
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+
+ $listener->handle($event);
+ }
+}
diff --git a/Http/Tests/Firewall/AnonymousAuthenticationListenerTest.php b/Http/Tests/Firewall/AnonymousAuthenticationListenerTest.php
new file mode 100644
index 0000000..7b24e61
--- /dev/null
+++ b/Http/Tests/Firewall/AnonymousAuthenticationListenerTest.php
@@ -0,0 +1,68 @@
+<?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\Tests\Firewall;
+
+use Symfony\Component\Security\Http\Firewall\AnonymousAuthenticationListener;
+
+class AnonymousAuthenticationListenerTest extends \PHPUnit_Framework_TestCase
+{
+ public function testHandleWithContextHavingAToken()
+ {
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $context
+ ->expects($this->any())
+ ->method('getToken')
+ ->will($this->returnValue($this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')))
+ ;
+ $context
+ ->expects($this->never())
+ ->method('setToken')
+ ;
+
+ $listener = new AnonymousAuthenticationListener($context, 'TheKey');
+ $listener->handle($this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false));
+ }
+
+ public function testHandleWithContextHavingNoToken()
+ {
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $context
+ ->expects($this->any())
+ ->method('getToken')
+ ->will($this->returnValue(null))
+ ;
+ $context
+ ->expects($this->once())
+ ->method('setToken')
+ ->with(self::logicalAnd(
+ $this->isInstanceOf('Symfony\Component\Security\Core\Authentication\Token\AnonymousToken'),
+ $this->attributeEqualTo('key', 'TheKey')
+ ))
+ ;
+
+ $listener = new AnonymousAuthenticationListener($context, 'TheKey');
+ $listener->handle($this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false));
+ }
+
+ public function testHandledEventIsLogged()
+ {
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $logger = $this->getMock('Psr\Log\LoggerInterface');
+ $logger->expects($this->once())
+ ->method('info')
+ ->with('Populated SecurityContext with an anonymous Token')
+ ;
+
+ $listener = new AnonymousAuthenticationListener($context, 'TheKey', $logger);
+ $listener->handle($this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false));
+ }
+}
diff --git a/Http/Tests/Firewall/BasicAuthenticationListenerTest.php b/Http/Tests/Firewall/BasicAuthenticationListenerTest.php
new file mode 100644
index 0000000..0ef993f
--- /dev/null
+++ b/Http/Tests/Firewall/BasicAuthenticationListenerTest.php
@@ -0,0 +1,249 @@
+<?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\Tests\Firewall;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
+use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Security\Http\Firewall\BasicAuthenticationListener;
+use Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager;
+
+class BasicAuthenticationListenerTest extends \PHPUnit_Framework_TestCase
+{
+ public function testHandleWithValidUsernameAndPasswordServerParameters()
+ {
+ $request = new Request(array(), array(), array(), array(), array(), array(
+ 'PHP_AUTH_USER' => 'TheUsername',
+ 'PHP_AUTH_PW' => 'ThePassword',
+ ));
+
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $context
+ ->expects($this->any())
+ ->method('getToken')
+ ->will($this->returnValue(null))
+ ;
+ $context
+ ->expects($this->once())
+ ->method('setToken')
+ ->with($this->equalTo($token))
+ ;
+
+ $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
+ $authenticationManager
+ ->expects($this->once())
+ ->method('authenticate')
+ ->with($this->isInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken'))
+ ->will($this->returnValue($token))
+ ;
+
+ $listener = new BasicAuthenticationListener(
+ $context,
+ $authenticationManager,
+ 'TheProviderKey',
+ $this->getMock('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface')
+ );
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+
+ $listener->handle($event);
+ }
+
+ public function testHandleWhenAuthenticationFails()
+ {
+ $request = new Request(array(), array(), array(), array(), array(), array(
+ 'PHP_AUTH_USER' => 'TheUsername',
+ 'PHP_AUTH_PW' => 'ThePassword',
+ ));
+
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $context
+ ->expects($this->any())
+ ->method('getToken')
+ ->will($this->returnValue(null))
+ ;
+ $context
+ ->expects($this->never())
+ ->method('setToken')
+ ;
+
+ $response = new Response();
+
+ $authenticationEntryPoint = $this->getMock('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface');
+ $authenticationEntryPoint
+ ->expects($this->any())
+ ->method('start')
+ ->with($this->equalTo($request), $this->isInstanceOf('Symfony\Component\Security\Core\Exception\AuthenticationException'))
+ ->will($this->returnValue($response))
+ ;
+
+ $listener = new BasicAuthenticationListener(
+ $context,
+ new AuthenticationProviderManager(array($this->getMock('Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface'))),
+ 'TheProviderKey',
+ $authenticationEntryPoint
+ );
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+ $event
+ ->expects($this->once())
+ ->method('setResponse')
+ ->with($this->equalTo($response))
+ ;
+
+ $listener->handle($event);
+ }
+
+ public function testHandleWithNoUsernameServerParameter()
+ {
+ $request = new Request();
+
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $context
+ ->expects($this->never())
+ ->method('getToken')
+ ;
+
+ $listener = new BasicAuthenticationListener(
+ $context,
+ $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'),
+ 'TheProviderKey',
+ $this->getMock('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface')
+ );
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+
+ $listener->handle($event);
+ }
+
+ public function testHandleWithASimilarAuthenticatedToken()
+ {
+ $request = new Request(array(), array(), array(), array(), array(), array('PHP_AUTH_USER' => 'TheUsername'));
+
+ $token = new UsernamePasswordToken('TheUsername', 'ThePassword', 'TheProviderKey', array('ROLE_FOO'));
+
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $context
+ ->expects($this->any())
+ ->method('getToken')
+ ->will($this->returnValue($token))
+ ;
+
+ $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
+ $authenticationManager
+ ->expects($this->never())
+ ->method('authenticate')
+ ;
+
+ $listener = new BasicAuthenticationListener(
+ $context,
+ $authenticationManager,
+ 'TheProviderKey',
+ $this->getMock('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface')
+ );
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+
+ $listener->handle($event);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage $providerKey must not be empty
+ */
+ public function testItRequiresProviderKey()
+ {
+ new BasicAuthenticationListener(
+ $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'),
+ $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'),
+ '',
+ $this->getMock('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface')
+ );
+ }
+
+ public function testHandleWithADifferentAuthenticatedToken()
+ {
+ $request = new Request(array(), array(), array(), array(), array(), array(
+ 'PHP_AUTH_USER' => 'TheUsername',
+ 'PHP_AUTH_PW' => 'ThePassword',
+ ));
+
+ $token = new PreAuthenticatedToken('TheUser', 'TheCredentials', 'TheProviderKey', array('ROLE_FOO'));
+
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $context
+ ->expects($this->any())
+ ->method('getToken')
+ ->will($this->returnValue($token))
+ ;
+ $context
+ ->expects($this->never())
+ ->method('setToken')
+ ;
+
+ $response = new Response();
+
+ $authenticationEntryPoint = $this->getMock('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface');
+ $authenticationEntryPoint
+ ->expects($this->any())
+ ->method('start')
+ ->with($this->equalTo($request), $this->isInstanceOf('Symfony\Component\Security\Core\Exception\AuthenticationException'))
+ ->will($this->returnValue($response))
+ ;
+
+ $listener = new BasicAuthenticationListener(
+ $context,
+ new AuthenticationProviderManager(array($this->getMock('Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface'))),
+ 'TheProviderKey',
+ $authenticationEntryPoint
+ );
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+ $event
+ ->expects($this->once())
+ ->method('setResponse')
+ ->with($this->equalTo($response))
+ ;
+
+ $listener->handle($event);
+ }
+}
diff --git a/Http/Tests/Firewall/ChannelListenerTest.php b/Http/Tests/Firewall/ChannelListenerTest.php
new file mode 100644
index 0000000..1465224
--- /dev/null
+++ b/Http/Tests/Firewall/ChannelListenerTest.php
@@ -0,0 +1,180 @@
+<?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\Tests\Firewall;
+
+use Symfony\Component\Security\Http\Firewall\ChannelListener;
+use Symfony\Component\HttpFoundation\Response;
+
+class ChannelListenerTest extends \PHPUnit_Framework_TestCase
+{
+ public function testHandleWithNotSecuredRequestAndHttpChannel()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request', array(), array(), '', false, false);
+ $request
+ ->expects($this->any())
+ ->method('isSecure')
+ ->will($this->returnValue(false))
+ ;
+
+ $accessMap = $this->getMock('Symfony\Component\Security\Http\AccessMapInterface');
+ $accessMap
+ ->expects($this->any())
+ ->method('getPatterns')
+ ->with($this->equalTo($request))
+ ->will($this->returnValue(array(array(), 'http')))
+ ;
+
+ $entryPoint = $this->getMock('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface');
+ $entryPoint
+ ->expects($this->never())
+ ->method('start')
+ ;
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+ $event
+ ->expects($this->never())
+ ->method('setResponse')
+ ;
+
+ $listener = new ChannelListener($accessMap, $entryPoint);
+ $listener->handle($event);
+ }
+
+ public function testHandleWithSecuredRequestAndHttpsChannel()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request', array(), array(), '', false, false);
+ $request
+ ->expects($this->any())
+ ->method('isSecure')
+ ->will($this->returnValue(true))
+ ;
+
+ $accessMap = $this->getMock('Symfony\Component\Security\Http\AccessMapInterface');
+ $accessMap
+ ->expects($this->any())
+ ->method('getPatterns')
+ ->with($this->equalTo($request))
+ ->will($this->returnValue(array(array(), 'https')))
+ ;
+
+ $entryPoint = $this->getMock('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface');
+ $entryPoint
+ ->expects($this->never())
+ ->method('start')
+ ;
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+ $event
+ ->expects($this->never())
+ ->method('setResponse')
+ ;
+
+ $listener = new ChannelListener($accessMap, $entryPoint);
+ $listener->handle($event);
+ }
+
+ public function testHandleWithNotSecuredRequestAndHttpsChannel()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request', array(), array(), '', false, false);
+ $request
+ ->expects($this->any())
+ ->method('isSecure')
+ ->will($this->returnValue(false))
+ ;
+
+ $response = new Response();
+
+ $accessMap = $this->getMock('Symfony\Component\Security\Http\AccessMapInterface');
+ $accessMap
+ ->expects($this->any())
+ ->method('getPatterns')
+ ->with($this->equalTo($request))
+ ->will($this->returnValue(array(array(), 'https')))
+ ;
+
+ $entryPoint = $this->getMock('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface');
+ $entryPoint
+ ->expects($this->once())
+ ->method('start')
+ ->with($this->equalTo($request))
+ ->will($this->returnValue($response))
+ ;
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+ $event
+ ->expects($this->once())
+ ->method('setResponse')
+ ->with($this->equalTo($response))
+ ;
+
+ $listener = new ChannelListener($accessMap, $entryPoint);
+ $listener->handle($event);
+ }
+
+ public function testHandleWithSecuredRequestAndHttpChannel()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request', array(), array(), '', false, false);
+ $request
+ ->expects($this->any())
+ ->method('isSecure')
+ ->will($this->returnValue(true))
+ ;
+
+ $response = new Response();
+
+ $accessMap = $this->getMock('Symfony\Component\Security\Http\AccessMapInterface');
+ $accessMap
+ ->expects($this->any())
+ ->method('getPatterns')
+ ->with($this->equalTo($request))
+ ->will($this->returnValue(array(array(), 'http')))
+ ;
+
+ $entryPoint = $this->getMock('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface');
+ $entryPoint
+ ->expects($this->once())
+ ->method('start')
+ ->with($this->equalTo($request))
+ ->will($this->returnValue($response))
+ ;
+
+ $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ $event
+ ->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+ $event
+ ->expects($this->once())
+ ->method('setResponse')
+ ->with($this->equalTo($response))
+ ;
+
+ $listener = new ChannelListener($accessMap, $entryPoint);
+ $listener->handle($event);
+ }
+}
diff --git a/Http/Tests/Firewall/ContextListenerTest.php b/Http/Tests/Firewall/ContextListenerTest.php
new file mode 100644
index 0000000..d6bc5b4
--- /dev/null
+++ b/Http/Tests/Firewall/ContextListenerTest.php
@@ -0,0 +1,248 @@
+<?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\Tests\Firewall;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
+use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
+use Symfony\Component\Security\Core\SecurityContext;
+use Symfony\Component\Security\Http\Firewall\ContextListener;
+
+class ContextListenerTest extends \PHPUnit_Framework_TestCase
+{
+ protected function setUp()
+ {
+ $this->securityContext = new SecurityContext(
+ $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'),
+ $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface')
+ );
+ }
+
+ protected function tearDown()
+ {
+ unset($this->securityContext);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage $contextKey must not be empty
+ */
+ public function testItRequiresContextKey()
+ {
+ new ContextListener(
+ $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'),
+ array(),
+ ''
+ );
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage User provider "stdClass" must implement "Symfony\Component\Security\Core\User\UserProviderInterface
+ */
+ public function testUserProvidersNeedToImplementAnInterface()
+ {
+ new ContextListener(
+ $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'),
+ array(new \stdClass()),
+ 'key123'
+ );
+ }
+
+ public function testOnKernelResponseWillAddSession()
+ {
+ $session = $this->runSessionOnKernelResponse(
+ new UsernamePasswordToken('test1', 'pass1', 'phpunit'),
+ null
+ );
+
+ $token = unserialize($session->get('_security_session'));
+ $this->assertInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken', $token);
+ $this->assertEquals('test1', $token->getUsername());
+ }
+
+ public function testOnKernelResponseWillReplaceSession()
+ {
+ $session = $this->runSessionOnKernelResponse(
+ new UsernamePasswordToken('test1', 'pass1', 'phpunit'),
+ 'C:10:"serialized"'
+ );
+
+ $token = unserialize($session->get('_security_session'));
+ $this->assertInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken', $token);
+ $this->assertEquals('test1', $token->getUsername());
+ }
+
+ public function testOnKernelResponseWillRemoveSession()
+ {
+ $session = $this->runSessionOnKernelResponse(
+ null,
+ 'C:10:"serialized"'
+ );
+
+ $this->assertFalse($session->has('_security_session'));
+ }
+
+ public function testOnKernelResponseWithoutSession()
+ {
+ $this->securityContext->setToken(new UsernamePasswordToken('test1', 'pass1', 'phpunit'));
+ $request = new Request();
+ $session = new Session(new MockArraySessionStorage());
+ $request->setSession($session);
+
+ $event = new FilterResponseEvent(
+ $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'),
+ $request,
+ HttpKernelInterface::MASTER_REQUEST,
+ new Response()
+ );
+
+ $listener = new ContextListener($this->securityContext, array(), 'session');
+ $listener->onKernelResponse($event);
+
+ $this->assertTrue($session->isStarted());
+ }
+
+ public function testOnKernelResponseWithoutSessionNorToken()
+ {
+ $request = new Request();
+ $session = new Session(new MockArraySessionStorage());
+ $request->setSession($session);
+
+ $event = new FilterResponseEvent(
+ $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'),
+ $request,
+ HttpKernelInterface::MASTER_REQUEST,
+ new Response()
+ );
+
+ $listener = new ContextListener($this->securityContext, array(), 'session');
+ $listener->onKernelResponse($event);
+
+ $this->assertFalse($session->isStarted());
+ }
+
+ /**
+ * @dataProvider provideInvalidToken
+ */
+ public function testInvalidTokenInSession($token)
+ {
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+ $session = $this->getMock('Symfony\Component\HttpFoundation\Session\SessionInterface');
+
+ $event->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request));
+ $request->expects($this->any())
+ ->method('hasPreviousSession')
+ ->will($this->returnValue(true));
+ $request->expects($this->any())
+ ->method('getSession')
+ ->will($this->returnValue($session));
+ $session->expects($this->any())
+ ->method('get')
+ ->with('_security_key123')
+ ->will($this->returnValue($token));
+ $context->expects($this->once())
+ ->method('setToken')
+ ->with(null);
+
+ $listener = new ContextListener($context, array(), 'key123');
+ $listener->handle($event);
+ }
+
+ public function provideInvalidToken()
+ {
+ return array(
+ array(serialize(new \__PHP_Incomplete_Class())),
+ array(serialize(null)),
+ array(null),
+ );
+ }
+
+ public function testHandleAddsKernelResponseListener()
+ {
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
+ $event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $listener = new ContextListener($context, array(), 'key123', null, $dispatcher);
+
+ $event->expects($this->any())
+ ->method('isMasterRequest')
+ ->will($this->returnValue(true));
+ $event->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($this->getMock('Symfony\Component\HttpFoundation\Request')));
+
+ $dispatcher->expects($this->once())
+ ->method('addListener')
+ ->with(KernelEvents::RESPONSE, array($listener, 'onKernelResponse'));
+
+ $listener->handle($event);
+ }
+
+ public function testHandleRemovesTokenIfNoPreviousSessionWasFound()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+ $request->expects($this->any())->method('hasPreviousSession')->will($this->returnValue(false));
+
+ $event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $event->expects($this->any())->method('getRequest')->will($this->returnValue($request));
+
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $context->expects($this->once())->method('setToken')->with(null);
+
+ $listener = new ContextListener($context, array(), 'key123');
+ $listener->handle($event);
+ }
+
+ protected function runSessionOnKernelResponse($newToken, $original = null)
+ {
+ $session = new Session(new MockArraySessionStorage());
+
+ if ($original !== null) {
+ $session->set('_security_session', $original);
+ }
+
+ $this->securityContext->setToken($newToken);
+
+ $request = new Request();
+ $request->setSession($session);
+ $request->cookies->set('MOCKSESSID', true);
+
+ $event = new FilterResponseEvent(
+ $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'),
+ $request,
+ HttpKernelInterface::MASTER_REQUEST,
+ new Response()
+ );
+
+ $listener = new ContextListener($this->securityContext, array(), 'session');
+ $listener->onKernelResponse($event);
+
+ return $session;
+ }
+}
diff --git a/Http/Tests/Firewall/DigestDataTest.php b/Http/Tests/Firewall/DigestDataTest.php
new file mode 100644
index 0000000..a7c8d49
--- /dev/null
+++ b/Http/Tests/Firewall/DigestDataTest.php
@@ -0,0 +1,181 @@
+<?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\Tests\Firewall;
+
+use Symfony\Component\Security\Http\Firewall\DigestData;
+
+class DigestDataTest extends \PHPUnit_Framework_TestCase
+{
+ public function testGetResponse()
+ {
+ $digestAuth = new DigestData(
+ 'username="user", realm="Welcome, robot!", '.
+ 'nonce="MTM0NzMyMTgyMy42NzkzOmRlZjM4NmIzOGNjMjE0OWJiNDU0MDAxNzJmYmM1MmZl", '.
+ 'uri="/path/info?p1=5&p2=5", cnonce="MDIwODkz", nc=00000001, qop="auth", '.
+ 'response="b52938fc9e6d7c01be7702ece9031b42"'
+ );
+
+ $this->assertEquals('b52938fc9e6d7c01be7702ece9031b42', $digestAuth->getResponse());
+ }
+
+ public function testGetUsername()
+ {
+ $digestAuth = new DigestData(
+ 'username="user", realm="Welcome, robot!", '.
+ 'nonce="MTM0NzMyMTgyMy42NzkzOmRlZjM4NmIzOGNjMjE0OWJiNDU0MDAxNzJmYmM1MmZl", '.
+ 'uri="/path/info?p1=5&p2=5", cnonce="MDIwODkz", nc=00000001, qop="auth", '.
+ 'response="b52938fc9e6d7c01be7702ece9031b42"'
+ );
+
+ $this->assertEquals('user', $digestAuth->getUsername());
+ }
+
+ public function testGetUsernameWithQuote()
+ {
+ $digestAuth = new DigestData(
+ 'username="\"user\"", realm="Welcome, robot!", '.
+ 'nonce="MTM0NzMyMTgyMy42NzkzOmRlZjM4NmIzOGNjMjE0OWJiNDU0MDAxNzJmYmM1MmZl", '.
+ 'uri="/path/info?p1=5&p2=5", cnonce="MDIwODkz", nc=00000001, qop="auth", '.
+ 'response="b52938fc9e6d7c01be7702ece9031b42"'
+ );
+
+ $this->assertEquals('"user"', $digestAuth->getUsername());
+ }
+
+ public function testGetUsernameWithQuoteAndEscape()
+ {
+ $digestAuth = new DigestData(
+ 'username="\"u\\\\\"ser\"", realm="Welcome, robot!", '.
+ 'nonce="MTM0NzMyMTgyMy42NzkzOmRlZjM4NmIzOGNjMjE0OWJiNDU0MDAxNzJmYmM1MmZl", '.
+ 'uri="/path/info?p1=5&p2=5", cnonce="MDIwODkz", nc=00000001, qop="auth", '.
+ 'response="b52938fc9e6d7c01be7702ece9031b42"'
+ );
+
+ $this->assertEquals('"u\\"ser"', $digestAuth->getUsername());
+ }
+
+ public function testGetUsernameWithSingleQuote()
+ {
+ $digestAuth = new DigestData(
+ 'username="\"u\'ser\"", realm="Welcome, robot!", '.
+ 'nonce="MTM0NzMyMTgyMy42NzkzOmRlZjM4NmIzOGNjMjE0OWJiNDU0MDAxNzJmYmM1MmZl", '.
+ 'uri="/path/info?p1=5&p2=5", cnonce="MDIwODkz", nc=00000001, qop="auth", '.
+ 'response="b52938fc9e6d7c01be7702ece9031b42"'
+ );
+
+ $this->assertEquals('"u\'ser"', $digestAuth->getUsername());
+ }
+
+ public function testGetUsernameWithSingleQuoteAndEscape()
+ {
+ $digestAuth = new DigestData(
+ 'username="\"u\\\'ser\"", realm="Welcome, robot!", '.
+ 'nonce="MTM0NzMyMTgyMy42NzkzOmRlZjM4NmIzOGNjMjE0OWJiNDU0MDAxNzJmYmM1MmZl", '.
+ 'uri="/path/info?p1=5&p2=5", cnonce="MDIwODkz", nc=00000001, qop="auth", '.
+ 'response="b52938fc9e6d7c01be7702ece9031b42"'
+ );
+
+ $this->assertEquals('"u\\\'ser"', $digestAuth->getUsername());
+ }
+
+ public function testGetUsernameWithEscape()
+ {
+ $digestAuth = new DigestData(
+ 'username="\"u\\ser\"", realm="Welcome, robot!", '.
+ 'nonce="MTM0NzMyMTgyMy42NzkzOmRlZjM4NmIzOGNjMjE0OWJiNDU0MDAxNzJmYmM1MmZl", '.
+ 'uri="/path/info?p1=5&p2=5", cnonce="MDIwODkz", nc=00000001, qop="auth", '.
+ 'response="b52938fc9e6d7c01be7702ece9031b42"'
+ );
+
+ $this->assertEquals('"u\\ser"', $digestAuth->getUsername());
+ }
+
+ public function testValidateAndDecode()
+ {
+ $time = microtime(true);
+ $key = 'ThisIsAKey';
+ $nonce = base64_encode($time.':'.md5($time.':'.$key));
+
+ $digestAuth = new DigestData(
+ 'username="user", realm="Welcome, robot!", nonce="'.$nonce.'", '.
+ 'uri="/path/info?p1=5&p2=5", cnonce="MDIwODkz", nc=00000001, qop="auth", '.
+ 'response="b52938fc9e6d7c01be7702ece9031b42"'
+ );
+
+ try {
+ $digestAuth->validateAndDecode($key, 'Welcome, robot!');
+ } catch (\Exception $e) {
+ $this->fail(sprintf('testValidateAndDecode fail with message: %s', $e->getMessage()));
+ }
+ }
+
+ public function testCalculateServerDigest()
+ {
+ $this->calculateServerDigest('user', 'Welcome, robot!', 'pass,word=password', 'ThisIsAKey', '00000001', 'MDIwODkz', 'auth', 'GET', '/path/info?p1=5&p2=5');
+ }
+
+ public function testCalculateServerDigestWithQuote()
+ {
+ $this->calculateServerDigest('\"user\"', 'Welcome, \"robot\"!', 'pass,word=password', 'ThisIsAKey', '00000001', 'MDIwODkz', 'auth', 'GET', '/path/info?p1=5&p2=5');
+ }
+
+ public function testCalculateServerDigestWithQuoteAndEscape()
+ {
+ $this->calculateServerDigest('\"u\\\\\"ser\"', 'Welcome, \"robot\"!', 'pass,word=password', 'ThisIsAKey', '00000001', 'MDIwODkz', 'auth', 'GET', '/path/info?p1=5&p2=5');
+ }
+
+ public function testCalculateServerDigestEscape()
+ {
+ $this->calculateServerDigest('\"u\\ser\"', 'Welcome, \"robot\"!', 'pass,word=password', 'ThisIsAKey', '00000001', 'MDIwODkz', 'auth', 'GET', '/path/info?p1=5&p2=5');
+ $this->calculateServerDigest('\"u\\ser\\\\\"', 'Welcome, \"robot\"!', 'pass,word=password', 'ThisIsAKey', '00000001', 'MDIwODkz', 'auth', 'GET', '/path/info?p1=5&p2=5');
+ }
+
+ public function testIsNonceExpired()
+ {
+ $time = microtime(true) + 10;
+ $key = 'ThisIsAKey';
+ $nonce = base64_encode($time.':'.md5($time.':'.$key));
+
+ $digestAuth = new DigestData(
+ 'username="user", realm="Welcome, robot!", nonce="'.$nonce.'", '.
+ 'uri="/path/info?p1=5&p2=5", cnonce="MDIwODkz", nc=00000001, qop="auth", '.
+ 'response="b52938fc9e6d7c01be7702ece9031b42"'
+ );
+
+ $digestAuth->validateAndDecode($key, 'Welcome, robot!');
+
+ $this->assertFalse($digestAuth->isNonceExpired());
+ }
+
+ protected function setUp()
+ {
+ class_exists('Symfony\Component\Security\Http\Firewall\DigestAuthenticationListener', true);
+ }
+
+ private function calculateServerDigest($username, $realm, $password, $key, $nc, $cnonce, $qop, $method, $uri)
+ {
+ $time = microtime(true);
+ $nonce = base64_encode($time.':'.md5($time.':'.$key));
+
+ $response = md5(
+ md5($username.':'.$realm.':'.$password).':'.$nonce.':'.$nc.':'.$cnonce.':'.$qop.':'.md5($method.':'.$uri)
+ );
+
+ $digest = sprintf('username="%s", realm="%s", nonce="%s", uri="%s", cnonce="%s", nc=%s, qop="%s", response="%s"',
+ $username, $realm, $nonce, $uri, $cnonce, $nc, $qop, $response
+ );
+
+ $digestAuth = new DigestData($digest);
+
+ $this->assertEquals($digestAuth->getResponse(), $digestAuth->calculateServerDigest($password, $method));
+ }
+}
diff --git a/Http/Tests/Firewall/ExceptionListenerTest.php b/Http/Tests/Firewall/ExceptionListenerTest.php
new file mode 100644
index 0000000..f1409e4
--- /dev/null
+++ b/Http/Tests/Firewall/ExceptionListenerTest.php
@@ -0,0 +1,184 @@
+<?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\Tests\Firewall;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
+use Symfony\Component\Security\Core\Exception\AccessDeniedException;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Core\SecurityContextInterface;
+use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface;
+use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
+use Symfony\Component\Security\Http\Firewall\ExceptionListener;
+use Symfony\Component\Security\Http\HttpUtils;
+
+class ExceptionListenerTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider getAuthenticationExceptionProvider
+ */
+ public function testAuthenticationExceptionWithoutEntryPoint(\Exception $exception, \Exception $eventException = null)
+ {
+ $event = $this->createEvent($exception);
+
+ $listener = $this->createExceptionListener();
+ $listener->onKernelException($event);
+
+ $this->assertNull($event->getResponse());
+ $this->assertSame(null === $eventException ? $exception : $eventException, $event->getException());
+ }
+
+ /**
+ * @dataProvider getAuthenticationExceptionProvider
+ */
+ public function testAuthenticationExceptionWithEntryPoint(\Exception $exception, \Exception $eventException = null)
+ {
+ $event = $this->createEvent($exception = new AuthenticationException());
+
+ $listener = $this->createExceptionListener(null, null, null, $this->createEntryPoint());
+ $listener->onKernelException($event);
+
+ $this->assertEquals('OK', $event->getResponse()->getContent());
+ $this->assertSame($exception, $event->getException());
+ }
+
+ public function getAuthenticationExceptionProvider()
+ {
+ return array(
+ array(new AuthenticationException()),
+ array(new \LogicException('random', 0, $e = new AuthenticationException()), $e),
+ array(new \LogicException('random', 0, $e = new AuthenticationException('embed', 0, new AuthenticationException())), $e),
+ array(new \LogicException('random', 0, $e = new AuthenticationException('embed', 0, new AccessDeniedException())), $e),
+ array(new AuthenticationException('random', 0, new \LogicException())),
+ );
+ }
+
+ /**
+ * @dataProvider getAccessDeniedExceptionProvider
+ */
+ public function testAccessDeniedExceptionFullFledgedAndWithoutAccessDeniedHandlerAndWithoutErrorPage(\Exception $exception, \Exception $eventException = null)
+ {
+ $event = $this->createEvent($exception);
+
+ $listener = $this->createExceptionListener(null, $this->createTrustResolver(true));
+ $listener->onKernelException($event);
+
+ $this->assertNull($event->getResponse());
+ $this->assertSame(null === $eventException ? $exception : $eventException, $event->getException()->getPrevious());
+ }
+
+ /**
+ * @dataProvider getAccessDeniedExceptionProvider
+ */
+ public function testAccessDeniedExceptionFullFledgedAndWithoutAccessDeniedHandlerAndWithErrorPage(\Exception $exception, \Exception $eventException = null)
+ {
+ $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
+ $kernel->expects($this->once())->method('handle')->will($this->returnValue(new Response('error')));
+
+ $event = $this->createEvent($exception, $kernel);
+
+ $httpUtils = $this->getMock('Symfony\Component\Security\Http\HttpUtils');
+ $httpUtils->expects($this->once())->method('createRequest')->will($this->returnValue(Request::create('/error')));
+
+ $listener = $this->createExceptionListener(null, $this->createTrustResolver(true), $httpUtils, null, '/error');
+ $listener->onKernelException($event);
+
+ $this->assertEquals('error', $event->getResponse()->getContent());
+ $this->assertSame(null === $eventException ? $exception : $eventException, $event->getException()->getPrevious());
+ }
+
+ /**
+ * @dataProvider getAccessDeniedExceptionProvider
+ */
+ public function testAccessDeniedExceptionFullFledgedAndWithAccessDeniedHandlerAndWithoutErrorPage(\Exception $exception, \Exception $eventException = null)
+ {
+ $event = $this->createEvent($exception);
+
+ $accessDeniedHandler = $this->getMock('Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface');
+ $accessDeniedHandler->expects($this->once())->method('handle')->will($this->returnValue(new Response('error')));
+
+ $listener = $this->createExceptionListener(null, $this->createTrustResolver(true), null, null, null, $accessDeniedHandler);
+ $listener->onKernelException($event);
+
+ $this->assertEquals('error', $event->getResponse()->getContent());
+ $this->assertSame(null === $eventException ? $exception : $eventException, $event->getException()->getPrevious());
+ }
+
+ /**
+ * @dataProvider getAccessDeniedExceptionProvider
+ */
+ public function testAccessDeniedExceptionNotFullFledged(\Exception $exception, \Exception $eventException = null)
+ {
+ $event = $this->createEvent($exception);
+
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $context->expects($this->once())->method('getToken')->will($this->returnValue($this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')));
+
+ $listener = $this->createExceptionListener($context, $this->createTrustResolver(false), null, $this->createEntryPoint());
+ $listener->onKernelException($event);
+
+ $this->assertEquals('OK', $event->getResponse()->getContent());
+ $this->assertSame(null === $eventException ? $exception : $eventException, $event->getException()->getPrevious());
+ }
+
+ public function getAccessDeniedExceptionProvider()
+ {
+ return array(
+ array(new AccessDeniedException()),
+ array(new \LogicException('random', 0, $e = new AccessDeniedException()), $e),
+ array(new \LogicException('random', 0, $e = new AccessDeniedException('embed', new AccessDeniedException())), $e),
+ array(new \LogicException('random', 0, $e = new AccessDeniedException('embed', new AuthenticationException())), $e),
+ array(new AccessDeniedException('random', new \LogicException())),
+ );
+ }
+
+ private function createEntryPoint()
+ {
+ $entryPoint = $this->getMock('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface');
+ $entryPoint->expects($this->once())->method('start')->will($this->returnValue(new Response('OK')));
+
+ return $entryPoint;
+ }
+
+ private function createTrustResolver($fullFledged)
+ {
+ $trustResolver = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface');
+ $trustResolver->expects($this->once())->method('isFullFledged')->will($this->returnValue($fullFledged));
+
+ return $trustResolver;
+ }
+
+ private function createEvent(\Exception $exception, $kernel = null)
+ {
+ if (null === $kernel) {
+ $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
+ }
+
+ return new GetResponseForExceptionEvent($kernel, Request::create('/'), HttpKernelInterface::MASTER_REQUEST, $exception);
+ }
+
+ private function createExceptionListener(SecurityContextInterface $context = null, AuthenticationTrustResolverInterface $trustResolver = null, HttpUtils $httpUtils = null, AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, AccessDeniedHandlerInterface $accessDeniedHandler = null)
+ {
+ return new ExceptionListener(
+ $context ? $context : $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'),
+ $trustResolver ? $trustResolver : $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface'),
+ $httpUtils ? $httpUtils : $this->getMock('Symfony\Component\Security\Http\HttpUtils'),
+ 'key',
+ $authenticationEntryPoint,
+ $errorPage,
+ $accessDeniedHandler
+ );
+ }
+}
diff --git a/Http/Tests/Firewall/LogoutListenerTest.php b/Http/Tests/Firewall/LogoutListenerTest.php
new file mode 100644
index 0000000..041febc
--- /dev/null
+++ b/Http/Tests/Firewall/LogoutListenerTest.php
@@ -0,0 +1,237 @@
+<?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\Tests\Firewall;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Security\Http\Firewall\LogoutListener;
+
+class LogoutListenerTest extends \PHPUnit_Framework_TestCase
+{
+ public function testHandleUnmatchedPath()
+ {
+ list($listener, $context, $httpUtils, $options) = $this->getListener();
+
+ list($event, $request) = $this->getGetResponseEvent();
+
+ $event->expects($this->never())
+ ->method('setResponse');
+
+ $httpUtils->expects($this->once())
+ ->method('checkRequestPath')
+ ->with($request, $options['logout_path'])
+ ->will($this->returnValue(false));
+
+ $listener->handle($event);
+ }
+
+ public function testHandleMatchedPathWithSuccessHandlerAndCsrfValidation()
+ {
+ $successHandler = $this->getSuccessHandler();
+ $tokenManager = $this->getTokenManager();
+
+ list($listener, $context, $httpUtils, $options) = $this->getListener($successHandler, $tokenManager);
+
+ list($event, $request) = $this->getGetResponseEvent();
+
+ $request->query->set('_csrf_token', 'token');
+
+ $httpUtils->expects($this->once())
+ ->method('checkRequestPath')
+ ->with($request, $options['logout_path'])
+ ->will($this->returnValue(true));
+
+ $tokenManager->expects($this->once())
+ ->method('isTokenValid')
+ ->will($this->returnValue(true));
+
+ $successHandler->expects($this->once())
+ ->method('onLogoutSuccess')
+ ->with($request)
+ ->will($this->returnValue($response = new Response()));
+
+ $context->expects($this->once())
+ ->method('getToken')
+ ->will($this->returnValue($token = $this->getToken()));
+
+ $handler = $this->getHandler();
+ $handler->expects($this->once())
+ ->method('logout')
+ ->with($request, $response, $token);
+
+ $context->expects($this->once())
+ ->method('setToken')
+ ->with(null);
+
+ $event->expects($this->once())
+ ->method('setResponse')
+ ->with($response);
+
+ $listener->addHandler($handler);
+
+ $listener->handle($event);
+ }
+
+ public function testHandleMatchedPathWithoutSuccessHandlerAndCsrfValidation()
+ {
+ $successHandler = $this->getSuccessHandler();
+
+ list($listener, $context, $httpUtils, $options) = $this->getListener($successHandler);
+
+ list($event, $request) = $this->getGetResponseEvent();
+
+ $httpUtils->expects($this->once())
+ ->method('checkRequestPath')
+ ->with($request, $options['logout_path'])
+ ->will($this->returnValue(true));
+
+ $successHandler->expects($this->once())
+ ->method('onLogoutSuccess')
+ ->with($request)
+ ->will($this->returnValue($response = new Response()));
+
+ $context->expects($this->once())
+ ->method('getToken')
+ ->will($this->returnValue($token = $this->getToken()));
+
+ $handler = $this->getHandler();
+ $handler->expects($this->once())
+ ->method('logout')
+ ->with($request, $response, $token);
+
+ $context->expects($this->once())
+ ->method('setToken')
+ ->with(null);
+
+ $event->expects($this->once())
+ ->method('setResponse')
+ ->with($response);
+
+ $listener->addHandler($handler);
+
+ $listener->handle($event);
+ }
+
+ /**
+ * @expectedException \RuntimeException
+ */
+ public function testSuccessHandlerReturnsNonResponse()
+ {
+ $successHandler = $this->getSuccessHandler();
+
+ list($listener, $context, $httpUtils, $options) = $this->getListener($successHandler);
+
+ list($event, $request) = $this->getGetResponseEvent();
+
+ $httpUtils->expects($this->once())
+ ->method('checkRequestPath')
+ ->with($request, $options['logout_path'])
+ ->will($this->returnValue(true));
+
+ $successHandler->expects($this->once())
+ ->method('onLogoutSuccess')
+ ->with($request)
+ ->will($this->returnValue(null));
+
+ $listener->handle($event);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Security\Core\Exception\LogoutException
+ */
+ public function testCsrfValidationFails()
+ {
+ $tokenManager = $this->getTokenManager();
+
+ list($listener, $context, $httpUtils, $options) = $this->getListener(null, $tokenManager);
+
+ list($event, $request) = $this->getGetResponseEvent();
+
+ $request->query->set('_csrf_token', 'token');
+
+ $httpUtils->expects($this->once())
+ ->method('checkRequestPath')
+ ->with($request, $options['logout_path'])
+ ->will($this->returnValue(true));
+
+ $tokenManager->expects($this->once())
+ ->method('isTokenValid')
+ ->will($this->returnValue(false));
+
+ $listener->handle($event);
+ }
+
+ private function getTokenManager()
+ {
+ return $this->getMock('Symfony\Component\Security\Csrf\CsrfTokenManagerInterface');
+ }
+
+ private function getContext()
+ {
+ return $this->getMockBuilder('Symfony\Component\Security\Core\SecurityContext')
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+ private function getGetResponseEvent()
+ {
+ $event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $event->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request = new Request()));
+
+ return array($event, $request);
+ }
+
+ private function getHandler()
+ {
+ return $this->getMock('Symfony\Component\Security\Http\Logout\LogoutHandlerInterface');
+ }
+
+ private function getHttpUtils()
+ {
+ return $this->getMockBuilder('Symfony\Component\Security\Http\HttpUtils')
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+ private function getListener($successHandler = null, $tokenManager = null)
+ {
+ $listener = new LogoutListener(
+ $context = $this->getContext(),
+ $httpUtils = $this->getHttpUtils(),
+ $successHandler ?: $this->getSuccessHandler(),
+ $options = array(
+ 'csrf_parameter' => '_csrf_token',
+ 'intention' => 'logout',
+ 'logout_path' => '/logout',
+ 'target_url' => '/',
+ ),
+ $tokenManager
+ );
+
+ return array($listener, $context, $httpUtils, $options);
+ }
+
+ private function getSuccessHandler()
+ {
+ return $this->getMock('Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface');
+ }
+
+ private function getToken()
+ {
+ return $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ }
+}
diff --git a/Http/Tests/Firewall/RememberMeListenerTest.php b/Http/Tests/Firewall/RememberMeListenerTest.php
new file mode 100644
index 0000000..99d7fcc
--- /dev/null
+++ b/Http/Tests/Firewall/RememberMeListenerTest.php
@@ -0,0 +1,184 @@
+<?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\Tests\Firewall;
+
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Http\Firewall\RememberMeListener;
+use Symfony\Component\HttpFoundation\Request;
+
+class RememberMeListenerTest extends \PHPUnit_Framework_TestCase
+{
+ public function testOnCoreSecurityDoesNotTryToPopulateNonEmptySecurityContext()
+ {
+ list($listener, $context, $service, ,) = $this->getListener();
+
+ $context
+ ->expects($this->once())
+ ->method('getToken')
+ ->will($this->returnValue($this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')))
+ ;
+
+ $context
+ ->expects($this->never())
+ ->method('setToken')
+ ;
+
+ $this->assertNull($listener->handle($this->getGetResponseEvent()));
+ }
+
+ public function testOnCoreSecurityDoesNothingWhenNoCookieIsSet()
+ {
+ list($listener, $context, $service, ,) = $this->getListener();
+
+ $context
+ ->expects($this->once())
+ ->method('getToken')
+ ->will($this->returnValue(null))
+ ;
+
+ $service
+ ->expects($this->once())
+ ->method('autoLogin')
+ ->will($this->returnValue(null))
+ ;
+
+ $event = $this->getGetResponseEvent();
+ $event
+ ->expects($this->once())
+ ->method('getRequest')
+ ->will($this->returnValue(new Request()))
+ ;
+
+ $this->assertNull($listener->handle($event));
+ }
+
+ public function testOnCoreSecurityIgnoresAuthenticationExceptionThrownByAuthenticationManagerImplementation()
+ {
+ list($listener, $context, $service, $manager,) = $this->getListener();
+
+ $context
+ ->expects($this->once())
+ ->method('getToken')
+ ->will($this->returnValue(null))
+ ;
+
+ $service
+ ->expects($this->once())
+ ->method('autoLogin')
+ ->will($this->returnValue($this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')))
+ ;
+
+ $service
+ ->expects($this->once())
+ ->method('loginFail')
+ ;
+
+ $exception = new AuthenticationException('Authentication failed.');
+ $manager
+ ->expects($this->once())
+ ->method('authenticate')
+ ->will($this->throwException($exception))
+ ;
+
+ $event = $this->getGetResponseEvent();
+ $event
+ ->expects($this->once())
+ ->method('getRequest')
+ ->will($this->returnValue(new Request()))
+ ;
+
+ $listener->handle($event);
+ }
+
+ public function testOnCoreSecurity()
+ {
+ list($listener, $context, $service, $manager,) = $this->getListener();
+
+ $context
+ ->expects($this->once())
+ ->method('getToken')
+ ->will($this->returnValue(null))
+ ;
+
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ $service
+ ->expects($this->once())
+ ->method('autoLogin')
+ ->will($this->returnValue($token))
+ ;
+
+ $context
+ ->expects($this->once())
+ ->method('setToken')
+ ->with($this->equalTo($token))
+ ;
+
+ $manager
+ ->expects($this->once())
+ ->method('authenticate')
+ ->will($this->returnValue($token))
+ ;
+
+ $event = $this->getGetResponseEvent();
+ $event
+ ->expects($this->once())
+ ->method('getRequest')
+ ->will($this->returnValue(new Request()))
+ ;
+
+ $listener->handle($event);
+ }
+
+ protected function getGetResponseEvent()
+ {
+ return $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
+ }
+
+ protected function getFilterResponseEvent()
+ {
+ return $this->getMock('Symfony\Component\HttpKernel\Event\FilterResponseEvent', array(), array(), '', false);
+ }
+
+ protected function getListener()
+ {
+ $listener = new RememberMeListener(
+ $context = $this->getContext(),
+ $service = $this->getService(),
+ $manager = $this->getManager(),
+ $logger = $this->getLogger()
+ );
+
+ return array($listener, $context, $service, $manager, $logger);
+ }
+
+ protected function getLogger()
+ {
+ return $this->getMock('Psr\Log\LoggerInterface');
+ }
+
+ protected function getManager()
+ {
+ return $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
+ }
+
+ protected function getService()
+ {
+ return $this->getMock('Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface');
+ }
+
+ protected function getContext()
+ {
+ return $this->getMockBuilder('Symfony\Component\Security\Core\SecurityContext')
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+}
diff --git a/Http/Tests/Firewall/SwitchUserListenerTest.php b/Http/Tests/Firewall/SwitchUserListenerTest.php
new file mode 100644
index 0000000..9fb4e50
--- /dev/null
+++ b/Http/Tests/Firewall/SwitchUserListenerTest.php
@@ -0,0 +1,202 @@
+<?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\Tests\Firewall;
+
+use Symfony\Component\Security\Http\Firewall\SwitchUserListener;
+
+class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase
+{
+ private $securityContext;
+
+ private $userProvider;
+
+ private $userChecker;
+
+ private $accessDecisionManager;
+
+ private $request;
+
+ private $event;
+
+ protected function setUp()
+ {
+ $this->securityContext = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+ $this->userProvider = $this->getMock('Symfony\Component\Security\Core\User\UserProviderInterface');
+ $this->userChecker = $this->getMock('Symfony\Component\Security\Core\User\UserCheckerInterface');
+ $this->accessDecisionManager = $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface');
+ $this->request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+ $this->request->query = $this->getMock('Symfony\Component\HttpFoundation\ParameterBag');
+ $this->request->server = $this->getMock('Symfony\Component\HttpFoundation\ServerBag');
+ $this->event = $this->getEvent($this->request);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage $providerKey must not be empty
+ */
+ public function testProviderKeyIsRequired()
+ {
+ new SwitchUserListener($this->securityContext, $this->userProvider, $this->userChecker, '', $this->accessDecisionManager);
+ }
+
+ public function testEventIsIgnoredIfUsernameIsNotPassedWithTheRequest()
+ {
+ $this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue(null));
+
+ $this->event->expects($this->never())->method('setResponse');
+ $this->securityContext->expects($this->never())->method('setToken');
+
+ $listener = new SwitchUserListener($this->securityContext, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager);
+ $listener->handle($this->event);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException
+ */
+ public function testExitUserThrowsAuthenticationExceptionIfOriginalTokenCannotBeFound()
+ {
+ $token = $this->getToken(array($this->getMock('Symfony\Component\Security\Core\Role\RoleInterface')));
+
+ $this->securityContext->expects($this->any())->method('getToken')->will($this->returnValue($token));
+ $this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('_exit'));
+
+ $listener = new SwitchUserListener($this->securityContext, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager);
+ $listener->handle($this->event);
+ }
+
+ public function testExitUserUpdatesToken()
+ {
+ $originalToken = $this->getToken();
+ $role = $this->getMockBuilder('Symfony\Component\Security\Core\Role\SwitchUserRole')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $role->expects($this->any())->method('getSource')->will($this->returnValue($originalToken));
+
+ $this->securityContext->expects($this->any())
+ ->method('getToken')
+ ->will($this->returnValue($this->getToken(array($role))));
+
+ $this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('_exit'));
+ $this->request->expects($this->any())->method('getUri')->will($this->returnValue('/'));
+ $this->request->query->expects($this->once())->method('remove', '_switch_user');
+ $this->request->query->expects($this->any())->method('all')->will($this->returnValue(array()));
+ $this->request->server->expects($this->once())->method('set')->with('QUERY_STRING', '');
+
+ $this->securityContext->expects($this->once())
+ ->method('setToken')->with($originalToken);
+ $this->event->expects($this->once())
+ ->method('setResponse')->with($this->isInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse'));
+
+ $listener = new SwitchUserListener($this->securityContext, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager);
+ $listener->handle($this->event);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Security\Core\Exception\AccessDeniedException
+ */
+ public function testSwitchUserIsDisallowed()
+ {
+ $token = $this->getToken(array($this->getMock('Symfony\Component\Security\Core\Role\RoleInterface')));
+
+ $this->securityContext->expects($this->any())->method('getToken')->will($this->returnValue($token));
+ $this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('kuba'));
+
+ $this->accessDecisionManager->expects($this->once())
+ ->method('decide')->with($token, array('ROLE_ALLOWED_TO_SWITCH'))
+ ->will($this->returnValue(false));
+
+ $listener = new SwitchUserListener($this->securityContext, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager);
+ $listener->handle($this->event);
+ }
+
+ public function testSwitchUser()
+ {
+ $token = $this->getToken(array($this->getMock('Symfony\Component\Security\Core\Role\RoleInterface')));
+ $user = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $user->expects($this->any())->method('getRoles')->will($this->returnValue(array()));
+
+ $this->securityContext->expects($this->any())->method('getToken')->will($this->returnValue($token));
+ $this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('kuba'));
+ $this->request->query->expects($this->once())->method('remove', '_switch_user');
+ $this->request->query->expects($this->any())->method('all')->will($this->returnValue(array()));
+
+ $this->request->expects($this->any())->method('getUri')->will($this->returnValue('/'));
+ $this->request->server->expects($this->once())->method('set')->with('QUERY_STRING', '');
+
+ $this->accessDecisionManager->expects($this->once())
+ ->method('decide')->with($token, array('ROLE_ALLOWED_TO_SWITCH'))
+ ->will($this->returnValue(true));
+
+ $this->userProvider->expects($this->once())
+ ->method('loadUserByUsername')->with('kuba')
+ ->will($this->returnValue($user));
+ $this->userChecker->expects($this->once())
+ ->method('checkPostAuth')->with($user);
+ $this->securityContext->expects($this->once())
+ ->method('setToken')->with($this->isInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken'));
+
+ $listener = new SwitchUserListener($this->securityContext, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager);
+ $listener->handle($this->event);
+ }
+
+ public function testSwitchUserKeepsOtherQueryStringParameters()
+ {
+ $token = $this->getToken(array($this->getMock('Symfony\Component\Security\Core\Role\RoleInterface')));
+ $user = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $user->expects($this->any())->method('getRoles')->will($this->returnValue(array()));
+
+ $this->securityContext->expects($this->any())->method('getToken')->will($this->returnValue($token));
+ $this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('kuba'));
+ $this->request->query->expects($this->once())->method('remove', '_switch_user');
+ $this->request->query->expects($this->any())->method('all')->will($this->returnValue(array('page' => 3, 'section' => 2)));
+ $this->request->expects($this->any())->method('getUri')->will($this->returnValue('/'));
+ $this->request->server->expects($this->once())->method('set')->with('QUERY_STRING', 'page=3&section=2');
+
+ $this->accessDecisionManager->expects($this->once())
+ ->method('decide')->with($token, array('ROLE_ALLOWED_TO_SWITCH'))
+ ->will($this->returnValue(true));
+
+ $this->userProvider->expects($this->once())
+ ->method('loadUserByUsername')->with('kuba')
+ ->will($this->returnValue($user));
+ $this->userChecker->expects($this->once())
+ ->method('checkPostAuth')->with($user);
+ $this->securityContext->expects($this->once())
+ ->method('setToken')->with($this->isInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken'));
+
+ $listener = new SwitchUserListener($this->securityContext, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager);
+ $listener->handle($this->event);
+ }
+
+ private function getEvent($request)
+ {
+ $event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $event->expects($this->any())
+ ->method('getRequest')
+ ->will($this->returnValue($request));
+
+ return $event;
+ }
+
+ private function getToken(array $roles = array())
+ {
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ $token->expects($this->any())
+ ->method('getRoles')
+ ->will($this->returnValue($roles));
+
+ return $token;
+ }
+}
diff --git a/Http/Tests/Firewall/X509AuthenticationListenerTest.php b/Http/Tests/Firewall/X509AuthenticationListenerTest.php
new file mode 100644
index 0000000..7f2da3e
--- /dev/null
+++ b/Http/Tests/Firewall/X509AuthenticationListenerTest.php
@@ -0,0 +1,123 @@
+<?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\Tests\Firewall;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Security\Http\Firewall\X509AuthenticationListener;
+
+class X509AuthenticationListenerTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider dataProviderGetPreAuthenticatedData
+ */
+ public function testGetPreAuthenticatedData($user, $credentials)
+ {
+ $serverVars = array();
+ if ('' !== $user) {
+ $serverVars['SSL_CLIENT_S_DN_Email'] = $user;
+ }
+ if ('' !== $credentials) {
+ $serverVars['SSL_CLIENT_S_DN'] = $credentials;
+ }
+
+ $request = new Request(array(), array(), array(), array(), array(), $serverVars);
+
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+
+ $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
+
+ $listener = new X509AuthenticationListener($context, $authenticationManager, 'TheProviderKey');
+
+ $method = new \ReflectionMethod($listener, 'getPreAuthenticatedData');
+ $method->setAccessible(true);
+
+ $result = $method->invokeArgs($listener, array($request));
+ $this->assertSame($result, array($user, $credentials));
+ }
+
+ public static function dataProviderGetPreAuthenticatedData()
+ {
+ return array(
+ 'validValues' => array('TheUser', 'TheCredentials'),
+ 'noCredentials' => array('TheUser', ''),
+ );
+ }
+
+ /**
+ * @dataProvider dataProviderGetPreAuthenticatedDataNoUser
+ */
+ public function testGetPreAuthenticatedDataNoUser($emailAddress)
+ {
+ $credentials = 'CN=Sample certificate DN/emailAddress='.$emailAddress;
+ $request = new Request(array(), array(), array(), array(), array(), array('SSL_CLIENT_S_DN' => $credentials));
+
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+
+ $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
+
+ $listener = new X509AuthenticationListener($context, $authenticationManager, 'TheProviderKey');
+
+ $method = new \ReflectionMethod($listener, 'getPreAuthenticatedData');
+ $method->setAccessible(true);
+
+ $result = $method->invokeArgs($listener, array($request));
+ $this->assertSame($result, array($emailAddress, $credentials));
+ }
+
+ public static function dataProviderGetPreAuthenticatedDataNoUser()
+ {
+ return array(
+ 'basicEmailAddress' => array('cert@example.com'),
+ 'emailAddressWithPlusSign' => array('cert+something@example.com'),
+ );
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
+ */
+ public function testGetPreAuthenticatedDataNoData()
+ {
+ $request = new Request(array(), array(), array(), array(), array(), array());
+
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+
+ $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
+
+ $listener = new X509AuthenticationListener($context, $authenticationManager, 'TheProviderKey');
+
+ $method = new \ReflectionMethod($listener, 'getPreAuthenticatedData');
+ $method->setAccessible(true);
+
+ $result = $method->invokeArgs($listener, array($request));
+ }
+
+ public function testGetPreAuthenticatedDataWithDifferentKeys()
+ {
+ $userCredentials = array('TheUser', 'TheCredentials');
+
+ $request = new Request(array(), array(), array(), array(), array(), array(
+ 'TheUserKey' => 'TheUser',
+ 'TheCredentialsKey' => 'TheCredentials',
+ ));
+ $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
+
+ $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
+
+ $listener = new X509AuthenticationListener($context, $authenticationManager, 'TheProviderKey', 'TheUserKey', 'TheCredentialsKey');
+
+ $method = new \ReflectionMethod($listener, 'getPreAuthenticatedData');
+ $method->setAccessible(true);
+
+ $result = $method->invokeArgs($listener, array($request));
+ $this->assertSame($result, $userCredentials);
+ }
+}
diff --git a/Http/Tests/FirewallMapTest.php b/Http/Tests/FirewallMapTest.php
new file mode 100644
index 0000000..85a57ab
--- /dev/null
+++ b/Http/Tests/FirewallMapTest.php
@@ -0,0 +1,117 @@
+<?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\Tests;
+
+use Symfony\Component\Security\Http\FirewallMap;
+use Symfony\Component\HttpFoundation\Request;
+
+class FirewallMapTest extends \PHPUnit_Framework_TestCase
+{
+ public function testGetListeners()
+ {
+ $map = new FirewallMap();
+
+ $request = new Request();
+
+ $notMatchingMatcher = $this->getMock('Symfony\Component\HttpFoundation\RequestMatcher');
+ $notMatchingMatcher
+ ->expects($this->once())
+ ->method('matches')
+ ->with($this->equalTo($request))
+ ->will($this->returnValue(false))
+ ;
+
+ $map->add($notMatchingMatcher, array($this->getMock('Symfony\Component\Security\Http\Firewall\ListenerInterface')));
+
+ $matchingMatcher = $this->getMock('Symfony\Component\HttpFoundation\RequestMatcher');
+ $matchingMatcher
+ ->expects($this->once())
+ ->method('matches')
+ ->with($this->equalTo($request))
+ ->will($this->returnValue(true))
+ ;
+ $theListener = $this->getMock('Symfony\Component\Security\Http\Firewall\ListenerInterface');
+ $theException = $this->getMock('Symfony\Component\Security\Http\Firewall\ExceptionListener', array(), array(), '', false);
+
+ $map->add($matchingMatcher, array($theListener), $theException);
+
+ $tooLateMatcher = $this->getMock('Symfony\Component\HttpFoundation\RequestMatcher');
+ $tooLateMatcher
+ ->expects($this->never())
+ ->method('matches')
+ ;
+
+ $map->add($tooLateMatcher, array($this->getMock('Symfony\Component\Security\Http\Firewall\ListenerInterface')));
+
+ list($listeners, $exception) = $map->getListeners($request);
+
+ $this->assertEquals(array($theListener), $listeners);
+ $this->assertEquals($theException, $exception);
+ }
+
+ public function testGetListenersWithAnEntryHavingNoRequestMatcher()
+ {
+ $map = new FirewallMap();
+
+ $request = new Request();
+
+ $notMatchingMatcher = $this->getMock('Symfony\Component\HttpFoundation\RequestMatcher');
+ $notMatchingMatcher
+ ->expects($this->once())
+ ->method('matches')
+ ->with($this->equalTo($request))
+ ->will($this->returnValue(false))
+ ;
+
+ $map->add($notMatchingMatcher, array($this->getMock('Symfony\Component\Security\Http\Firewall\ListenerInterface')));
+
+ $theListener = $this->getMock('Symfony\Component\Security\Http\Firewall\ListenerInterface');
+ $theException = $this->getMock('Symfony\Component\Security\Http\Firewall\ExceptionListener', array(), array(), '', false);
+
+ $map->add(null, array($theListener), $theException);
+
+ $tooLateMatcher = $this->getMock('Symfony\Component\HttpFoundation\RequestMatcher');
+ $tooLateMatcher
+ ->expects($this->never())
+ ->method('matches')
+ ;
+
+ $map->add($tooLateMatcher, array($this->getMock('Symfony\Component\Security\Http\Firewall\ListenerInterface')));
+
+ list($listeners, $exception) = $map->getListeners($request);
+
+ $this->assertEquals(array($theListener), $listeners);
+ $this->assertEquals($theException, $exception);
+ }
+
+ public function testGetListenersWithNoMatchingEntry()
+ {
+ $map = new FirewallMap();
+
+ $request = new Request();
+
+ $notMatchingMatcher = $this->getMock('Symfony\Component\HttpFoundation\RequestMatcher');
+ $notMatchingMatcher
+ ->expects($this->once())
+ ->method('matches')
+ ->with($this->equalTo($request))
+ ->will($this->returnValue(false))
+ ;
+
+ $map->add($notMatchingMatcher, array($this->getMock('Symfony\Component\Security\Http\Firewall\ListenerInterface')));
+
+ list($listeners, $exception) = $map->getListeners($request);
+
+ $this->assertEquals(array(), $listeners);
+ $this->assertNull($exception);
+ }
+}
diff --git a/Http/Tests/FirewallTest.php b/Http/Tests/FirewallTest.php
new file mode 100644
index 0000000..9994737
--- /dev/null
+++ b/Http/Tests/FirewallTest.php
@@ -0,0 +1,108 @@
+<?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\Tests;
+
+use Symfony\Component\Security\Http\Firewall;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
+class FirewallTest extends \PHPUnit_Framework_TestCase
+{
+ public function testOnKernelRequestRegistersExceptionListener()
+ {
+ $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
+
+ $listener = $this->getMock('Symfony\Component\Security\Http\Firewall\ExceptionListener', array(), array(), '', false);
+ $listener
+ ->expects($this->once())
+ ->method('register')
+ ->with($this->equalTo($dispatcher))
+ ;
+
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request', array(), array(), '', false, false);
+
+ $map = $this->getMock('Symfony\Component\Security\Http\FirewallMapInterface');
+ $map
+ ->expects($this->once())
+ ->method('getListeners')
+ ->with($this->equalTo($request))
+ ->will($this->returnValue(array(array(), $listener)))
+ ;
+
+ $event = new GetResponseEvent($this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'), $request, HttpKernelInterface::MASTER_REQUEST);
+
+ $firewall = new Firewall($map, $dispatcher);
+ $firewall->onKernelRequest($event);
+ }
+
+ public function testOnKernelRequestStopsWhenThereIsAResponse()
+ {
+ $response = $this->getMock('Symfony\Component\HttpFoundation\Response');
+
+ $first = $this->getMock('Symfony\Component\Security\Http\Firewall\ListenerInterface');
+ $first
+ ->expects($this->once())
+ ->method('handle')
+ ;
+
+ $second = $this->getMock('Symfony\Component\Security\Http\Firewall\ListenerInterface');
+ $second
+ ->expects($this->never())
+ ->method('handle')
+ ;
+
+ $map = $this->getMock('Symfony\Component\Security\Http\FirewallMapInterface');
+ $map
+ ->expects($this->once())
+ ->method('getListeners')
+ ->will($this->returnValue(array(array($first, $second), null)))
+ ;
+
+ $event = $this->getMock(
+ 'Symfony\Component\HttpKernel\Event\GetResponseEvent',
+ array('hasResponse'),
+ array(
+ $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'),
+ $this->getMock('Symfony\Component\HttpFoundation\Request', array(), array(), '', false, false),
+ HttpKernelInterface::MASTER_REQUEST,
+ )
+ );
+ $event
+ ->expects($this->once())
+ ->method('hasResponse')
+ ->will($this->returnValue(true))
+ ;
+
+ $firewall = new Firewall($map, $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'));
+ $firewall->onKernelRequest($event);
+ }
+
+ public function testOnKernelRequestWithSubRequest()
+ {
+ $map = $this->getMock('Symfony\Component\Security\Http\FirewallMapInterface');
+ $map
+ ->expects($this->never())
+ ->method('getListeners')
+ ;
+
+ $event = new GetResponseEvent(
+ $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'),
+ $this->getMock('Symfony\Component\HttpFoundation\Request'),
+ HttpKernelInterface::SUB_REQUEST
+ );
+
+ $firewall = new Firewall($map, $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'));
+ $firewall->onKernelRequest($event);
+
+ $this->assertFalse($event->hasResponse());
+ }
+}
diff --git a/Http/Tests/HttpUtilsTest.php b/Http/Tests/HttpUtilsTest.php
new file mode 100644
index 0000000..5cac504
--- /dev/null
+++ b/Http/Tests/HttpUtilsTest.php
@@ -0,0 +1,266 @@
+<?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\Tests;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Exception\MethodNotAllowedException;
+use Symfony\Component\Routing\Exception\ResourceNotFoundException;
+use Symfony\Component\Security\Core\SecurityContextInterface;
+use Symfony\Component\Security\Http\HttpUtils;
+
+class HttpUtilsTest extends \PHPUnit_Framework_TestCase
+{
+ public function testCreateRedirectResponseWithPath()
+ {
+ $utils = new HttpUtils($this->getUrlGenerator());
+ $response = $utils->createRedirectResponse($this->getRequest(), '/foobar');
+
+ $this->assertTrue($response->isRedirect('http://localhost/foobar'));
+ $this->assertEquals(302, $response->getStatusCode());
+ }
+
+ public function testCreateRedirectResponseWithAbsoluteUrl()
+ {
+ $utils = new HttpUtils($this->getUrlGenerator());
+ $response = $utils->createRedirectResponse($this->getRequest(), 'http://symfony.com/');
+
+ $this->assertTrue($response->isRedirect('http://symfony.com/'));
+ }
+
+ public function testCreateRedirectResponseWithRouteName()
+ {
+ $utils = new HttpUtils($urlGenerator = $this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface'));
+
+ $urlGenerator
+ ->expects($this->any())
+ ->method('generate')
+ ->with('foobar', array(), true)
+ ->will($this->returnValue('http://localhost/foo/bar'))
+ ;
+ $urlGenerator
+ ->expects($this->any())
+ ->method('getContext')
+ ->will($this->returnValue($this->getMock('Symfony\Component\Routing\RequestContext')))
+ ;
+
+ $response = $utils->createRedirectResponse($this->getRequest(), 'foobar');
+
+ $this->assertTrue($response->isRedirect('http://localhost/foo/bar'));
+ }
+
+ public function testCreateRequestWithPath()
+ {
+ $request = $this->getRequest();
+ $request->server->set('Foo', 'bar');
+
+ $utils = new HttpUtils($this->getUrlGenerator());
+ $subRequest = $utils->createRequest($request, '/foobar');
+
+ $this->assertEquals('GET', $subRequest->getMethod());
+ $this->assertEquals('/foobar', $subRequest->getPathInfo());
+ $this->assertEquals('bar', $subRequest->server->get('Foo'));
+ }
+
+ public function testCreateRequestWithRouteName()
+ {
+ $utils = new HttpUtils($urlGenerator = $this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface'));
+
+ $urlGenerator
+ ->expects($this->once())
+ ->method('generate')
+ ->will($this->returnValue('/foo/bar'))
+ ;
+ $urlGenerator
+ ->expects($this->any())
+ ->method('getContext')
+ ->will($this->returnValue($this->getMock('Symfony\Component\Routing\RequestContext')))
+ ;
+
+ $subRequest = $utils->createRequest($this->getRequest(), 'foobar');
+
+ $this->assertEquals('/foo/bar', $subRequest->getPathInfo());
+ }
+
+ public function testCreateRequestWithAbsoluteUrl()
+ {
+ $utils = new HttpUtils($this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface'));
+ $subRequest = $utils->createRequest($this->getRequest(), 'http://symfony.com/');
+
+ $this->assertEquals('/', $subRequest->getPathInfo());
+ }
+
+ public function testCreateRequestPassesSessionToTheNewRequest()
+ {
+ $request = $this->getRequest();
+ $request->setSession($session = $this->getMock('Symfony\Component\HttpFoundation\Session\SessionInterface'));
+
+ $utils = new HttpUtils($this->getUrlGenerator());
+ $subRequest = $utils->createRequest($request, '/foobar');
+
+ $this->assertSame($session, $subRequest->getSession());
+ }
+
+ /**
+ * @dataProvider provideSecurityContextAttributes
+ */
+ public function testCreateRequestPassesSecurityContextAttributesToTheNewRequest($attribute)
+ {
+ $request = $this->getRequest();
+ $request->attributes->set($attribute, 'foo');
+
+ $utils = new HttpUtils($this->getUrlGenerator());
+ $subRequest = $utils->createRequest($request, '/foobar');
+
+ $this->assertSame('foo', $subRequest->attributes->get($attribute));
+ }
+
+ public function provideSecurityContextAttributes()
+ {
+ return array(
+ array(SecurityContextInterface::AUTHENTICATION_ERROR),
+ array(SecurityContextInterface::ACCESS_DENIED_ERROR),
+ array(SecurityContextInterface::LAST_USERNAME),
+ );
+ }
+
+ public function testCheckRequestPath()
+ {
+ $utils = new HttpUtils($this->getUrlGenerator());
+
+ $this->assertTrue($utils->checkRequestPath($this->getRequest(), '/'));
+ $this->assertFalse($utils->checkRequestPath($this->getRequest(), '/foo'));
+ $this->assertTrue($utils->checkRequestPath($this->getRequest('/foo%20bar'), '/foo bar'));
+ // Plus must not decoded to space
+ $this->assertTrue($utils->checkRequestPath($this->getRequest('/foo+bar'), '/foo+bar'));
+ // Checking unicode
+ $this->assertTrue($utils->checkRequestPath($this->getRequest(urlencode('/вход')), '/вход'));
+ }
+
+ public function testCheckRequestPathWithUrlMatcherAndResourceNotFound()
+ {
+ $urlMatcher = $this->getMock('Symfony\Component\Routing\Matcher\UrlMatcherInterface');
+ $urlMatcher
+ ->expects($this->any())
+ ->method('match')
+ ->with('/')
+ ->will($this->throwException(new ResourceNotFoundException()))
+ ;
+
+ $utils = new HttpUtils(null, $urlMatcher);
+ $this->assertFalse($utils->checkRequestPath($this->getRequest(), 'foobar'));
+ }
+
+ public function testCheckRequestPathWithUrlMatcherAndMethodNotAllowed()
+ {
+ $request = $this->getRequest();
+ $urlMatcher = $this->getMock('Symfony\Component\Routing\Matcher\RequestMatcherInterface');
+ $urlMatcher
+ ->expects($this->any())
+ ->method('matchRequest')
+ ->with($request)
+ ->will($this->throwException(new MethodNotAllowedException(array())))
+ ;
+
+ $utils = new HttpUtils(null, $urlMatcher);
+ $this->assertFalse($utils->checkRequestPath($request, 'foobar'));
+ }
+
+ public function testCheckRequestPathWithUrlMatcherAndResourceFoundByUrl()
+ {
+ $urlMatcher = $this->getMock('Symfony\Component\Routing\Matcher\UrlMatcherInterface');
+ $urlMatcher
+ ->expects($this->any())
+ ->method('match')
+ ->with('/foo/bar')
+ ->will($this->returnValue(array('_route' => 'foobar')))
+ ;
+
+ $utils = new HttpUtils(null, $urlMatcher);
+ $this->assertTrue($utils->checkRequestPath($this->getRequest('/foo/bar'), 'foobar'));
+ }
+
+ public function testCheckRequestPathWithUrlMatcherAndResourceFoundByRequest()
+ {
+ $request = $this->getRequest();
+ $urlMatcher = $this->getMock('Symfony\Component\Routing\Matcher\RequestMatcherInterface');
+ $urlMatcher
+ ->expects($this->any())
+ ->method('matchRequest')
+ ->with($request)
+ ->will($this->returnValue(array('_route' => 'foobar')))
+ ;
+
+ $utils = new HttpUtils(null, $urlMatcher);
+ $this->assertTrue($utils->checkRequestPath($request, 'foobar'));
+ }
+
+ /**
+ * @expectedException \RuntimeException
+ */
+ public function testCheckRequestPathWithUrlMatcherLoadingException()
+ {
+ $urlMatcher = $this->getMock('Symfony\Component\Routing\Matcher\UrlMatcherInterface');
+ $urlMatcher
+ ->expects($this->any())
+ ->method('match')
+ ->will($this->throwException(new \RuntimeException()))
+ ;
+
+ $utils = new HttpUtils(null, $urlMatcher);
+ $utils->checkRequestPath($this->getRequest(), 'foobar');
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Matcher must either implement UrlMatcherInterface or RequestMatcherInterface
+ */
+ public function testUrlMatcher()
+ {
+ new HttpUtils($this->getUrlGenerator(), new \stdClass());
+ }
+
+ public function testGenerateUriRemovesQueryString()
+ {
+ $utils = new HttpUtils($this->getUrlGenerator('/foo/bar'));
+ $this->assertEquals('/foo/bar', $utils->generateUri(new Request(), 'route_name'));
+
+ $utils = new HttpUtils($this->getUrlGenerator('/foo/bar?param=value'));
+ $this->assertEquals('/foo/bar', $utils->generateUri(new Request(), 'route_name'));
+ }
+
+ /**
+ * @expectedException \LogicException
+ * @expectedExceptionMessage You must provide a UrlGeneratorInterface instance to be able to use routes.
+ */
+ public function testUrlGeneratorIsRequiredToGenerateUrl()
+ {
+ $utils = new HttpUtils();
+ $utils->generateUri(new Request(), 'route_name');
+ }
+
+ private function getUrlGenerator($generatedUrl = '/foo/bar')
+ {
+ $urlGenerator = $this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface');
+ $urlGenerator
+ ->expects($this->any())
+ ->method('generate')
+ ->will($this->returnValue($generatedUrl))
+ ;
+
+ return $urlGenerator;
+ }
+
+ private function getRequest($path = '/')
+ {
+ return Request::create($path, 'get');
+ }
+}
diff --git a/Http/Tests/Logout/CookieClearingLogoutHandlerTest.php b/Http/Tests/Logout/CookieClearingLogoutHandlerTest.php
new file mode 100644
index 0000000..8474504
--- /dev/null
+++ b/Http/Tests/Logout/CookieClearingLogoutHandlerTest.php
@@ -0,0 +1,49 @@
+<?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\Tests\Logout;
+
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\ResponseHeaderBag;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Security\Http\Logout\CookieClearingLogoutHandler;
+
+class CookieClearingLogoutHandlerTest extends \PHPUnit_Framework_TestCase
+{
+ public function testLogout()
+ {
+ $request = new Request();
+ $response = new Response();
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+
+ $handler = new CookieClearingLogoutHandler(array('foo' => array('path' => '/foo', 'domain' => 'foo.foo'), 'foo2' => array('path' => null, 'domain' => null)));
+
+ $cookies = $response->headers->getCookies();
+ $this->assertCount(0, $cookies);
+
+ $handler->logout($request, $response, $token);
+
+ $cookies = $response->headers->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
+ $this->assertCount(2, $cookies);
+
+ $cookie = $cookies['foo.foo']['/foo']['foo'];
+ $this->assertEquals('foo', $cookie->getName());
+ $this->assertEquals('/foo', $cookie->getPath());
+ $this->assertEquals('foo.foo', $cookie->getDomain());
+ $this->assertTrue($cookie->isCleared());
+
+ $cookie = $cookies['']['/']['foo2'];
+ $this->assertStringStartsWith('foo2', $cookie->getName());
+ $this->assertEquals('/', $cookie->getPath());
+ $this->assertNull($cookie->getDomain());
+ $this->assertTrue($cookie->isCleared());
+ }
+}
diff --git a/Http/Tests/Logout/DefaultLogoutSuccessHandlerTest.php b/Http/Tests/Logout/DefaultLogoutSuccessHandlerTest.php
new file mode 100644
index 0000000..381a48e
--- /dev/null
+++ b/Http/Tests/Logout/DefaultLogoutSuccessHandlerTest.php
@@ -0,0 +1,34 @@
+<?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\Tests\Logout;
+
+use Symfony\Component\Security\Http\Logout\DefaultLogoutSuccessHandler;
+
+class DefaultLogoutSuccessHandlerTest extends \PHPUnit_Framework_TestCase
+{
+ public function testLogout()
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+ $response = $this->getMock('Symfony\Component\HttpFoundation\Response');
+
+ $httpUtils = $this->getMock('Symfony\Component\Security\Http\HttpUtils');
+ $httpUtils->expects($this->once())
+ ->method('createRedirectResponse')
+ ->with($request, '/dashboard')
+ ->will($this->returnValue($response));
+
+ $handler = new DefaultLogoutSuccessHandler($httpUtils, '/dashboard');
+ $result = $handler->onLogoutSuccess($request);
+
+ $this->assertSame($response, $result);
+ }
+}
diff --git a/Http/Tests/Logout/SessionLogoutHandlerTest.php b/Http/Tests/Logout/SessionLogoutHandlerTest.php
new file mode 100644
index 0000000..c342995
--- /dev/null
+++ b/Http/Tests/Logout/SessionLogoutHandlerTest.php
@@ -0,0 +1,40 @@
+<?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\Tests\Logout;
+
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Security\Http\Logout\SessionLogoutHandler;
+
+class SessionLogoutHandlerTest extends \PHPUnit_Framework_TestCase
+{
+ public function testLogout()
+ {
+ $handler = new SessionLogoutHandler();
+
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+ $response = new Response();
+ $session = $this->getMock('Symfony\Component\HttpFoundation\Session\Session', array(), array(), '', false);
+
+ $request
+ ->expects($this->once())
+ ->method('getSession')
+ ->will($this->returnValue($session))
+ ;
+
+ $session
+ ->expects($this->once())
+ ->method('invalidate')
+ ;
+
+ $handler->logout($request, $response, $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'));
+ }
+}
diff --git a/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php b/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php
new file mode 100644
index 0000000..c3d9260
--- /dev/null
+++ b/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php
@@ -0,0 +1,261 @@
+<?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\Tests\RememberMe;
+
+use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+
+class AbstractRememberMeServicesTest extends \PHPUnit_Framework_TestCase
+{
+ public function testGetRememberMeParameter()
+ {
+ $service = $this->getService(null, array('remember_me_parameter' => 'foo'));
+
+ $this->assertEquals('foo', $service->getRememberMeParameter());
+ }
+
+ public function testGetKey()
+ {
+ $service = $this->getService();
+ $this->assertEquals('fookey', $service->getKey());
+ }
+
+ public function testAutoLoginReturnsNullWhenNoCookie()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null));
+
+ $this->assertNull($service->autoLogin(new Request()));
+ }
+
+ /**
+ * @expectedException \RuntimeException
+ */
+ public function testAutoLoginThrowsExceptionWhenImplementationDoesNotReturnUserInterface()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null));
+ $request = new Request();
+ $request->cookies->set('foo', 'foo');
+
+ $service
+ ->expects($this->once())
+ ->method('processAutoLoginCookie')
+ ->will($this->returnValue(null))
+ ;
+
+ $service->autoLogin($request);
+ }
+
+ public function testAutoLogin()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null));
+ $request = new Request();
+ $request->cookies->set('foo', 'foo');
+
+ $user = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $user
+ ->expects($this->once())
+ ->method('getRoles')
+ ->will($this->returnValue(array()))
+ ;
+
+ $service
+ ->expects($this->once())
+ ->method('processAutoLoginCookie')
+ ->will($this->returnValue($user))
+ ;
+
+ $returnedToken = $service->autoLogin($request);
+
+ $this->assertSame($user, $returnedToken->getUser());
+ $this->assertSame('fookey', $returnedToken->getKey());
+ $this->assertSame('fookey', $returnedToken->getProviderKey());
+ }
+
+ public function testLogout()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null));
+ $request = new Request();
+ $response = new Response();
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+
+ $service->logout($request, $response, $token);
+
+ $this->assertTrue($request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME)->isCleared());
+ }
+
+ public function testLoginFail()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null));
+ $request = new Request();
+
+ $service->loginFail($request);
+
+ $this->assertTrue($request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME)->isCleared());
+ }
+
+ public function testLoginSuccessIsNotProcessedWhenTokenDoesNotContainUserInterfaceImplementation()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'always_remember_me' => true, 'path' => null, 'domain' => null));
+ $request = new Request();
+ $response = new Response();
+ $account = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ $token
+ ->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue('foo'))
+ ;
+
+ $service
+ ->expects($this->never())
+ ->method('onLoginSuccess')
+ ;
+
+ $this->assertFalse($request->request->has('foo'));
+
+ $service->loginSuccess($request, $response, $token);
+ }
+
+ public function testLoginSuccessIsNotProcessedWhenRememberMeIsNotRequested()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'always_remember_me' => false, 'remember_me_parameter' => 'foo', 'path' => null, 'domain' => null));
+ $request = new Request();
+ $response = new Response();
+ $account = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ $token
+ ->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($account))
+ ;
+
+ $service
+ ->expects($this->never())
+ ->method('onLoginSuccess')
+ ->will($this->returnValue(null))
+ ;
+
+ $this->assertFalse($request->request->has('foo'));
+
+ $service->loginSuccess($request, $response, $token);
+ }
+
+ public function testLoginSuccessWhenRememberMeAlwaysIsTrue()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'always_remember_me' => true, 'path' => null, 'domain' => null));
+ $request = new Request();
+ $response = new Response();
+ $account = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ $token
+ ->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($account))
+ ;
+
+ $service
+ ->expects($this->once())
+ ->method('onLoginSuccess')
+ ->will($this->returnValue(null))
+ ;
+
+ $service->loginSuccess($request, $response, $token);
+ }
+
+ /**
+ * @dataProvider getPositiveRememberMeParameterValues
+ */
+ public function testLoginSuccessWhenRememberMeParameterWithPathIsPositive($value)
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'always_remember_me' => false, 'remember_me_parameter' => 'foo[bar]', 'path' => null, 'domain' => null));
+
+ $request = new Request();
+ $request->request->set('foo', array('bar' => $value));
+ $response = new Response();
+ $account = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ $token
+ ->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($account))
+ ;
+
+ $service
+ ->expects($this->once())
+ ->method('onLoginSuccess')
+ ->will($this->returnValue(true))
+ ;
+
+ $service->loginSuccess($request, $response, $token);
+ }
+
+ /**
+ * @dataProvider getPositiveRememberMeParameterValues
+ */
+ public function testLoginSuccessWhenRememberMeParameterIsPositive($value)
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'always_remember_me' => false, 'remember_me_parameter' => 'foo', 'path' => null, 'domain' => null));
+
+ $request = new Request();
+ $request->request->set('foo', $value);
+ $response = new Response();
+ $account = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ $token
+ ->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($account))
+ ;
+
+ $service
+ ->expects($this->once())
+ ->method('onLoginSuccess')
+ ->will($this->returnValue(true))
+ ;
+
+ $service->loginSuccess($request, $response, $token);
+ }
+
+ public function getPositiveRememberMeParameterValues()
+ {
+ return array(
+ array('true'),
+ array('1'),
+ array('on'),
+ array('yes'),
+ );
+ }
+
+ protected function getService($userProvider = null, $options = array(), $logger = null)
+ {
+ if (null === $userProvider) {
+ $userProvider = $this->getProvider();
+ }
+
+ return $this->getMockForAbstractClass('Symfony\Component\Security\Http\RememberMe\AbstractRememberMeServices', array(
+ array($userProvider), 'fookey', 'fookey', $options, $logger,
+ ));
+ }
+
+ protected function getProvider()
+ {
+ $provider = $this->getMock('Symfony\Component\Security\Core\User\UserProviderInterface');
+ $provider
+ ->expects($this->any())
+ ->method('supportsClass')
+ ->will($this->returnValue(true))
+ ;
+
+ return $provider;
+ }
+}
diff --git a/Http/Tests/RememberMe/PersistentTokenBasedRememberMeServicesTest.php b/Http/Tests/RememberMe/PersistentTokenBasedRememberMeServicesTest.php
new file mode 100644
index 0000000..6aee1b1
--- /dev/null
+++ b/Http/Tests/RememberMe/PersistentTokenBasedRememberMeServicesTest.php
@@ -0,0 +1,328 @@
+<?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\Tests\RememberMe;
+
+use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
+use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
+use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\ResponseHeaderBag;
+use Symfony\Component\Security\Http\RememberMe\PersistentTokenBasedRememberMeServices;
+use Symfony\Component\Security\Core\Exception\TokenNotFoundException;
+use Symfony\Component\Security\Core\Exception\CookieTheftException;
+use Symfony\Component\Security\Core\Util\SecureRandom;
+
+class PersistentTokenBasedRememberMeServicesTest extends \PHPUnit_Framework_TestCase
+{
+ public function testAutoLoginReturnsNullWhenNoCookie()
+ {
+ $service = $this->getService(null, array('name' => 'foo'));
+
+ $this->assertNull($service->autoLogin(new Request()));
+ }
+
+ public function testAutoLoginThrowsExceptionOnInvalidCookie()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null, 'always_remember_me' => false, 'remember_me_parameter' => 'foo'));
+ $request = new Request();
+ $request->request->set('foo', 'true');
+ $request->cookies->set('foo', 'foo');
+
+ $this->assertNull($service->autoLogin($request));
+ $this->assertTrue($request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME)->isCleared());
+ }
+
+ public function testAutoLoginThrowsExceptionOnNonExistentToken()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null, 'always_remember_me' => false, 'remember_me_parameter' => 'foo'));
+ $request = new Request();
+ $request->request->set('foo', 'true');
+ $request->cookies->set('foo', $this->encodeCookie(array(
+ $series = 'fooseries',
+ $tokenValue = 'foovalue',
+ )));
+
+ $tokenProvider = $this->getMock('Symfony\Component\Security\Core\Authentication\RememberMe\TokenProviderInterface');
+ $tokenProvider
+ ->expects($this->once())
+ ->method('loadTokenBySeries')
+ ->will($this->throwException(new TokenNotFoundException('Token not found.')))
+ ;
+ $service->setTokenProvider($tokenProvider);
+
+ $this->assertNull($service->autoLogin($request));
+ $this->assertTrue($request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME)->isCleared());
+ }
+
+ public function testAutoLoginReturnsNullOnNonExistentUser()
+ {
+ $userProvider = $this->getProvider();
+ $service = $this->getService($userProvider, array('name' => 'foo', 'path' => null, 'domain' => null, 'always_remember_me' => true, 'lifetime' => 3600, 'secure' => false, 'httponly' => false));
+ $request = new Request();
+ $request->cookies->set('foo', $this->encodeCookie(array('fooseries', 'foovalue')));
+
+ $tokenProvider = $this->getMock('Symfony\Component\Security\Core\Authentication\RememberMe\TokenProviderInterface');
+ $tokenProvider
+ ->expects($this->once())
+ ->method('loadTokenBySeries')
+ ->will($this->returnValue(new PersistentToken('fooclass', 'fooname', 'fooseries', 'foovalue', new \DateTime())))
+ ;
+ $service->setTokenProvider($tokenProvider);
+
+ $userProvider
+ ->expects($this->once())
+ ->method('loadUserByUsername')
+ ->will($this->throwException(new UsernameNotFoundException('user not found')))
+ ;
+
+ $this->assertNull($service->autoLogin($request));
+ $this->assertTrue($request->attributes->has(RememberMeServicesInterface::COOKIE_ATTR_NAME));
+ }
+
+ public function testAutoLoginThrowsExceptionOnStolenCookieAndRemovesItFromThePersistentBackend()
+ {
+ $userProvider = $this->getProvider();
+ $service = $this->getService($userProvider, array('name' => 'foo', 'path' => null, 'domain' => null, 'always_remember_me' => true));
+ $request = new Request();
+ $request->cookies->set('foo', $this->encodeCookie(array('fooseries', 'foovalue')));
+
+ $tokenProvider = $this->getMock('Symfony\Component\Security\Core\Authentication\RememberMe\TokenProviderInterface');
+ $service->setTokenProvider($tokenProvider);
+
+ $tokenProvider
+ ->expects($this->once())
+ ->method('loadTokenBySeries')
+ ->will($this->returnValue(new PersistentToken('fooclass', 'foouser', 'fooseries', 'anotherFooValue', new \DateTime())))
+ ;
+
+ $tokenProvider
+ ->expects($this->once())
+ ->method('deleteTokenBySeries')
+ ->with($this->equalTo('fooseries'))
+ ->will($this->returnValue(null))
+ ;
+
+ try {
+ $service->autoLogin($request);
+ $this->fail('Expected CookieTheftException was not thrown.');
+ } catch (CookieTheftException $theft) {
+ }
+
+ $this->assertTrue($request->attributes->has(RememberMeServicesInterface::COOKIE_ATTR_NAME));
+ }
+
+ public function testAutoLoginDoesNotAcceptAnExpiredCookie()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null, 'always_remember_me' => true, 'lifetime' => 3600));
+ $request = new Request();
+ $request->cookies->set('foo', $this->encodeCookie(array('fooseries', 'foovalue')));
+
+ $tokenProvider = $this->getMock('Symfony\Component\Security\Core\Authentication\RememberMe\TokenProviderInterface');
+ $tokenProvider
+ ->expects($this->once())
+ ->method('loadTokenBySeries')
+ ->with($this->equalTo('fooseries'))
+ ->will($this->returnValue(new PersistentToken('fooclass', 'username', 'fooseries', 'foovalue', new \DateTime('yesterday'))))
+ ;
+ $service->setTokenProvider($tokenProvider);
+
+ $this->assertNull($service->autoLogin($request));
+ $this->assertTrue($request->attributes->has(RememberMeServicesInterface::COOKIE_ATTR_NAME));
+ }
+
+ public function testAutoLogin()
+ {
+ $user = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $user
+ ->expects($this->once())
+ ->method('getRoles')
+ ->will($this->returnValue(array('ROLE_FOO')))
+ ;
+
+ $userProvider = $this->getProvider();
+ $userProvider
+ ->expects($this->once())
+ ->method('loadUserByUsername')
+ ->with($this->equalTo('foouser'))
+ ->will($this->returnValue($user))
+ ;
+
+ $service = $this->getService($userProvider, array('name' => 'foo', 'path' => null, 'domain' => null, 'secure' => false, 'httponly' => false, 'always_remember_me' => true, 'lifetime' => 3600));
+ $request = new Request();
+ $request->cookies->set('foo', $this->encodeCookie(array('fooseries', 'foovalue')));
+
+ $tokenProvider = $this->getMock('Symfony\Component\Security\Core\Authentication\RememberMe\TokenProviderInterface');
+ $tokenProvider
+ ->expects($this->once())
+ ->method('loadTokenBySeries')
+ ->with($this->equalTo('fooseries'))
+ ->will($this->returnValue(new PersistentToken('fooclass', 'foouser', 'fooseries', 'foovalue', new \DateTime())))
+ ;
+ $service->setTokenProvider($tokenProvider);
+
+ $returnedToken = $service->autoLogin($request);
+
+ $this->assertInstanceOf('Symfony\Component\Security\Core\Authentication\Token\RememberMeToken', $returnedToken);
+ $this->assertSame($user, $returnedToken->getUser());
+ $this->assertEquals('fookey', $returnedToken->getKey());
+ $this->assertTrue($request->attributes->has(RememberMeServicesInterface::COOKIE_ATTR_NAME));
+ }
+
+ public function testLogout()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'path' => '/foo', 'domain' => 'foodomain.foo'));
+ $request = new Request();
+ $request->cookies->set('foo', $this->encodeCookie(array('fooseries', 'foovalue')));
+ $response = new Response();
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+
+ $tokenProvider = $this->getMock('Symfony\Component\Security\Core\Authentication\RememberMe\TokenProviderInterface');
+ $tokenProvider
+ ->expects($this->once())
+ ->method('deleteTokenBySeries')
+ ->with($this->equalTo('fooseries'))
+ ->will($this->returnValue(null))
+ ;
+ $service->setTokenProvider($tokenProvider);
+
+ $service->logout($request, $response, $token);
+
+ $cookie = $request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME);
+ $this->assertTrue($cookie->isCleared());
+ $this->assertEquals('/foo', $cookie->getPath());
+ $this->assertEquals('foodomain.foo', $cookie->getDomain());
+ }
+
+ public function testLogoutSimplyIgnoresNonSetRequestCookie()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null));
+ $request = new Request();
+ $response = new Response();
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+
+ $tokenProvider = $this->getMock('Symfony\Component\Security\Core\Authentication\RememberMe\TokenProviderInterface');
+ $tokenProvider
+ ->expects($this->never())
+ ->method('deleteTokenBySeries')
+ ;
+ $service->setTokenProvider($tokenProvider);
+
+ $service->logout($request, $response, $token);
+
+ $cookie = $request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME);
+ $this->assertTrue($cookie->isCleared());
+ $this->assertEquals('/', $cookie->getPath());
+ $this->assertNull($cookie->getDomain());
+ }
+
+ public function testLogoutSimplyIgnoresInvalidCookie()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null));
+ $request = new Request();
+ $request->cookies->set('foo', 'somefoovalue');
+ $response = new Response();
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+
+ $tokenProvider = $this->getMock('Symfony\Component\Security\Core\Authentication\RememberMe\TokenProviderInterface');
+ $tokenProvider
+ ->expects($this->never())
+ ->method('deleteTokenBySeries')
+ ;
+ $service->setTokenProvider($tokenProvider);
+
+ $service->logout($request, $response, $token);
+
+ $this->assertTrue($request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME)->isCleared());
+ }
+
+ public function testLoginFail()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null));
+ $request = new Request();
+
+ $this->assertFalse($request->attributes->has(RememberMeServicesInterface::COOKIE_ATTR_NAME));
+ $service->loginFail($request);
+ $this->assertTrue($request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME)->isCleared());
+ }
+
+ public function testLoginSuccessSetsCookieWhenLoggedInWithNonRememberMeTokenInterfaceImplementation()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'domain' => 'myfoodomain.foo', 'path' => '/foo/path', 'secure' => true, 'httponly' => true, 'lifetime' => 3600, 'always_remember_me' => true));
+ $request = new Request();
+ $response = new Response();
+
+ $account = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $account
+ ->expects($this->once())
+ ->method('getUsername')
+ ->will($this->returnValue('foo'))
+ ;
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ $token
+ ->expects($this->any())
+ ->method('getUser')
+ ->will($this->returnValue($account))
+ ;
+
+ $tokenProvider = $this->getMock('Symfony\Component\Security\Core\Authentication\RememberMe\TokenProviderInterface');
+ $tokenProvider
+ ->expects($this->once())
+ ->method('createNewToken')
+ ;
+ $service->setTokenProvider($tokenProvider);
+
+ $cookies = $response->headers->getCookies();
+ $this->assertCount(0, $cookies);
+
+ $service->loginSuccess($request, $response, $token);
+
+ $cookies = $response->headers->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
+ $cookie = $cookies['myfoodomain.foo']['/foo/path']['foo'];
+ $this->assertFalse($cookie->isCleared());
+ $this->assertTrue($cookie->isSecure());
+ $this->assertTrue($cookie->isHttpOnly());
+ $this->assertTrue($cookie->getExpiresTime() > time() + 3590 && $cookie->getExpiresTime() < time() + 3610);
+ $this->assertEquals('myfoodomain.foo', $cookie->getDomain());
+ $this->assertEquals('/foo/path', $cookie->getPath());
+ }
+
+ protected function encodeCookie(array $parts)
+ {
+ $service = $this->getService();
+ $r = new \ReflectionMethod($service, 'encodeCookie');
+ $r->setAccessible(true);
+
+ return $r->invoke($service, $parts);
+ }
+
+ protected function getService($userProvider = null, $options = array(), $logger = null)
+ {
+ if (null === $userProvider) {
+ $userProvider = $this->getProvider();
+ }
+
+ return new PersistentTokenBasedRememberMeServices(array($userProvider), 'fookey', 'fookey', $options, $logger, new SecureRandom(sys_get_temp_dir().'/_sf2.seed'));
+ }
+
+ protected function getProvider()
+ {
+ $provider = $this->getMock('Symfony\Component\Security\Core\User\UserProviderInterface');
+ $provider
+ ->expects($this->any())
+ ->method('supportsClass')
+ ->will($this->returnValue(true))
+ ;
+
+ return $provider;
+ }
+}
diff --git a/Http/Tests/RememberMe/ResponseListenerTest.php b/Http/Tests/RememberMe/ResponseListenerTest.php
new file mode 100644
index 0000000..78de8e4
--- /dev/null
+++ b/Http/Tests/RememberMe/ResponseListenerTest.php
@@ -0,0 +1,102 @@
+<?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\Tests\RememberMe;
+
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\Security\Http\RememberMe\ResponseListener;
+use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Cookie;
+use Symfony\Component\HttpKernel\KernelEvents;
+
+class ResponseListenerTest extends \PHPUnit_Framework_TestCase
+{
+ public function testRememberMeCookieIsSentWithResponse()
+ {
+ $cookie = new Cookie('rememberme');
+
+ $request = $this->getRequest(array(
+ RememberMeServicesInterface::COOKIE_ATTR_NAME => $cookie,
+ ));
+
+ $response = $this->getResponse();
+ $response->headers->expects($this->once())->method('setCookie')->with($cookie);
+
+ $listener = new ResponseListener();
+ $listener->onKernelResponse($this->getEvent($request, $response));
+ }
+
+ public function testRememberMeCookieIsNotSendWithResponseForSubRequests()
+ {
+ $cookie = new Cookie('rememberme');
+
+ $request = $this->getRequest(array(
+ RememberMeServicesInterface::COOKIE_ATTR_NAME => $cookie,
+ ));
+
+ $response = $this->getResponse();
+ $response->headers->expects($this->never())->method('setCookie');
+
+ $listener = new ResponseListener();
+ $listener->onKernelResponse($this->getEvent($request, $response, HttpKernelInterface::SUB_REQUEST));
+ }
+
+ public function testRememberMeCookieIsNotSendWithResponse()
+ {
+ $request = $this->getRequest();
+
+ $response = $this->getResponse();
+ $response->headers->expects($this->never())->method('setCookie');
+
+ $listener = new ResponseListener();
+ $listener->onKernelResponse($this->getEvent($request, $response));
+ }
+
+ public function testItSubscribesToTheOnKernelResponseEvent()
+ {
+ $listener = new ResponseListener();
+
+ $this->assertSame(array(KernelEvents::RESPONSE => 'onKernelResponse'), ResponseListener::getSubscribedEvents());
+ }
+
+ private function getRequest(array $attributes = array())
+ {
+ $request = new Request();
+
+ foreach ($attributes as $name => $value) {
+ $request->attributes->set($name, $value);
+ }
+
+ return $request;
+ }
+
+ private function getResponse()
+ {
+ $response = $this->getMock('Symfony\Component\HttpFoundation\Response');
+ $response->headers = $this->getMock('Symfony\Component\HttpFoundation\ResponseHeaderBag');
+
+ return $response;
+ }
+
+ private function getEvent($request, $response, $type = HttpKernelInterface::MASTER_REQUEST)
+ {
+ $event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\FilterResponseEvent')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $event->expects($this->any())->method('getRequest')->will($this->returnValue($request));
+ $event->expects($this->any())->method('isMasterRequest')->will($this->returnValue($type === HttpKernelInterface::MASTER_REQUEST));
+ $event->expects($this->any())->method('getResponse')->will($this->returnValue($response));
+
+ return $event;
+ }
+}
diff --git a/Http/Tests/RememberMe/TokenBasedRememberMeServicesTest.php b/Http/Tests/RememberMe/TokenBasedRememberMeServicesTest.php
new file mode 100644
index 0000000..8c215e2
--- /dev/null
+++ b/Http/Tests/RememberMe/TokenBasedRememberMeServicesTest.php
@@ -0,0 +1,270 @@
+<?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\Tests\RememberMe;
+
+use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
+use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\ResponseHeaderBag;
+use Symfony\Component\Security\Http\RememberMe\TokenBasedRememberMeServices;
+
+class TokenBasedRememberMeServicesTest extends \PHPUnit_Framework_TestCase
+{
+ public function testAutoLoginReturnsNullWhenNoCookie()
+ {
+ $service = $this->getService(null, array('name' => 'foo'));
+
+ $this->assertNull($service->autoLogin(new Request()));
+ }
+
+ public function testAutoLoginThrowsExceptionOnInvalidCookie()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null, 'always_remember_me' => false, 'remember_me_parameter' => 'foo'));
+ $request = new Request();
+ $request->request->set('foo', 'true');
+ $request->cookies->set('foo', 'foo');
+
+ $this->assertNull($service->autoLogin($request));
+ $this->assertTrue($request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME)->isCleared());
+ }
+
+ public function testAutoLoginThrowsExceptionOnNonExistentUser()
+ {
+ $userProvider = $this->getProvider();
+ $service = $this->getService($userProvider, array('name' => 'foo', 'path' => null, 'domain' => null, 'always_remember_me' => true, 'lifetime' => 3600));
+ $request = new Request();
+ $request->cookies->set('foo', $this->getCookie('fooclass', 'foouser', time()+3600, 'foopass'));
+
+ $userProvider
+ ->expects($this->once())
+ ->method('loadUserByUsername')
+ ->will($this->throwException(new UsernameNotFoundException('user not found')))
+ ;
+
+ $this->assertNull($service->autoLogin($request));
+ $this->assertTrue($request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME)->isCleared());
+ }
+
+ public function testAutoLoginDoesNotAcceptCookieWithInvalidHash()
+ {
+ $userProvider = $this->getProvider();
+ $service = $this->getService($userProvider, array('name' => 'foo', 'path' => null, 'domain' => null, 'always_remember_me' => true, 'lifetime' => 3600));
+ $request = new Request();
+ $request->cookies->set('foo', base64_encode('class:'.base64_encode('foouser').':123456789:fooHash'));
+
+ $user = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $user
+ ->expects($this->once())
+ ->method('getPassword')
+ ->will($this->returnValue('foopass'))
+ ;
+
+ $userProvider
+ ->expects($this->once())
+ ->method('loadUserByUsername')
+ ->with($this->equalTo('foouser'))
+ ->will($this->returnValue($user))
+ ;
+
+ $this->assertNull($service->autoLogin($request));
+ $this->assertTrue($request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME)->isCleared());
+ }
+
+ public function testAutoLoginDoesNotAcceptAnExpiredCookie()
+ {
+ $userProvider = $this->getProvider();
+ $service = $this->getService($userProvider, array('name' => 'foo', 'path' => null, 'domain' => null, 'always_remember_me' => true, 'lifetime' => 3600));
+ $request = new Request();
+ $request->cookies->set('foo', $this->getCookie('fooclass', 'foouser', time() - 1, 'foopass'));
+
+ $user = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $user
+ ->expects($this->once())
+ ->method('getPassword')
+ ->will($this->returnValue('foopass'))
+ ;
+
+ $userProvider
+ ->expects($this->once())
+ ->method('loadUserByUsername')
+ ->with($this->equalTo('foouser'))
+ ->will($this->returnValue($user))
+ ;
+
+ $this->assertNull($service->autoLogin($request));
+ $this->assertTrue($request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME)->isCleared());
+ }
+
+ public function testAutoLogin()
+ {
+ $user = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $user
+ ->expects($this->once())
+ ->method('getRoles')
+ ->will($this->returnValue(array('ROLE_FOO')))
+ ;
+ $user
+ ->expects($this->once())
+ ->method('getPassword')
+ ->will($this->returnValue('foopass'))
+ ;
+
+ $userProvider = $this->getProvider();
+ $userProvider
+ ->expects($this->once())
+ ->method('loadUserByUsername')
+ ->with($this->equalTo('foouser'))
+ ->will($this->returnValue($user))
+ ;
+
+ $service = $this->getService($userProvider, array('name' => 'foo', 'always_remember_me' => true, 'lifetime' => 3600));
+ $request = new Request();
+ $request->cookies->set('foo', $this->getCookie('fooclass', 'foouser', time()+3600, 'foopass'));
+
+ $returnedToken = $service->autoLogin($request);
+
+ $this->assertInstanceOf('Symfony\Component\Security\Core\Authentication\Token\RememberMeToken', $returnedToken);
+ $this->assertSame($user, $returnedToken->getUser());
+ $this->assertEquals('fookey', $returnedToken->getKey());
+ }
+
+ public function testLogout()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null));
+ $request = new Request();
+ $response = new Response();
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+
+ $service->logout($request, $response, $token);
+
+ $cookie = $request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME);
+ $this->assertTrue($cookie->isCleared());
+ $this->assertEquals('/', $cookie->getPath());
+ $this->assertNull($cookie->getDomain());
+ }
+
+ public function testLoginFail()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'path' => '/foo', 'domain' => 'foodomain.foo'));
+ $request = new Request();
+ $response = new Response();
+
+ $service->loginFail($request, $response);
+
+ $cookie = $request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME);
+ $this->assertTrue($cookie->isCleared());
+ $this->assertEquals('/foo', $cookie->getPath());
+ $this->assertEquals('foodomain.foo', $cookie->getDomain());
+ }
+
+ public function testLoginSuccessIgnoresTokensWhichDoNotContainAnUserInterfaceImplementation()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'always_remember_me' => true, 'path' => null, 'domain' => null));
+ $request = new Request();
+ $response = new Response();
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ $token
+ ->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue('foo'))
+ ;
+
+ $cookies = $response->headers->getCookies();
+ $this->assertCount(0, $cookies);
+
+ $service->loginSuccess($request, $response, $token);
+
+ $cookies = $response->headers->getCookies();
+ $this->assertCount(0, $cookies);
+ }
+
+ public function testLoginSuccess()
+ {
+ $service = $this->getService(null, array('name' => 'foo', 'domain' => 'myfoodomain.foo', 'path' => '/foo/path', 'secure' => true, 'httponly' => true, 'lifetime' => 3600, 'always_remember_me' => true));
+ $request = new Request();
+ $response = new Response();
+
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ $user = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $user
+ ->expects($this->once())
+ ->method('getPassword')
+ ->will($this->returnValue('foopass'))
+ ;
+ $user
+ ->expects($this->once())
+ ->method('getUsername')
+ ->will($this->returnValue('foouser'))
+ ;
+ $token
+ ->expects($this->atLeastOnce())
+ ->method('getUser')
+ ->will($this->returnValue($user))
+ ;
+
+ $cookies = $response->headers->getCookies();
+ $this->assertCount(0, $cookies);
+
+ $service->loginSuccess($request, $response, $token);
+
+ $cookies = $response->headers->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
+ $cookie = $cookies['myfoodomain.foo']['/foo/path']['foo'];
+ $this->assertFalse($cookie->isCleared());
+ $this->assertTrue($cookie->isSecure());
+ $this->assertTrue($cookie->isHttpOnly());
+ $this->assertTrue($cookie->getExpiresTime() > time() + 3590 && $cookie->getExpiresTime() < time() + 3610);
+ $this->assertEquals('myfoodomain.foo', $cookie->getDomain());
+ $this->assertEquals('/foo/path', $cookie->getPath());
+ }
+
+ protected function getCookie($class, $username, $expires, $password)
+ {
+ $service = $this->getService();
+ $r = new \ReflectionMethod($service, 'generateCookieValue');
+ $r->setAccessible(true);
+
+ return $r->invoke($service, $class, $username, $expires, $password);
+ }
+
+ protected function encodeCookie(array $parts)
+ {
+ $service = $this->getService();
+ $r = new \ReflectionMethod($service, 'encodeCookie');
+ $r->setAccessible(true);
+
+ return $r->invoke($service, $parts);
+ }
+
+ protected function getService($userProvider = null, $options = array(), $logger = null)
+ {
+ if (null === $userProvider) {
+ $userProvider = $this->getProvider();
+ }
+
+ $service = new TokenBasedRememberMeServices(array($userProvider), 'fookey', 'fookey', $options, $logger);
+
+ return $service;
+ }
+
+ protected function getProvider()
+ {
+ $provider = $this->getMock('Symfony\Component\Security\Core\User\UserProviderInterface');
+ $provider
+ ->expects($this->any())
+ ->method('supportsClass')
+ ->will($this->returnValue(true))
+ ;
+
+ return $provider;
+ }
+}
diff --git a/Http/Tests/Session/SessionAuthenticationStrategyTest.php b/Http/Tests/Session/SessionAuthenticationStrategyTest.php
new file mode 100644
index 0000000..4aef4b2
--- /dev/null
+++ b/Http/Tests/Session/SessionAuthenticationStrategyTest.php
@@ -0,0 +1,90 @@
+<?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\Tests\Session;
+
+use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy;
+
+class SessionAuthenticationStrategyTest extends \PHPUnit_Framework_TestCase
+{
+ public function testSessionIsNotChanged()
+ {
+ $request = $this->getRequest();
+ $request->expects($this->never())->method('getSession');
+
+ $strategy = new SessionAuthenticationStrategy(SessionAuthenticationStrategy::NONE);
+ $strategy->onAuthentication($request, $this->getToken());
+ }
+
+ /**
+ * @expectedException \RuntimeException
+ * @expectedExceptionMessage Invalid session authentication strategy "foo"
+ */
+ public function testUnsupportedStrategy()
+ {
+ $request = $this->getRequest();
+ $request->expects($this->never())->method('getSession');
+
+ $strategy = new SessionAuthenticationStrategy('foo');
+ $strategy->onAuthentication($request, $this->getToken());
+ }
+
+ public function testSessionIsMigrated()
+ {
+ if (PHP_VERSION_ID >= 50400 && PHP_VERSION_ID < 50411) {
+ $this->markTestSkipped('We cannot destroy the old session on PHP 5.4.0 - 5.4.10.');
+ }
+
+ $session = $this->getMock('Symfony\Component\HttpFoundation\Session\SessionInterface');
+ $session->expects($this->once())->method('migrate')->with($this->equalTo(true));
+
+ $strategy = new SessionAuthenticationStrategy(SessionAuthenticationStrategy::MIGRATE);
+ $strategy->onAuthentication($this->getRequest($session), $this->getToken());
+ }
+
+ public function testSessionIsMigratedWithPhp54Workaround()
+ {
+ if (PHP_VERSION_ID < 50400 || PHP_VERSION_ID >= 50411) {
+ $this->markTestSkipped('This PHP version is not affected.');
+ }
+
+ $session = $this->getMock('Symfony\Component\HttpFoundation\Session\SessionInterface');
+ $session->expects($this->once())->method('migrate')->with($this->equalTo(false));
+
+ $strategy = new SessionAuthenticationStrategy(SessionAuthenticationStrategy::MIGRATE);
+ $strategy->onAuthentication($this->getRequest($session), $this->getToken());
+ }
+
+ public function testSessionIsInvalidated()
+ {
+ $session = $this->getMock('Symfony\Component\HttpFoundation\Session\SessionInterface');
+ $session->expects($this->once())->method('invalidate');
+
+ $strategy = new SessionAuthenticationStrategy(SessionAuthenticationStrategy::INVALIDATE);
+ $strategy->onAuthentication($this->getRequest($session), $this->getToken());
+ }
+
+ private function getRequest($session = null)
+ {
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+
+ if (null !== $session) {
+ $request->expects($this->any())->method('getSession')->will($this->returnValue($session));
+ }
+
+ return $request;
+ }
+
+ private function getToken()
+ {
+ return $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ }
+}
diff --git a/Http/composer.json b/Http/composer.json
new file mode 100644
index 0000000..c544ad1
--- /dev/null
+++ b/Http/composer.json
@@ -0,0 +1,44 @@
+{
+ "name": "symfony/security-http",
+ "type": "library",
+ "description": "Symfony Security Component - HTTP Integration",
+ "keywords": [],
+ "homepage": "http://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.3",
+ "symfony/security-core": "~2.4",
+ "symfony/event-dispatcher": "~2.1",
+ "symfony/http-foundation": "~2.4",
+ "symfony/http-kernel": "~2.4"
+ },
+ "require-dev": {
+ "symfony/routing": "~2.2",
+ "symfony/security-csrf": "~2.4",
+ "psr/log": "~1.0"
+ },
+ "suggest": {
+ "symfony/security-csrf": "For using tokens to protect authentication/logout attempts",
+ "symfony/routing": "For using the HttpUtils class to create sub-requests, redirect the user, and match URLs"
+ },
+ "autoload": {
+ "psr-0": { "Symfony\\Component\\Security\\Http\\": "" }
+ },
+ "target-dir": "Symfony/Component/Security/Http",
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.5-dev"
+ }
+ }
+}
diff --git a/Http/phpunit.xml.dist b/Http/phpunit.xml.dist
new file mode 100644
index 0000000..a152839
--- /dev/null
+++ b/Http/phpunit.xml.dist
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit backupGlobals="false"
+ backupStaticAttributes="false"
+ colors="true"
+ convertErrorsToExceptions="true"
+ convertNoticesToExceptions="true"
+ convertWarningsToExceptions="true"
+ processIsolation="false"
+ stopOnFailure="false"
+ syntaxCheck="false"
+ bootstrap="vendor/autoload.php"
+>
+ <php>
+ <!-- Silence E_USER_DEPRECATED (-16385 == -1 & ~E_USER_DEPRECATED) -->
+ <ini name="error_reporting" value="-16385"/>
+ </php>
+ <testsuites>
+ <testsuite name="Symfony Security Component HTTP Test Suite">
+ <directory>./Tests/</directory>
+ </testsuite>
+ </testsuites>
+
+ <filter>
+ <whitelist>
+ <directory>./</directory>
+ <exclude>
+ <directory>./vendor</directory>
+ <directory>./Tests</directory>
+ </exclude>
+ </whitelist>
+ </filter>
+</phpunit>