Skip to content
This repository was archived by the owner on May 31, 2024. It is now read-only.

Commit 1aa1d1b

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 9143527 commit 1aa1d1b

File tree

4 files changed

+55
-8
lines changed

4 files changed

+55
-8
lines changed

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);

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) {

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,

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)