diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserPreAuthenticatedTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserPreAuthenticatedTest.php new file mode 100644 index 0000000000000..0f60250379063 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserPreAuthenticatedTest.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\SecurityBundle\Tests\Functional; + +class SwitchUserPreAuthenticatedTest extends WebTestCase +{ + /** + * @dataProvider getTestParameters + */ + public function testSwitchUser($originalUser, $targetUser, $expectedUser, $expectedStatus) + { + $client = $this->createAuthenticatedClient($originalUser); + + $client->request('GET', '/profile?_switch_user='.$targetUser); + + $this->assertEquals($expectedStatus, $client->getResponse()->getStatusCode()); + $this->assertEquals($expectedUser, $client->getProfile()->getCollector('security')->getUser()); + } + + public function testSwitchedUserCannotSwitchToOther() + { + $client = $this->createAuthenticatedClient('user_can_switch'); + + $client->request('GET', '/profile?_switch_user=user_cannot_switch_1'); + $client->request('GET', '/profile?_switch_user=user_cannot_switch_2'); + + $this->assertEquals(500, $client->getResponse()->getStatusCode()); + $this->assertEquals('user_cannot_switch_1', $client->getProfile()->getCollector('security')->getUser()); + } + + public function testSwitchedUserExit() + { + $client = $this->createAuthenticatedClient('user_can_switch'); + + $client->request('GET', '/profile?_switch_user=user_cannot_switch_1'); + $client->request('GET', '/profile?_switch_user=_exit'); + + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + $this->assertEquals('user_can_switch', $client->getProfile()->getCollector('security')->getUser()); + } + + public function getTestParameters() + { + return array( + 'unauthorized_user_cannot_switch' => array('user_cannot_switch_1', 'user_cannot_switch_1', 'user_cannot_switch_1', 403), + 'authorized_user_can_switch' => array('user_can_switch', 'user_cannot_switch_1', 'user_cannot_switch_1', 200), + 'authorized_user_cannot_switch_to_non_existent' => array('user_can_switch', 'user_does_not_exist', 'user_can_switch', 500), + 'authorized_user_can_switch_to_himself' => array('user_can_switch', 'user_can_switch', 'user_can_switch', 200), + ); + } + + protected function createAuthenticatedClient($username) + { + $client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'switchuser_preauthenticated.yml')); + $client->followRedirects(true); + + $client->setServerParameters(array( + 'SSL_CLIENT_S_DN_Email' => $username, + 'SSL_CLIENT_S_DN' => 'test', + )); + + return $client; + } + + public static function setUpBeforeClass() + { + parent::deleteTmpDir('StandardFormLogin'); + } + + public static function tearDownAfterClass() + { + parent::deleteTmpDir('StandardFormLogin'); + } +} diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/switchuser_preauthenticated.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/switchuser_preauthenticated.yml new file mode 100644 index 0000000000000..e87fd3c3823aa --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/switchuser_preauthenticated.yml @@ -0,0 +1,16 @@ +imports: + - { resource: ./config.yml } + +security: + providers: + in_memory: + memory: + users: + user_can_switch: { password: test, roles: [ROLE_USER, ROLE_ALLOWED_TO_SWITCH] } + user_cannot_switch_1: { password: test, roles: [ROLE_USER] } + user_cannot_switch_2: { password: test, roles: [ROLE_USER] } + firewalls: + default: + switch_user: true + form_login: false + x509: true diff --git a/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php b/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php index b793310d9b336..bdccff9d2ae61 100644 --- a/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php @@ -54,6 +54,15 @@ public function __construct(TokenStorageInterface $tokenStorage, AuthenticationM */ final public function handle(GetResponseEvent $event) { + $token = $this->tokenStorage->getToken(); + if (null !== $token && !$token instanceof PreAuthenticatedToken && $token->isAuthenticated()) { + if (null !== $this->logger) { + $this->logger->debug('An authenticated token is already provided, bypass PreAuthenticatedListener.', array('token' => (string) $token)); + } + + return; + } + $request = $event->getRequest(); try { @@ -65,10 +74,10 @@ final public function handle(GetResponseEvent $event) } if (null !== $this->logger) { - $this->logger->debug('Checking current security token.', array('token' => (string) $this->tokenStorage->getToken())); + $this->logger->debug('Checking current security token.', array('token' => (string) $token)); } - if (null !== $token = $this->tokenStorage->getToken()) { + if (null !== $token) { if ($token instanceof PreAuthenticatedToken && $this->providerKey == $token->getProviderKey() && $token->isAuthenticated() && $token->getUsername() === $user) { return; }