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

Commit 8e84c8e

Browse files
committed
feature #10793 [Security] Allow exception bubbling in RememberMeListener (lstrojny)
This PR was merged into the 2.6-dev branch. Discussion ---------- [Security] Allow exception bubbling in RememberMeListener - Allow optional exception bubbling so that the exception listener has a chance to handle those exceptions #### While at it - Test for dispatching the InteractiveLogin event - Smaller cleanups in the test | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | ye | Fixed tickets | n.A. | License | MIT | Doc PR | n.A. Commits ------- fcb7f74 Allow exception bubbling in RememberMeListener
2 parents e6cf9c5 + c9b8877 commit 8e84c8e

File tree

2 files changed

+112
-8
lines changed

2 files changed

+112
-8
lines changed

Http/Firewall/RememberMeListener.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class RememberMeListener implements ListenerInterface
3333
private $authenticationManager;
3434
private $logger;
3535
private $dispatcher;
36+
private $catchExceptions = true;
3637

3738
/**
3839
* Constructor.
@@ -42,14 +43,16 @@ class RememberMeListener implements ListenerInterface
4243
* @param AuthenticationManagerInterface $authenticationManager
4344
* @param LoggerInterface $logger
4445
* @param EventDispatcherInterface $dispatcher
46+
* @param bool $catchExceptions
4547
*/
46-
public function __construct(SecurityContextInterface $securityContext, RememberMeServicesInterface $rememberMeServices, AuthenticationManagerInterface $authenticationManager, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null)
48+
public function __construct(SecurityContextInterface $securityContext, RememberMeServicesInterface $rememberMeServices, AuthenticationManagerInterface $authenticationManager, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, $catchExceptions = true)
4749
{
4850
$this->securityContext = $securityContext;
4951
$this->rememberMeServices = $rememberMeServices;
5052
$this->authenticationManager = $authenticationManager;
5153
$this->logger = $logger;
5254
$this->dispatcher = $dispatcher;
55+
$this->catchExceptions = $catchExceptions;
5356
}
5457

5558
/**
@@ -90,6 +93,10 @@ public function handle(GetResponseEvent $event)
9093
}
9194

9295
$this->rememberMeServices->loginFail($request);
96+
97+
if (!$this->catchExceptions) {
98+
throw $failed;
99+
}
93100
}
94101
}
95102
}

Http/Tests/Firewall/RememberMeListenerTest.php

Lines changed: 104 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@
1414
use Symfony\Component\Security\Core\Exception\AuthenticationException;
1515
use Symfony\Component\Security\Http\Firewall\RememberMeListener;
1616
use Symfony\Component\HttpFoundation\Request;
17+
use Symfony\Component\Security\Http\SecurityEvents;
1718

1819
class RememberMeListenerTest extends \PHPUnit_Framework_TestCase
1920
{
2021
public function testOnCoreSecurityDoesNotTryToPopulateNonEmptySecurityContext()
2122
{
22-
list($listener, $context, $service,,) = $this->getListener();
23+
list($listener, $context,,,,) = $this->getListener();
2324

2425
$context
2526
->expects($this->once())
@@ -99,6 +100,48 @@ public function testOnCoreSecurityIgnoresAuthenticationExceptionThrownByAuthenti
99100
$listener->handle($event);
100101
}
101102

103+
/**
104+
* @expectedException Symfony\Component\Security\Core\Exception\AuthenticationException
105+
* @expectedExceptionMessage Authentication failed.
106+
*/
107+
public function testOnCoreSecurityIgnoresAuthenticationOptionallyRethrowsExceptionThrownAuthenticationManagerImplementation()
108+
{
109+
list($listener, $context, $service, $manager,) = $this->getListener(false, false);
110+
111+
$context
112+
->expects($this->once())
113+
->method('getToken')
114+
->will($this->returnValue(null))
115+
;
116+
117+
$service
118+
->expects($this->once())
119+
->method('autoLogin')
120+
->will($this->returnValue($this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')))
121+
;
122+
123+
$service
124+
->expects($this->once())
125+
->method('loginFail')
126+
;
127+
128+
$exception = new AuthenticationException('Authentication failed.');
129+
$manager
130+
->expects($this->once())
131+
->method('authenticate')
132+
->will($this->throwException($exception))
133+
;
134+
135+
$event = $this->getGetResponseEvent();
136+
$event
137+
->expects($this->once())
138+
->method('getRequest')
139+
->will($this->returnValue(new Request()))
140+
;
141+
142+
$listener->handle($event);
143+
}
144+
102145
public function testOnCoreSecurity()
103146
{
104147
list($listener, $context, $service, $manager,) = $this->getListener();
@@ -138,6 +181,55 @@ public function testOnCoreSecurity()
138181
$listener->handle($event);
139182
}
140183

184+
public function testOnCoreSecurityInteractiveLoginEventIsDispatchedIfDispatcherIsPresent()
185+
{
186+
list($listener, $context, $service, $manager,, $dispatcher) = $this->getListener(true);
187+
188+
$context
189+
->expects($this->once())
190+
->method('getToken')
191+
->will($this->returnValue(null))
192+
;
193+
194+
$token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
195+
$service
196+
->expects($this->once())
197+
->method('autoLogin')
198+
->will($this->returnValue($token))
199+
;
200+
201+
$context
202+
->expects($this->once())
203+
->method('setToken')
204+
->with($this->equalTo($token))
205+
;
206+
207+
$manager
208+
->expects($this->once())
209+
->method('authenticate')
210+
->will($this->returnValue($token))
211+
;
212+
213+
$event = $this->getGetResponseEvent();
214+
$request = new Request();
215+
$event
216+
->expects($this->once())
217+
->method('getRequest')
218+
->will($this->returnValue($request))
219+
;
220+
221+
$dispatcher
222+
->expects($this->once())
223+
->method('dispatch')
224+
->with(
225+
SecurityEvents::INTERACTIVE_LOGIN,
226+
$this->isInstanceOf('Symfony\Component\Security\Http\Event\InteractiveLoginEvent')
227+
)
228+
;
229+
230+
$listener->handle($event);
231+
}
232+
141233
protected function getGetResponseEvent()
142234
{
143235
return $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
@@ -148,16 +240,18 @@ protected function getFilterResponseEvent()
148240
return $this->getMock('Symfony\Component\HttpKernel\Event\FilterResponseEvent', array(), array(), '', false);
149241
}
150242

151-
protected function getListener()
243+
protected function getListener($withDispatcher = false, $catchExceptions = true)
152244
{
153245
$listener = new RememberMeListener(
154246
$context = $this->getContext(),
155247
$service = $this->getService(),
156248
$manager = $this->getManager(),
157-
$logger = $this->getLogger()
249+
$logger = $this->getLogger(),
250+
$dispatcher = ($withDispatcher ? $this->getDispatcher() : null),
251+
$catchExceptions
158252
);
159253

160-
return array($listener, $context, $service, $manager, $logger);
254+
return array($listener, $context, $service, $manager, $logger, $dispatcher);
161255
}
162256

163257
protected function getLogger()
@@ -177,8 +271,11 @@ protected function getService()
177271

178272
protected function getContext()
179273
{
180-
return $this->getMockBuilder('Symfony\Component\Security\Core\SecurityContext')
181-
->disableOriginalConstructor()
182-
->getMock();
274+
return $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
275+
}
276+
277+
protected function getDispatcher()
278+
{
279+
return $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
183280
}
184281
}

0 commit comments

Comments
 (0)