diff options
Diffstat (limited to 'Http')
22 files changed, 567 insertions, 64 deletions
diff --git a/Http/Authentication/AuthenticationUtils.php b/Http/Authentication/AuthenticationUtils.php new file mode 100644 index 0000000..38763dc --- /dev/null +++ b/Http/Authentication/AuthenticationUtils.php @@ -0,0 +1,86 @@ +<?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\RequestStack; +use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Core\Security; + +/** + * Extracts Security Errors from Request + * + * @author Boris Vujicic <boris.vujicic@gmail.com> + */ +class AuthenticationUtils +{ + /** + * @var RequestStack + */ + private $requestStack; + + /** + * @param RequestStack $requestStack + */ + public function __construct(RequestStack $requestStack) + { + $this->requestStack = $requestStack; + } + + /** + * @param bool $clearSession + * @return null|AuthenticationException + */ + public function getLastAuthenticationError($clearSession = true) + { + $request = $this->getRequest(); + $session = $request->getSession(); + $authenticationException = null; + + if ($request->attributes->has(Security::AUTHENTICATION_ERROR)) { + $authenticationException = $request->attributes->get(Security::AUTHENTICATION_ERROR); + } elseif ($session !== null && $session->has(Security::AUTHENTICATION_ERROR)) { + $authenticationException = $session->get(Security::AUTHENTICATION_ERROR); + + if ($clearSession) { + $session->remove(Security::AUTHENTICATION_ERROR); + } + } + + return $authenticationException; + } + + /** + * @return string + */ + public function getLastUsername() + { + $session = $this->getRequest()->getSession(); + + return null === $session ? '' : $session->get(Security::LAST_USERNAME); + } + + /** + * @return Request + * @throws \LogicException + */ + private function getRequest() + { + $request = $this->requestStack->getCurrentRequest(); + + if (null === $request) { + throw new \LogicException('Request should exist so it can be processed for error.'); + } + + return $request; + } +} diff --git a/Http/Authentication/CustomAuthenticationFailureHandler.php b/Http/Authentication/CustomAuthenticationFailureHandler.php new file mode 100644 index 0000000..35bfc05 --- /dev/null +++ b/Http/Authentication/CustomAuthenticationFailureHandler.php @@ -0,0 +1,45 @@ +<?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\Security\Core\Exception\AuthenticationException; + +/** + * @author Fabien Potencier <fabien@symfony.com> + */ +class CustomAuthenticationFailureHandler implements AuthenticationFailureHandlerInterface +{ + private $handler; + + /** + * Constructor. + * + * @param AuthenticationFailureHandlerInterface $handler An AuthenticationFailureHandlerInterface instance + * @param array $options Options for processing a successful authentication attempt + */ + public function __construct(AuthenticationFailureHandlerInterface $handler, array $options) + { + $this->handler = $handler; + if (method_exists($handler, 'setOptions')) { + $this->handler->setOptions($options); + } + } + + /** + * {@inheritdoc} + */ + public function onAuthenticationFailure(Request $request, AuthenticationException $exception) + { + return $this->handler->onAuthenticationFailure($request, $exception); + } +} diff --git a/Http/Authentication/CustomAuthenticationSuccessHandler.php b/Http/Authentication/CustomAuthenticationSuccessHandler.php new file mode 100644 index 0000000..abbb81b --- /dev/null +++ b/Http/Authentication/CustomAuthenticationSuccessHandler.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\Authentication; + +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\HttpFoundation\Request; + +/** + * @author Fabien Potencier <fabien@symfony.com> + */ +class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandlerInterface +{ + private $handler; + + /** + * Constructor. + * + * @param AuthenticationSuccessHandlerInterface $handler An AuthenticationFailureHandlerInterface instance + * @param array $options Options for processing a successful authentication attempt + * @param string $providerKey The provider key + */ + public function __construct(AuthenticationSuccessHandlerInterface $handler, array $options, $providerKey) + { + $this->handler = $handler; + if (method_exists($handler, 'setOptions')) { + $this->handler->setOptions($options); + } + if (method_exists($handler, 'setProviderKey')) { + $this->handler->setProviderKey($providerKey); + } + } + + /** + * {@inheritdoc} + */ + public function onAuthenticationSuccess(Request $request, TokenInterface $token) + { + return $this->handler->onAuthenticationSuccess($request, $token); + } +} diff --git a/Http/Authentication/DefaultAuthenticationFailureHandler.php b/Http/Authentication/DefaultAuthenticationFailureHandler.php index b3c5c4d..93150c8 100644 --- a/Http/Authentication/DefaultAuthenticationFailureHandler.php +++ b/Http/Authentication/DefaultAuthenticationFailureHandler.php @@ -15,7 +15,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\HttpKernelInterface; use Psr\Log\LoggerInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; -use Symfony\Component\Security\Core\SecurityContextInterface; +use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Http\HttpUtils; /** @@ -34,6 +34,12 @@ class DefaultAuthenticationFailureHandler implements AuthenticationFailureHandle protected $httpUtils; protected $logger; protected $options; + protected $defaultOptions = array( + 'failure_path' => null, + 'failure_forward' => false, + 'login_path' => '/login', + 'failure_path_parameter' => '_failure_path', + ); /** * Constructor. @@ -43,18 +49,32 @@ class DefaultAuthenticationFailureHandler implements AuthenticationFailureHandle * @param array $options Options for processing a failed authentication attempt. * @param LoggerInterface $logger Optional logger */ - public function __construct(HttpKernelInterface $httpKernel, HttpUtils $httpUtils, array $options, LoggerInterface $logger = null) + public function __construct(HttpKernelInterface $httpKernel, HttpUtils $httpUtils, array $options = array(), LoggerInterface $logger = null) { $this->httpKernel = $httpKernel; $this->httpUtils = $httpUtils; $this->logger = $logger; + $this->setOptions($options); + } - $this->options = array_merge(array( - 'failure_path' => null, - 'failure_forward' => false, - 'login_path' => '/login', - 'failure_path_parameter' => '_failure_path', - ), $options); + /** + * Gets the options. + * + * @return array An array of options + */ + public function getOptions() + { + return $this->options; + } + + /** + * Sets the options. + * + * @param array $options An array of options + */ + public function setOptions(array $options) + { + $this->options = array_merge($this->defaultOptions, $options); } /** @@ -76,7 +96,7 @@ class DefaultAuthenticationFailureHandler implements AuthenticationFailureHandle } $subRequest = $this->httpUtils->createRequest($request, $this->options['failure_path']); - $subRequest->attributes->set(SecurityContextInterface::AUTHENTICATION_ERROR, $exception); + $subRequest->attributes->set(Security::AUTHENTICATION_ERROR, $exception); return $this->httpKernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST); } @@ -85,7 +105,7 @@ class DefaultAuthenticationFailureHandler implements AuthenticationFailureHandle $this->logger->debug(sprintf('Redirecting to %s', $this->options['failure_path'])); } - $request->getSession()->set(SecurityContextInterface::AUTHENTICATION_ERROR, $exception); + $request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception); return $this->httpUtils->createRedirectResponse($request, $this->options['failure_path']); } diff --git a/Http/Authentication/DefaultAuthenticationSuccessHandler.php b/Http/Authentication/DefaultAuthenticationSuccessHandler.php index 591a28d..0ee11b4 100644 --- a/Http/Authentication/DefaultAuthenticationSuccessHandler.php +++ b/Http/Authentication/DefaultAuthenticationSuccessHandler.php @@ -27,6 +27,13 @@ class DefaultAuthenticationSuccessHandler implements AuthenticationSuccessHandle protected $httpUtils; protected $options; protected $providerKey; + protected $defaultOptions = array( + 'always_use_default_target_path' => false, + 'default_target_path' => '/', + 'login_path' => '/login', + 'target_path_parameter' => '_target_path', + 'use_referer' => false, + ); /** * Constructor. @@ -34,17 +41,10 @@ class DefaultAuthenticationSuccessHandler implements AuthenticationSuccessHandle * @param HttpUtils $httpUtils * @param array $options Options for processing a successful authentication attempt. */ - public function __construct(HttpUtils $httpUtils, array $options) + public function __construct(HttpUtils $httpUtils, array $options = array()) { $this->httpUtils = $httpUtils; - - $this->options = array_merge(array( - 'always_use_default_target_path' => false, - 'default_target_path' => '/', - 'login_path' => '/login', - 'target_path_parameter' => '_target_path', - 'use_referer' => false, - ), $options); + $this->setOptions($options); } /** @@ -56,6 +56,26 @@ class DefaultAuthenticationSuccessHandler implements AuthenticationSuccessHandle } /** + * Gets the options. + * + * @return array An array of options + */ + public function getOptions() + { + return $this->options; + } + + /** + * Sets the options. + * + * @param array $options An array of options + */ + public function setOptions(array $options) + { + $this->options = array_merge($this->defaultOptions, $options); + } + + /** * Get the provider key. * * @return string diff --git a/Http/Firewall/AbstractAuthenticationListener.php b/Http/Firewall/AbstractAuthenticationListener.php index a67d61c..d89785e 100644 --- a/Http/Firewall/AbstractAuthenticationListener.php +++ b/Http/Firewall/AbstractAuthenticationListener.php @@ -15,6 +15,7 @@ use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterfa use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface; +use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; @@ -218,8 +219,8 @@ abstract class AbstractAuthenticationListener implements ListenerInterface $this->securityContext->setToken($token); $session = $request->getSession(); - $session->remove(SecurityContextInterface::AUTHENTICATION_ERROR); - $session->remove(SecurityContextInterface::LAST_USERNAME); + $session->remove(Security::AUTHENTICATION_ERROR); + $session->remove(Security::LAST_USERNAME); if (null !== $this->dispatcher) { $loginEvent = new InteractiveLoginEvent($request, $token); diff --git a/Http/Firewall/AnonymousAuthenticationListener.php b/Http/Firewall/AnonymousAuthenticationListener.php index 446dfec..68f8987 100644 --- a/Http/Firewall/AnonymousAuthenticationListener.php +++ b/Http/Firewall/AnonymousAuthenticationListener.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Security\Http\Firewall; +use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\SecurityContextInterface; use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; @@ -26,12 +28,14 @@ class AnonymousAuthenticationListener implements ListenerInterface { private $context; private $key; + private $authenticationManager; private $logger; - public function __construct(SecurityContextInterface $context, $key, LoggerInterface $logger = null) + public function __construct(SecurityContextInterface $context, $key, LoggerInterface $logger = null, AuthenticationManagerInterface $authenticationManager = null) { $this->context = $context; $this->key = $key; + $this->authenticationManager = $authenticationManager; $this->logger = $logger; } @@ -46,10 +50,21 @@ class AnonymousAuthenticationListener implements ListenerInterface return; } - $this->context->setToken(new AnonymousToken($this->key, 'anon.', array())); + try { + $token = new AnonymousToken($this->key, 'anon.', array()); + if (null !== $this->authenticationManager) { + $token = $this->authenticationManager->authenticate($token); + } - if (null !== $this->logger) { - $this->logger->info('Populated SecurityContext with an anonymous Token'); + $this->context->setToken($token); + + if (null !== $this->logger) { + $this->logger->info('Populated SecurityContext with an anonymous Token'); + } + } catch (AuthenticationException $failed) { + if (null !== $this->logger) { + $this->logger->info(sprintf('Anonymous authentication failed: %s', $failed->getMessage())); + } } } } diff --git a/Http/Firewall/ContextListener.php b/Http/Firewall/ContextListener.php index 435c440..e61907e 100644 --- a/Http/Firewall/ContextListener.php +++ b/Http/Firewall/ContextListener.php @@ -142,7 +142,7 @@ class ContextListener implements ListenerInterface * * @throws \RuntimeException */ - private function refreshUser(TokenInterface $token) + protected function refreshUser(TokenInterface $token) { $user = $token->getUser(); if (!$user instanceof UserInterface) { diff --git a/Http/Firewall/ExceptionListener.php b/Http/Firewall/ExceptionListener.php index d0b167e..e224ea3 100644 --- a/Http/Firewall/ExceptionListener.php +++ b/Http/Firewall/ExceptionListener.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface; +use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; @@ -146,7 +147,7 @@ class ExceptionListener } } elseif (null !== $this->errorPage) { $subRequest = $this->httpUtils->createRequest($event->getRequest(), $this->errorPage); - $subRequest->attributes->set(SecurityContextInterface::ACCESS_DENIED_ERROR, $exception); + $subRequest->attributes->set(Security::ACCESS_DENIED_ERROR, $exception); $event->setResponse($event->getKernel()->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true)); } diff --git a/Http/Firewall/RememberMeListener.php b/Http/Firewall/RememberMeListener.php index 6ca3842..44000d3 100644 --- a/Http/Firewall/RememberMeListener.php +++ b/Http/Firewall/RememberMeListener.php @@ -33,6 +33,7 @@ class RememberMeListener implements ListenerInterface private $authenticationManager; private $logger; private $dispatcher; + private $catchExceptions = true; /** * Constructor. @@ -42,14 +43,16 @@ class RememberMeListener implements ListenerInterface * @param AuthenticationManagerInterface $authenticationManager * @param LoggerInterface $logger * @param EventDispatcherInterface $dispatcher + * @param bool $catchExceptions */ - public function __construct(SecurityContextInterface $securityContext, RememberMeServicesInterface $rememberMeServices, AuthenticationManagerInterface $authenticationManager, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null) + public function __construct(SecurityContextInterface $securityContext, RememberMeServicesInterface $rememberMeServices, AuthenticationManagerInterface $authenticationManager, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, $catchExceptions = true) { $this->securityContext = $securityContext; $this->rememberMeServices = $rememberMeServices; $this->authenticationManager = $authenticationManager; $this->logger = $logger; $this->dispatcher = $dispatcher; + $this->catchExceptions = $catchExceptions; } /** @@ -90,6 +93,10 @@ class RememberMeListener implements ListenerInterface } $this->rememberMeServices->loginFail($request); + + if (!$this->catchExceptions) { + throw $failed; + } } } } diff --git a/Http/Firewall/RemoteUserAuthenticationListener.php b/Http/Firewall/RemoteUserAuthenticationListener.php new file mode 100644 index 0000000..f190a17 --- /dev/null +++ b/Http/Firewall/RemoteUserAuthenticationListener.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\Firewall; + +use Symfony\Component\Security\Core\SecurityContextInterface; +use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Core\Exception\BadCredentialsException; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; + +/** + * REMOTE_USER authentication listener. + * + * @author Fabien Potencier <fabien@symfony.com> + * @author Maxime Douailin <maxime.douailin@gmail.com> + */ +class RemoteUserAuthenticationListener extends AbstractPreAuthenticatedListener +{ + private $userKey; + + public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, $userKey = 'REMOTE_USER', LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null) + { + parent::__construct($securityContext, $authenticationManager, $providerKey, $logger, $dispatcher); + + $this->userKey = $userKey; + } + + /** + * {@inheritdoc} + */ + protected function getPreAuthenticatedData(Request $request) + { + if (!$request->server->has($this->userKey)) { + throw new BadCredentialsException(sprintf('User key was not found: %s', $this->userKey)); + } + + return array($request->server->get($this->userKey), null); + } +} diff --git a/Http/Firewall/SimpleFormAuthenticationListener.php b/Http/Firewall/SimpleFormAuthenticationListener.php index 5b905df..7f27b7f 100644 --- a/Http/Firewall/SimpleFormAuthenticationListener.php +++ b/Http/Firewall/SimpleFormAuthenticationListener.php @@ -23,6 +23,7 @@ use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerI 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\Security; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; @@ -114,7 +115,7 @@ class SimpleFormAuthenticationListener extends AbstractAuthenticationListener $password = $request->get($this->options['password_parameter'], null, true); } - $request->getSession()->set(SecurityContextInterface::LAST_USERNAME, $username); + $request->getSession()->set(Security::LAST_USERNAME, $username); $token = $this->simpleAuthenticator->createToken($request, $username, $password, $this->providerKey); diff --git a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php index 36ff758..b857fb3 100644 --- a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php +++ b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php @@ -25,6 +25,7 @@ use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterfac 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\Security; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -93,7 +94,7 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL $password = $request->get($this->options['password_parameter'], null, true); } - $request->getSession()->set(SecurityContextInterface::LAST_USERNAME, $username); + $request->getSession()->set(Security::LAST_USERNAME, $username); return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey)); } diff --git a/Http/HttpUtils.php b/Http/HttpUtils.php index 451c12c..fbcfdb7 100644 --- a/Http/HttpUtils.php +++ b/Http/HttpUtils.php @@ -11,8 +11,6 @@ namespace Symfony\Component\Security\Http; -use Symfony\Component\Security\Core\SecurityContextInterface; - use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\Routing\Matcher\UrlMatcherInterface; @@ -20,6 +18,7 @@ use Symfony\Component\Routing\Matcher\RequestMatcherInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\Exception\MethodNotAllowedException; use Symfony\Component\Routing\Exception\ResourceNotFoundException; +use Symfony\Component\Security\Core\Security; /** * Encapsulates the logic needed to create sub-requests, redirect the user, and match URLs. @@ -77,14 +76,14 @@ class HttpUtils $newRequest->setSession($request->getSession()); } - if ($request->attributes->has(SecurityContextInterface::AUTHENTICATION_ERROR)) { - $newRequest->attributes->set(SecurityContextInterface::AUTHENTICATION_ERROR, $request->attributes->get(SecurityContextInterface::AUTHENTICATION_ERROR)); + if ($request->attributes->has(Security::AUTHENTICATION_ERROR)) { + $newRequest->attributes->set(Security::AUTHENTICATION_ERROR, $request->attributes->get(Security::AUTHENTICATION_ERROR)); } - if ($request->attributes->has(SecurityContextInterface::ACCESS_DENIED_ERROR)) { - $newRequest->attributes->set(SecurityContextInterface::ACCESS_DENIED_ERROR, $request->attributes->get(SecurityContextInterface::ACCESS_DENIED_ERROR)); + if ($request->attributes->has(Security::ACCESS_DENIED_ERROR)) { + $newRequest->attributes->set(Security::ACCESS_DENIED_ERROR, $request->attributes->get(Security::ACCESS_DENIED_ERROR)); } - if ($request->attributes->has(SecurityContextInterface::LAST_USERNAME)) { - $newRequest->attributes->set(SecurityContextInterface::LAST_USERNAME, $request->attributes->get(SecurityContextInterface::LAST_USERNAME)); + if ($request->attributes->has(Security::LAST_USERNAME)) { + $newRequest->attributes->set(Security::LAST_USERNAME, $request->attributes->get(Security::LAST_USERNAME)); } return $newRequest; diff --git a/Http/README.md b/Http/README.md index c0760d4..e19af42 100644 --- a/Http/README.md +++ b/Http/README.md @@ -11,7 +11,7 @@ Resources Documentation: -http://symfony.com/doc/2.5/book/security.html +http://symfony.com/doc/2.6/book/security.html Tests ----- diff --git a/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php b/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php index 15adcdf..e065660 100644 --- a/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php +++ b/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Security\Http\Tests\Authentication; use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler; -use Symfony\Component\Security\Core\SecurityContextInterface; +use Symfony\Component\Security\Core\Security; use Symfony\Component\HttpKernel\HttpKernelInterface; class DefaultAuthenticationFailureHandlerTest extends \PHPUnit_Framework_TestCase @@ -47,7 +47,7 @@ class DefaultAuthenticationFailureHandlerTest extends \PHPUnit_Framework_TestCas $subRequest = $this->getRequest(); $subRequest->attributes->expects($this->once()) - ->method('set')->with(SecurityContextInterface::AUTHENTICATION_ERROR, $this->exception); + ->method('set')->with(Security::AUTHENTICATION_ERROR, $this->exception); $this->httpUtils->expects($this->once()) ->method('createRequest')->with($this->request, '/login') ->will($this->returnValue($subRequest)); @@ -79,7 +79,7 @@ class DefaultAuthenticationFailureHandlerTest extends \PHPUnit_Framework_TestCas public function testExceptionIsPersistedInSession() { $this->session->expects($this->once()) - ->method('set')->with(SecurityContextInterface::AUTHENTICATION_ERROR, $this->exception); + ->method('set')->with(Security::AUTHENTICATION_ERROR, $this->exception); $handler = new DefaultAuthenticationFailureHandler($this->httpKernel, $this->httpUtils, array(), $this->logger); $handler->onAuthenticationFailure($this->request, $this->exception); @@ -91,7 +91,7 @@ class DefaultAuthenticationFailureHandlerTest extends \PHPUnit_Framework_TestCas $subRequest = $this->getRequest(); $subRequest->attributes->expects($this->once()) - ->method('set')->with(SecurityContextInterface::AUTHENTICATION_ERROR, $this->exception); + ->method('set')->with(Security::AUTHENTICATION_ERROR, $this->exception); $this->httpUtils->expects($this->once()) ->method('createRequest')->with($this->request, '/login') diff --git a/Http/Tests/Firewall/AnonymousAuthenticationListenerTest.php b/Http/Tests/Firewall/AnonymousAuthenticationListenerTest.php index 1fb7350..0f43aa0 100644 --- a/Http/Tests/Firewall/AnonymousAuthenticationListenerTest.php +++ b/Http/Tests/Firewall/AnonymousAuthenticationListenerTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Security\Http\Tests\Firewall; +use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; use Symfony\Component\Security\Http\Firewall\AnonymousAuthenticationListener; class AnonymousAuthenticationListenerTest extends \PHPUnit_Framework_TestCase @@ -28,7 +29,13 @@ class AnonymousAuthenticationListenerTest extends \PHPUnit_Framework_TestCase ->method('setToken') ; - $listener = new AnonymousAuthenticationListener($context, 'TheKey'); + $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); + $authenticationManager + ->expects($this->never()) + ->method('authenticate') + ; + + $listener = new AnonymousAuthenticationListener($context, 'TheKey', null, $authenticationManager); $listener->handle($this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false)); } @@ -40,16 +47,27 @@ class AnonymousAuthenticationListenerTest extends \PHPUnit_Framework_TestCase ->method('getToken') ->will($this->returnValue(null)) ; - $context + + $anonymousToken = new AnonymousToken('TheKey', 'anon.', array()); + + $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); + $authenticationManager ->expects($this->once()) - ->method('setToken') + ->method('authenticate') ->with(self::logicalAnd( - $this->isInstanceOf('Symfony\Component\Security\Core\Authentication\Token\AnonymousToken'), - $this->attributeEqualTo('key', 'TheKey') + $this->isInstanceOf('Symfony\Component\Security\Core\Authentication\Token\AnonymousToken'), + $this->attributeEqualTo('key', 'TheKey') )) + ->will($this->returnValue($anonymousToken)) ; - $listener = new AnonymousAuthenticationListener($context, 'TheKey'); + $context + ->expects($this->once()) + ->method('setToken') + ->with($anonymousToken) + ; + + $listener = new AnonymousAuthenticationListener($context, 'TheKey', null, $authenticationManager); $listener->handle($this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false)); } @@ -66,7 +84,9 @@ class AnonymousAuthenticationListenerTest extends \PHPUnit_Framework_TestCase ->with('Populated SecurityContext with an anonymous Token') ; - $listener = new AnonymousAuthenticationListener($context, 'TheKey', $logger); + $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); + + $listener = new AnonymousAuthenticationListener($context, 'TheKey', $logger, $authenticationManager); $listener->handle($this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false)); } } diff --git a/Http/Tests/Firewall/ContextListenerTest.php b/Http/Tests/Firewall/ContextListenerTest.php index d6bc5b4..90af07e 100644 --- a/Http/Tests/Firewall/ContextListenerTest.php +++ b/Http/Tests/Firewall/ContextListenerTest.php @@ -18,6 +18,7 @@ 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\Storage\TokenStorage; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\SecurityContext; use Symfony\Component\Security\Http\Firewall\ContextListener; @@ -27,8 +28,8 @@ 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') + new TokenStorage(), + $this->getMock('Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface') ); } diff --git a/Http/Tests/Firewall/RememberMeListenerTest.php b/Http/Tests/Firewall/RememberMeListenerTest.php index 9506692..68dfc14 100644 --- a/Http/Tests/Firewall/RememberMeListenerTest.php +++ b/Http/Tests/Firewall/RememberMeListenerTest.php @@ -14,12 +14,13 @@ 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; +use Symfony\Component\Security\Http\SecurityEvents; class RememberMeListenerTest extends \PHPUnit_Framework_TestCase { public function testOnCoreSecurityDoesNotTryToPopulateNonEmptySecurityContext() { - list($listener, $context, $service,,) = $this->getListener(); + list($listener, $context,,,,) = $this->getListener(); $context ->expects($this->once()) @@ -99,6 +100,48 @@ class RememberMeListenerTest extends \PHPUnit_Framework_TestCase $listener->handle($event); } + /** + * @expectedException Symfony\Component\Security\Core\Exception\AuthenticationException + * @expectedExceptionMessage Authentication failed. + */ + public function testOnCoreSecurityIgnoresAuthenticationOptionallyRethrowsExceptionThrownAuthenticationManagerImplementation() + { + list($listener, $context, $service, $manager,) = $this->getListener(false, false); + + $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(); @@ -138,6 +181,55 @@ class RememberMeListenerTest extends \PHPUnit_Framework_TestCase $listener->handle($event); } + public function testOnCoreSecurityInteractiveLoginEventIsDispatchedIfDispatcherIsPresent() + { + list($listener, $context, $service, $manager,, $dispatcher) = $this->getListener(true); + + $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(); + $request = new Request(); + $event + ->expects($this->once()) + ->method('getRequest') + ->will($this->returnValue($request)) + ; + + $dispatcher + ->expects($this->once()) + ->method('dispatch') + ->with( + SecurityEvents::INTERACTIVE_LOGIN, + $this->isInstanceOf('Symfony\Component\Security\Http\Event\InteractiveLoginEvent') + ) + ; + + $listener->handle($event); + } + protected function getGetResponseEvent() { return $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false); @@ -148,16 +240,18 @@ class RememberMeListenerTest extends \PHPUnit_Framework_TestCase return $this->getMock('Symfony\Component\HttpKernel\Event\FilterResponseEvent', array(), array(), '', false); } - protected function getListener() + protected function getListener($withDispatcher = false, $catchExceptions = true) { $listener = new RememberMeListener( $context = $this->getContext(), $service = $this->getService(), $manager = $this->getManager(), - $logger = $this->getLogger() + $logger = $this->getLogger(), + $dispatcher = ($withDispatcher ? $this->getDispatcher() : null), + $catchExceptions ); - return array($listener, $context, $service, $manager, $logger); + return array($listener, $context, $service, $manager, $logger, $dispatcher); } protected function getLogger() @@ -177,8 +271,11 @@ class RememberMeListenerTest extends \PHPUnit_Framework_TestCase protected function getContext() { - return $this->getMockBuilder('Symfony\Component\Security\Core\SecurityContext') - ->disableOriginalConstructor() - ->getMock(); + return $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); + } + + protected function getDispatcher() + { + return $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); } } diff --git a/Http/Tests/Firewall/RemoteUserAuthenticationListenerTest.php b/Http/Tests/Firewall/RemoteUserAuthenticationListenerTest.php new file mode 100644 index 0000000..2bc1ad6 --- /dev/null +++ b/Http/Tests/Firewall/RemoteUserAuthenticationListenerTest.php @@ -0,0 +1,91 @@ +<?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\RemoteUserAuthenticationListener; + +class RemoteUserAuthenticationListenerTest extends \PHPUnit_Framework_TestCase +{ + public function testGetPreAuthenticatedData() + { + $serverVars = array( + 'REMOTE_USER' => 'TheUser' + ); + + $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 RemoteUserAuthenticationListener( + $context, + $authenticationManager, + 'TheProviderKey' + ); + + $method = new \ReflectionMethod($listener, 'getPreAuthenticatedData'); + $method->setAccessible(true); + + $result = $method->invokeArgs($listener, array($request)); + $this->assertSame($result, array('TheUser', null)); + } + + /** + * @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException + */ + public function testGetPreAuthenticatedDataNoUser() + { + $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 RemoteUserAuthenticationListener( + $context, + $authenticationManager, + 'TheProviderKey' + ); + + $method = new \ReflectionMethod($listener, 'getPreAuthenticatedData'); + $method->setAccessible(true); + + $result = $method->invokeArgs($listener, array($request)); + } + + public function testGetPreAuthenticatedDataWithDifferentKeys() + { + $userCredentials = array('TheUser', null); + + $request = new Request(array(), array(), array(), array(), array(), array( + 'TheUserKey' => 'TheUser' + )); + $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); + + $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); + + $listener = new RemoteUserAuthenticationListener( + $context, + $authenticationManager, + 'TheProviderKey', + 'TheUserKey' + ); + + $method = new \ReflectionMethod($listener, 'getPreAuthenticatedData'); + $method->setAccessible(true); + + $result = $method->invokeArgs($listener, array($request)); + $this->assertSame($result, $userCredentials); + } +} diff --git a/Http/Tests/HttpUtilsTest.php b/Http/Tests/HttpUtilsTest.php index 5cac504..195fc48 100644 --- a/Http/Tests/HttpUtilsTest.php +++ b/Http/Tests/HttpUtilsTest.php @@ -14,7 +14,7 @@ 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\Core\Security; use Symfony\Component\Security\Http\HttpUtils; class HttpUtilsTest extends \PHPUnit_Framework_TestCase @@ -126,9 +126,9 @@ class HttpUtilsTest extends \PHPUnit_Framework_TestCase public function provideSecurityContextAttributes() { return array( - array(SecurityContextInterface::AUTHENTICATION_ERROR), - array(SecurityContextInterface::ACCESS_DENIED_ERROR), - array(SecurityContextInterface::LAST_USERNAME), + array(Security::AUTHENTICATION_ERROR), + array(Security::ACCESS_DENIED_ERROR), + array(Security::LAST_USERNAME), ); } diff --git a/Http/composer.json b/Http/composer.json index c544ad1..8129523 100644 --- a/Http/composer.json +++ b/Http/composer.json @@ -38,7 +38,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" } } } |