bug #13466 [Security] Remove ContextListener's onKernelResponse listener as it is used (davedevelopment)

This PR was squashed before being merged into the 2.3 branch (closes #13466).

Discussion
----------

[Security] Remove ContextListener's onKernelResponse listener as it is used

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets |
| License       | MIT
| Doc PR        |

The context listeners are specific to a particular firewall, and as such, should not be applied if the current request doesn't match that context listener. To avoid this, the context listener can remove itself from the dispatcher as it is called.

This comes in to affect when two or more firewalls are setup and using the same kernel for multiple requests.  Assuming there are two firewalls 'site' and 'admin'

- Request comes in matching 'site' firewall, 'site' ContextListener adds it's onKernelResponse method to the dispatcher
- Succesful auth for 'site'
- ContextListener writes token to session
- Request comes in matching 'admin' firewall, 'admin' ContextListener can't find anything in the session, so nulls the token in the security context
- 'site' ContextListener listens for response, can't find a token in the security context so removes the 'site' token from the session

Commits
-------

380d805 [Security] Remove ContextListener's onKernelResponse listener as it is used
This commit is contained in:
Fabien Potencier 2015-02-05 11:02:25 +01:00
commit d9c0c55ace
2 changed files with 36 additions and 3 deletions

View File

@ -114,6 +114,9 @@ class ContextListener implements ListenerInterface
return;
}
$this->dispatcher->removeListener(KernelEvents::RESPONSE, array($this, 'onKernelResponse'));
$this->registered = false;
if (null !== $this->logger) {
$this->logger->debug('Write SecurityContext in the session');
}

View File

@ -21,6 +21,7 @@ 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;
use Symfony\Component\EventDispatcher\EventDispatcher;
class ContextListenerTest extends \PHPUnit_Framework_TestCase
{
@ -111,7 +112,7 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase
new Response()
);
$listener = new ContextListener($this->securityContext, array(), 'session');
$listener = new ContextListener($this->securityContext, array(), 'session', null, new EventDispatcher());
$listener->onKernelResponse($event);
$this->assertTrue($session->isStarted());
@ -130,7 +131,7 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase
new Response()
);
$listener = new ContextListener($this->securityContext, array(), 'session');
$listener = new ContextListener($this->securityContext, array(), 'session', null, new EventDispatcher());
$listener->onKernelResponse($event);
$this->assertFalse($session->isStarted());
@ -202,6 +203,35 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase
$listener->handle($event);
}
public function testOnKernelResponseListenerRemovesItself()
{
$context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
$dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
$event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\FilterResponseEvent')
->disableOriginalConstructor()
->getMock();
$listener = new ContextListener($context, array(), 'key123', null, $dispatcher);
$request = $this->getMock('Symfony\Component\HttpFoundation\Request');
$request->expects($this->any())
->method('hasSession')
->will($this->returnValue(true));
$event->expects($this->any())
->method('getRequestType')
->will($this->returnValue(HttpKernelInterface::MASTER_REQUEST));
$event->expects($this->any())
->method('getRequest')
->will($this->returnValue($request));
$dispatcher->expects($this->once())
->method('removeListener')
->with(KernelEvents::RESPONSE, array($listener, 'onKernelResponse'));
$listener->onKernelResponse($event);
}
public function testHandleRemovesTokenIfNoPreviousSessionWasFound()
{
$request = $this->getMock('Symfony\Component\HttpFoundation\Request');
@ -240,7 +270,7 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase
new Response()
);
$listener = new ContextListener($this->securityContext, array(), 'session');
$listener = new ContextListener($this->securityContext, array(), 'session', null, new EventDispatcher());
$listener->onKernelResponse($event);
return $session;