-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[HttpKernel] Use the existing session id if available. #45394
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Hey! I think @alexander-schranz has recently worked with this code. Maybe they can help review this? Cheers! Carsonbot |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/cc @alexander-schranz could you please have a look?
src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are currently multiple reasons why we are not calling getId
here or check for an existing session id in the session storage.
The first reason is that we can not be 100% sure that the sessionId was reseted here:
symfony/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php
Line 264 in 44db49f
session_id(''); |
If it is not reseted correctly there
$sess->getId()
could return a previous users session id from a previous requests (off course only in swoole, roadrunner not in traditional php-fpm process, but there it could be critical). So that is why we are not checking for $sess->getId()
instead we do \PHP_SESSION_ACTIVE !== session_status()
to check if a session is already started and then do nothing in that case as a bridge to a legacy application session in a traditional fpm/fastcgi setup.
The second reason is that $sess->getId() will triggering a session id generation and so would generate an unneeded additional session id when a session id is given. Not sure about the whole effects about generating unused session ids but wanted to avoid here. But still calling $sess->setId('');
because of reasons above to be sure the session id is in a reseted state at the start and has no data of previous users requests in it.
@trsteel88 Can you provide more information about your use case? In which cases you run into problem and in which cases no session id is in the cookies and but a session id is but strangely in your case not started?
@nicolas-grekas In general I must say PHP itself is missing one important function about session itself. Why there is session_abort
, session_unset
, session_destroy
, session_reset
, $_SESSION = []
. The only way to remove the session id is currently session_id('');
and only possible before the headers where send so something echo "test";
, var_dump("test");
is already killing that listener. If php would add a function which allows to reset the session variables, id in general after a request is send it would things less flacky / hacky here and we only need todo here:
if ($cookieSessionId) {
$session->setId($cookieSessionId);
}
And so it would only overwrite when a cookie session id is given.
@alexander-schranz I have a multi tenanted application which I'm sharing sessions across multiple domains. A user will login to domain1.com and manage content. Within that same area, they can switch to another site (e.g. domain2.com). When the user switches, we sign a URL and send the original session id to domain2.com. When the user lands on domain2.com, we are calling $session->setId('original-session-id'). The above works fine at the moment. The issue arises when the user already has an active session on domain2.com. e.g. they have logged into domain2.com. The open a new tab and visit domain1.com and login. Now, if they switch from domain1.com to domain2.com, the user lands on the signed URL but we can't use the session ID because the cookie is taking preference. |
@trsteel88 The $request->setSessionFactory(function () use (&$sess, $request) {
if (!$sess) {
$sess = $this->getSession();
/*
* For supporting sessions in php runtime with runners like roadrunner or swoole, the session
* cookie needs to be read from the cookie bag and set on the session storage.
*
* Do not set it when a native php session is active.
*/
if ($sess && !$sess->isStarted() && \PHP_SESSION_ACTIVE !== session_status()) {
$sessionId = $sess->getId() ? $sess->getId() : $request->cookies->get($sess->getName(), '');
$sess->setId($sessionId);
}
}
return $sess;
}); |
The session is not active when I'm calling it. I'm overriding the NativeSessionFactory and have an event that is fired when the createStorage is called. This allows me to then listen to that event elsewhere. In my case, the session has not started yet and that's why the interfering code is overriding my value. |
This works. I'll update the PR. |
Okay some tests are now failing. I need also check what effect this change will have on swoole and roadrunner applications. The |
@alexander-schranz Do you think you will have time to have a look at this one soon? |
@fabpot I will try to have a look at it tomorrow. |
Update here tested roadrunner and swoole and the change seems not have any effects on them. The following patch should fix the tests, I have no permissons to push it: commit 625f2b7e31fa242b515aa0cea13574a68f1d07a5
Author: Alexander Schranz <[email protected]>
Date: Thu Apr 7 01:47:40 2022 +0200
Fix surrogate test cases for session listener
diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/SessionListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/SessionListenerTest.php
index 3bf31bfe68..f0609316b4 100644
--- a/src/Symfony/Component/HttpKernel/Tests/EventListener/SessionListenerTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/SessionListenerTest.php
@@ -522,7 +522,7 @@ class SessionListenerTest extends TestCase
public function testSurrogateMainRequestIsPublic()
{
$session = $this->createMock(Session::class);
- $session->expects($this->exactly(2))->method('getName')->willReturn('PHPSESSID');
+ $session->expects($this->exactly(1))->method('getName')->willReturn('PHPSESSID');
$session->expects($this->exactly(4))->method('getUsageIndex')->will($this->onConsecutiveCalls(0, 1, 1, 1));
$container = new Container();
@@ -562,7 +562,7 @@ class SessionListenerTest extends TestCase
public function testGetSessionIsCalledOnce()
{
$session = $this->createMock(Session::class);
- $session->expects($this->exactly(2))->method('getName')->willReturn('PHPSESSID');
+ $session->expects($this->exactly(1))->method('getName')->willReturn('PHPSESSID');
$sessionStorage = $this->createMock(NativeSessionStorage::class);
$kernel = $this->createMock(KernelInterface::class); |
Updated @alexander-schranz |
Thank you @trsteel88. |
Hi, I'm on SF 5.4.8 and it seems this PR has changed a behavior during PHPUnit tests. public function testCountUserUnreadConversations()
{
$user = $this->em->getRepository(User::class)->findOneByEmail('[email protected]');
// Not logued
$this->client->request('GET', '/user/count-unread-conversations', [], [], ['HTTP_X-Requested-With' => 'XMLHttpRequest']);
$this->assertFalse($this->client->getResponse()->isSuccessful());
// No Ajax
$this->setLoggedClient($user);
$this->client->request('GET', '/user/count-unread-conversations');
$this->assertFalse($this->client->getResponse()->isSuccessful());
// Ok
$this->client->request('GET', '/user/count-unread-conversations', [], [], ['HTTP_X-Requested-With' => 'XMLHttpRequest']);
$this->assertTrue($this->client->getResponse()->isSuccessful());
...
} If was successful in previous versions but since 5.4.8, the last assertion fails, the The protected function setLoggedClient(User $user)
{
$this->client->loginUser($user, 'primary_auth');
} I'll create a bug report and a reproducer, unless you may have an idea of what's happening? Thanks! |
Session id is being overwritten by listener even if it is already set.
I have an application that is overriding the session id when the session factory creates the session. However, when this listener runs, it's overriding the session id that has already been set.