Skip to content

Commit

Permalink
bug #26157 [HttpKernel] Send new session cookie from AbstractTestSess…
Browse files Browse the repository at this point in the history
…ionListener after session invalidation (rpkamp)

This PR was merged into the 3.4 branch.

Discussion
----------

[HttpKernel] Send new session cookie from AbstractTestSessionListener after session invalidation

When we call `\Symfony\Component\HttpFoundation\Session\Session::invalidate` the session will be emptied and given a new ID, however, since it is empty this `AbstractTestSessionListener` will not send a new cookie to the user, so the user is not caught up to the latest session ID and will re-generate a session with the old session ID on a new visit.
Thus, we the sessionID has changed during a request we must always send a new cookie with the new sessionID, even though the session is empty.

This behaviour is also what is shown in production (non-test) mode.

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | N/A
| License       | MIT

Commits
-------

98f5d53 [HttpKernel] Send new session cookie from AbstractTestSessionListener after session invalidation
  • Loading branch information
nicolas-grekas committed Feb 19, 2018
2 parents 3ab3b44 + 98f5d53 commit b3c7ba7
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 2 deletions.
Expand Up @@ -29,6 +29,8 @@
*/
abstract class AbstractTestSessionListener implements EventSubscriberInterface
{
private $sessionId;

public function onKernelRequest(GetResponseEvent $event)
{
if (!$event->isMasterRequest()) {
Expand All @@ -44,7 +46,8 @@ public function onKernelRequest(GetResponseEvent $event)
$cookies = $event->getRequest()->cookies;

if ($cookies->has($session->getName())) {
$session->setId($cookies->get($session->getName()));
$this->sessionId = $cookies->get($session->getName());
$session->setId($this->sessionId);
}
}

Expand All @@ -66,9 +69,10 @@ public function onKernelResponse(FilterResponseEvent $event)
$session->save();
}

if ($session instanceof Session ? !$session->isEmpty() : $wasStarted) {
if ($session instanceof Session ? !$session->isEmpty() || $session->getId() !== $this->sessionId : $wasStarted) {
$params = session_get_cookie_params();
$event->getResponse()->headers->setCookie(new Cookie($session->getName(), $session->getId(), 0 === $params['lifetime'] ? 0 : time() + $params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly']));
$this->sessionId = $session->getId();
}
}

Expand Down
Expand Up @@ -13,8 +13,10 @@

use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\EventListener\SessionListener;
Expand Down Expand Up @@ -86,6 +88,22 @@ public function testEmptySessionDoesNotSendCookie()
$this->assertSame(array(), $response->headers->getCookies());
}

public function testEmptySessionWithNewSessionIdDoesSendCookie()
{
$this->sessionHasBeenStarted();
$this->sessionIsEmpty();
$this->fixSessionId('456');

$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
$request = Request::create('/', 'GET', array(), array(new Cookie('MOCKSESSID', '123')));
$event = new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
$this->listener->onKernelRequest($event);

$response = $this->filterResponse(new Request(), HttpKernelInterface::MASTER_REQUEST);

$this->assertNotEmpty($response->headers->getCookies());
}

public function testUnstartedSessionIsNotSave()
{
$this->sessionHasNotBeenStarted();
Expand Down Expand Up @@ -150,6 +168,13 @@ private function sessionIsEmpty()
->will($this->returnValue(true));
}

private function fixSessionId($sessionId)
{
$this->session->expects($this->any())
->method('getId')
->will($this->returnValue($sessionId));
}

private function getSession()
{
$mock = $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\Session')
Expand Down

0 comments on commit b3c7ba7

Please sign in to comment.