Skip to content

Commit 302235e

Browse files
committed
Fixing a bug where having an authentication failure would log you out.
This solution is a copy of what AbstractAuthenticationListener does. Scenario: 1) Login 2) Go back to the log in page 3) Put in a bad user/pass You *should* still be logged in after a failed attempt. This commit gives that behavior.
1 parent 396a162 commit 302235e

File tree

4 files changed

+55
-8
lines changed

4 files changed

+55
-8
lines changed

src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ private function executeGuardAuthenticator($uniqueGuardKey, GuardAuthenticatorIn
117117
$this->logger->info('Guard authentication failed.', array('exception' => $e, 'authenticator' => get_class($guardAuthenticator)));
118118
}
119119

120-
$response = $this->guardHandler->handleAuthenticationFailure($e, $request, $guardAuthenticator);
120+
$response = $this->guardHandler->handleAuthenticationFailure($e, $request, $guardAuthenticator, $this->providerKey);
121121

122122
if ($response instanceof Response) {
123123
$event->setResponse($response);

src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
1919
use Symfony\Component\Security\Core\Exception\AuthenticationException;
2020
use Symfony\Component\Security\Core\User\UserInterface;
21+
use Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken;
2122
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
2223
use Symfony\Component\Security\Http\SecurityEvents;
2324

@@ -112,12 +113,16 @@ public function authenticateUserAndHandleSuccess(UserInterface $user, Request $r
112113
* @param AuthenticationException $authenticationException
113114
* @param Request $request
114115
* @param GuardAuthenticatorInterface $guardAuthenticator
116+
* @param string $providerKey The key of the firewall
115117
*
116118
* @return null|Response
117119
*/
118-
public function handleAuthenticationFailure(AuthenticationException $authenticationException, Request $request, GuardAuthenticatorInterface $guardAuthenticator)
120+
public function handleAuthenticationFailure(AuthenticationException $authenticationException, Request $request, GuardAuthenticatorInterface $guardAuthenticator, $providerKey)
119121
{
120-
$this->tokenStorage->setToken(null);
122+
$token = $this->tokenStorage->getToken();
123+
if ($token instanceof PostAuthenticationGuardToken && $providerKey === $token->getProviderKey()) {
124+
$this->tokenStorage->setToken(null);
125+
}
121126

122127
$response = $guardAuthenticator->onAuthenticationFailure($request, $authenticationException);
123128
if ($response instanceof Response || null === $response) {

src/Symfony/Component/Security/Guard/Tests/Firewall/GuardAuthenticationListenerTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ public function testHandleCatchesAuthenticationException()
141141
$this->guardAuthenticatorHandler
142142
->expects($this->once())
143143
->method('handleAuthenticationFailure')
144-
->with($authException, $this->request, $authenticator);
144+
->with($authException, $this->request, $authenticator, $providerKey);
145145

146146
$listener = new GuardAuthenticationListener(
147147
$this->guardAuthenticatorHandler,

src/Symfony/Component/Security/Guard/Tests/GuardAuthenticatorHandlerTest.php

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@
1818
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
1919
use Symfony\Component\Security\Http\SecurityEvents;
2020

21-
/**
22-
* @author Ryan Weaver <weaverryan@gmail.com>
23-
*/
2421
class GuardAuthenticatorHandlerTest extends \PHPUnit_Framework_TestCase
2522
{
2623
private $tokenStorage;
@@ -63,7 +60,41 @@ public function testHandleAuthenticationSuccess()
6360

6461
public function testHandleAuthenticationFailure()
6562
{
63+
// setToken() not called - getToken() will return null, so there's nothing to clear
64+
$this->tokenStorage->expects($this->never())
65+
->method('setToken')
66+
->with(null);
67+
$authException = new AuthenticationException('Bad password!');
68+
69+
$response = new Response('Try again, but with the right password!');
70+
$this->guardAuthenticator->expects($this->once())
71+
->method('onAuthenticationFailure')
72+
->with($this->request, $authException)
73+
->will($this->returnValue($response));
74+
75+
$handler = new GuardAuthenticatorHandler($this->tokenStorage, $this->dispatcher);
76+
$actualResponse = $handler->handleAuthenticationFailure($authException, $this->request, $this->guardAuthenticator, 'firewall_provider_key');
77+
$this->assertSame($response, $actualResponse);
78+
}
79+
80+
/**
81+
* @dataProvider getTokenClearingTests
82+
*/
83+
public function testHandleAuthenticationClearsToken($tokenClass, $tokenProviderKey, $actualProviderKey, $shouldTokenBeCleared)
84+
{
85+
$token = $this->getMockBuilder($tokenClass)
86+
->disableOriginalConstructor()
87+
->getMock();
88+
$token->expects($this->any())
89+
->method('getProviderKey')
90+
->will($this->returnValue($tokenProviderKey));
91+
92+
// make the $token be the current token
6693
$this->tokenStorage->expects($this->once())
94+
->method('getToken')
95+
->will($this->returnValue($token));
96+
97+
$this->tokenStorage->expects($shouldTokenBeCleared ? $this->once() : $this->never())
6798
->method('setToken')
6899
->with(null);
69100
$authException = new AuthenticationException('Bad password!');
@@ -75,10 +106,21 @@ public function testHandleAuthenticationFailure()
75106
->will($this->returnValue($response));
76107

77108
$handler = new GuardAuthenticatorHandler($this->tokenStorage, $this->dispatcher);
78-
$actualResponse = $handler->handleAuthenticationFailure($authException, $this->request, $this->guardAuthenticator);
109+
$actualResponse = $handler->handleAuthenticationFailure($authException, $this->request, $this->guardAuthenticator, $actualProviderKey);
79110
$this->assertSame($response, $actualResponse);
80111
}
81112

113+
public function getTokenClearingTests()
114+
{
115+
$tests = array();
116+
// correct token class and matching firewall => clear the token
117+
$tests[] = array('Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken', 'the_firewall_key', 'the_firewall_key', true);
118+
$tests[] = array('Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken', 'the_firewall_key', 'different_key', false);
119+
$tests[] = array('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken', 'the_firewall_key', 'the_firewall_key', false);
120+
121+
return $tests;
122+
}
123+
82124
protected function setUp()
83125
{
84126
$this->tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface');

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy