diff options
author | Bernhard Schussek <bschussek@gmail.com> | 2013-09-16 10:03:00 +0200 |
---|---|---|
committer | Fabien Potencier <fabien.potencier@gmail.com> | 2013-09-18 09:16:41 +0200 |
commit | 5a6aaab2c35213f5ca7e57f061fbb2675e2ece35 (patch) | |
tree | 461816fef8160401dc113d3fef190fb437d01cc7 /Http/Tests | |
parent | 513a354be10f0ed87933adcb788e48660f8e6ed4 (diff) | |
download | symfony-security-5a6aaab2c35213f5ca7e57f061fbb2675e2ece35.zip symfony-security-5a6aaab2c35213f5ca7e57f061fbb2675e2ece35.tar.gz symfony-security-5a6aaab2c35213f5ca7e57f061fbb2675e2ece35.tar.bz2 |
[Security] Split the component into 3 sub-components Core, ACL, HTTP
Diffstat (limited to 'Http/Tests')
29 files changed, 4384 insertions, 0 deletions
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..097c926 --- /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; + +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..fa0ebd4 --- /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; + +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/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..f4e5425 --- /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..57a91cf --- /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..1fb7350 --- /dev/null +++ b/Http/Tests/Firewall/AnonymousAuthenticationListenerTest.php @@ -0,0 +1,72 @@ +<?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() + { + if (!interface_exists('Psr\Log\LoggerInterface')) { + $this->markTestSkipped('The "LoggerInterface" is not available'); + } + + $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..eb51f5f --- /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..2b27e75 --- /dev/null +++ b/Http/Tests/Firewall/ChannelListenerTest.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\ChannelListener; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; +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..c153fd5 --- /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..86a5327 --- /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/LogoutListenerTest.php b/Http/Tests/Firewall/LogoutListenerTest.php new file mode 100644 index 0000000..719b684 --- /dev/null +++ b/Http/Tests/Firewall/LogoutListenerTest.php @@ -0,0 +1,239 @@ +<?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(); + $csrfProvider = $this->getCsrfProvider(); + + list($listener, $context, $httpUtils, $options) = $this->getListener($successHandler, $csrfProvider); + + list($event, $request) = $this->getGetResponseEvent(); + + $request->query->set('_csrf_token', $csrfToken = 'token'); + + $httpUtils->expects($this->once()) + ->method('checkRequestPath') + ->with($request, $options['logout_path']) + ->will($this->returnValue(true)); + + $csrfProvider->expects($this->once()) + ->method('isCsrfTokenValid') + ->with('logout', $csrfToken) + ->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() + { + $csrfProvider = $this->getCsrfProvider(); + + list($listener, $context, $httpUtils, $options) = $this->getListener(null, $csrfProvider); + + list($event, $request) = $this->getGetResponseEvent(); + + $request->query->set('_csrf_token', $csrfToken = 'token'); + + $httpUtils->expects($this->once()) + ->method('checkRequestPath') + ->with($request, $options['logout_path']) + ->will($this->returnValue(true)); + + $csrfProvider->expects($this->once()) + ->method('isCsrfTokenValid') + ->with('logout', $csrfToken) + ->will($this->returnValue(false)); + + $listener->handle($event); + } + + private function getCsrfProvider() + { + return $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface'); + } + + 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, $csrfProvider = 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' => '/', + ), + $csrfProvider + ); + + 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..9506692 --- /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..f331f0e --- /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 testSwitchUserIsDissallowed() + { + $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§ion=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..1724591 --- /dev/null +++ b/Http/Tests/Firewall/X509AuthenticationListenerTest.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\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', ''), + ); + } + + /** + * @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 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..67f4f15 --- /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..90380ea --- /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..76a8cd9 --- /dev/null +++ b/Http/Tests/Logout/DefaultLogoutSuccessHandlerTest.php @@ -0,0 +1,35 @@ +<?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\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..3c4b10d --- /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..91188a4 --- /dev/null +++ b/Http/Tests/RememberMe/PersistentTokenBasedRememberMeServicesTest.php @@ -0,0 +1,329 @@ +<?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\Authentication\Token\RememberMeToken; +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..5d69a65 --- /dev/null +++ b/Http/Tests/RememberMe/ResponseListenerTest.php @@ -0,0 +1,85 @@ +<?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\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 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'), $listener->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) + { + $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('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..cdd3031 --- /dev/null +++ b/Http/Tests/RememberMe/TokenBasedRememberMeServicesTest.php @@ -0,0 +1,273 @@ +<?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\Authentication\Token\RememberMeToken; +use Symfony\Component\Security\Core\Authentication\Token\Token; +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..7be9054 --- /dev/null +++ b/Http/Tests/Session/SessionAuthenticationStrategyTest.php @@ -0,0 +1,73 @@ +<?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() + { + $session = $this->getMock('Symfony\Component\HttpFoundation\Session\SessionInterface'); + $session->expects($this->once())->method('migrate'); + + $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'); + } +} |