-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Session][Test] Cannot set session ID after the session has started. #13450
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
Comments
Indeed it doesn't seem to make any difference in case of If a session is started before the previous id is set from a cookie, you'd get a new session on each request, no? |
Indeed, that's another upcoming issue. The data is not migrated and in addition any data accessed from the "new" session is therefore not from the expected source. Even if the listener would migrate, any object that has accessed the session before, would have based its behaviour on the w 8000 rong dataset. I'm getting more and more convinced, that the test session needs a different approach on bootstrapping. The current listener seems not valid, it's far too late. |
@havvg would your issue be fixed if TestSessionListener was triggered earlier? |
Not in sense of "higher listener priority", no. I tried something different, which would work, but it's not a valid solution as it (injecting the id in Kernel::boot, just for the sake of trying it). I'm thinking about a proper solution to achieve this, maybe a factorized service would do the trick, that way the container (and thus the session itself) has immediate access to the correct data. Tricky one, this issue is :) |
In that case, would you mind forking the standard edition, to reproduce this issue? |
Yes, I will create one. |
injecting the id during the boot is wrong. A booted kernel could technically handle several requests, and the session id is tied to a request |
Yes, I know, it was just a proof of concept and easy to "hack in". |
@havvg any news? |
@jakzal Sorry for the delay, I just set up a simplified version of how to produce the issue. |
What's the status? Ran into this today. |
Me too. Any ideas? |
…by swapping out test session class. Also updated PHP deps
@jakzal I'm having the same issue also when running Behat 3. I started getting this exception when I upgraded Symfony from 2.6.4 to 2.6.5. |
I'm also running into this, reverting to 2.6.4 did not help in my case... |
I've discovered that I had a listener subscribed to the However my listener had a priority of -64, so it should have been triggered after the TestSessionListener, right? TestSessionListener has a priority of 192. |
@adamelso would you be able to fork the Symfony SE and isolate this issue on a new branch? |
@jakzal sure, any particular branch I should fork from ? |
The oldest supported branch that you can reproduce this issue on :) |
I'm also suffering this issue in my tests. Any news on the potential fix? Thanks. |
Sadly I haven't had much luck reproducing the issue in either 2.6 or 2.7. The issue I was having was because of a listener that set an object (similar to the I'll still try to reproduce it if I can. |
@javiereguiluz perhaps you could provide a SE fork with this issue reproduced? |
@adamelso Thank you. Finally I found it: I defined a twig globals var in config.yml and I assigned a service. This service had @session as an argument.This caused all the trouble. |
I've also encountered this issue in functional test extending WebTestCase. There is a TestSessionListener class which sets session ID if present in cookies on every master request. public function setId($id)
{
if ($this->started) {
throw new \LogicException('Cannot set session ID after the session has started.');
}
$this->id = $id;
} In this case this call is redundant since the same session ID is already present in the session. I temporarily fixed it by extending MockArraySessionStorage (or MockFileSessionStorage) like this. /**
* {@inheritdoc}
*/
public function setId($id)
{
if ($this->id !== $id) {
parent::setId($id);
}
} It is simpler than extending the TestSessionListener class. But if I understand it correctly then the listener is the place where the condition should be present. Should it be fixed? Should i provide a PR? Have someone already provided a failing test case? |
I'm having this problem with a Behat test that generates a CSRF token during the test steps, as shown below…
Anything else I can do to help this along? |
@maryo Thank you for this fix, we also ran into this problem when we switched to sqlite in-memory db for functional tests, and thus had to call disableReboot() on the client. |
Looking at this same issue, I am wondering if it makes more sense to put the fix in |
@maryo Could you please add more details on your fix? Specifically, where did you add the new function and how did you call it? I'm new to testing in Symfony and having trouble figuring it out.Thank you! |
If you interested, I have worked around this by clearing the session between requests.
This means I didn't have to apply fixes inside the Symfony code. |
@yvoloshin The fixes proposed by @maryo are in the class |
@sbergfeld I have the same issue here. After I've created a twig extension that had @session as an argument, I had the issue. How did you solve that? |
One of my coworkers solved this problem. The config_test.yml had these lines:
Deleting |
Thanks @yvoloshin, I am literally working on this same problem at this exact time. Now fixed thanks to you! |
In my case I was using the @session service in the Twig Extension constructor, like:
The solution was just to store @session and use it later:
Thanks, anyway. |
Im getting this on symfony 3.0.3 with LiipFunctionalTestBundle. Removing "test" entry as @yvoloshin suggested also removed the test client, so it does not solve the problem. |
Anyone have a final solution about this? I tried all but the problem has not fixed. I create my custom file session storage as commented and works, but when I testing my controllers as a functional test the CSRF protection of my form change after submit and I'm thinking this issue cause the problem. Remove test entry it's not an option as @jkobus says and I check all my services who has sessions dependencies and any service access to my session properties in the construct. Thanks! |
Consider disabling csrf in |
@mcfedr Thanks. I did it and with combinations with my "custom" session provider seems it works. Do you know if someone is working to fix this issue or maybe there are not solution and this is the best way by the moment? |
Hi everybody! This work for me: Im doing functionality tests in my Symfony 2.6 app. That test go against routes protected and i need to do the requests with an UsernamePasswordToken setted at the session. -The cookie always have the same id that the session, but that Exception is thrown when the cookie is setted and TestSessionListener check that the cookie have an item with the session name. My solution:
Why it have to set the id again and expose us to get an exception if the session is started? I hope help you! Bye! |
I had randomly the same problem in Symfony 3.2.* during functional tests. Solution presented by @rgarcia-martin didn't work for me, so I made own with following code: <?php
namespace CoreBundle\Event;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\EventListener\TestSessionListener as BaseTestSessionListener;
class TestSessionListener extends BaseTestSessionListener
{
/**
* @var ContainerInterface
*/
protected $container;
/**
* TestRequestListener constructor.
* @param ContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/**
* @return null|SessionInterface
*/
protected function getSession() : ?SessionInterface
{
if (!$this->container->has('session')) {
return null;
}
return $this->container->get('session');
}
/**
* @param GetResponseEvent $event
*/
public function onKernelRequest(GetResponseEvent $event)
{
if (!$event->isMasterRequest()) {
return;
}
// bootstrap the session
$session = $this->getSession();
if (!$session) {
return;
}
$cookies = $event->getRequest()->cookies;
if ($cookies->has($session->getName())) {
if (!$session->isStarted()) {
$session->setId($cookies->get($session->getName()));
}
}
}
} and in config_test.yml : services:
test.session.listener:
class: AppBundle\Event\TestSessionListener
arguments:
- '@service_container'
tags:
- { name: kernel.event_subscriber } Seems it works. |
Hoping this will help someone. I'm using the Liip Functional Test Bundle and was getting this issue. The way I solved it was to save the session before a request was made. Example: $client = $this->makeClient();
$client->getContainer()->get('session')->set('session_key_to_use', 'value_for_key');
$client->getContainer()->get('session')->save(); // This seems to make it work
$crawler = $client->request('GET', '/path/to'); config_test.yml framework:
test: ~
session:
name: MOCKSESSID
storage_id: session.storage.mock_file Symfony Version: 3.4.2 Hope this helps |
Got the same issue with Liip Functional Test Bundle too, and Symfony 4.0. Workaround for my case, inspired from #13450 (comment): use Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage as BaseSessionStorage;
final class MockFileSessionStorage extends BaseSessionStorage
{
public function setId($id)
{
if ($this->id !== $id) {
parent::setId($id);
}
}
} Then on the use App\Tests\TestCase\MockFileSessionStorage;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
class Kernel extends BaseKernel implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
if ('test' === $this->environment) {
$container->getDefinition('session.storage.mock_file')->setClass(MockFileSessionStorage::class);
}
} Work for me. But I'm sure the exception is not here for nothing. :-) What is the state of this issue? |
PR pending if a solution has been identified... |
@nicolas-grekas Well, the issue is we found some workaround, but it seems we don't really know why we have this "big". 😕 |
I ran into the same problem and found that the issue is that I have an event subscriber with a higher priority than Symfony's So what happens is first my listener (priority 2048) calls After that the I've "solved" this for now with a CompilerPass that removes the default tags from $container->getDefinition('test.session.listener')->clearTags();
$container->getDefinition('test.session.listener')->addTag(
'kernel.event_listener',
[
'event' => 'kernel.request',
'method' => 'onKernelRequest',
'priority' => 2049 // priority of my listener + 1
]
);
$container->getDefinition('test.session.listener')->addTag(
'kernel.event_listener',
[
'event' => 'kernel.response',
'method' => 'onKernelResponse',
'priority' => -1000 // same as original, doesn't really matter
]
); Without resorting to gigantic numbers for the priority of Maybe there is a way to retrieve all events subscribed to Or maybe we could pass the |
Disclaimer: just trying stuff blindly, I don't really understand why this works. I do not fully undestand the problem. |
I stumbled upon this problem and may have a fix with #28433. Don't hesitate to try and give your opinion on the PR or here. Thanks! |
…f ID did not change (tgalopin) This PR was merged into the 2.8 branch. Discussion ---------- [HttpFoundation] Allow reuse of Session between requests if ID did not change | Q | A | ------------- | --- | Branch? | 2.8 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #13450 | License | MIT | Doc PR | - I stumbled upon the issue from #13450 in a more simple case than what was exposed in the issue. From my understanding, the problem arises when the session is used between an access to the session and a functional test request: because the session was accessed (usually using the container directly), the session has started and the following request fails. This PR checks whether the ID was actually regenerated before throwing (if a setId is called with the same ID, it is the same request context, it shouldn't throw IMO). Not sure I understood everything correctly though, feel free to fix it for me if needed. Commits ------- fd30f4a Allow reuse of Session between requests
…f ID did not change (tgalopin) This PR was merged into the 2.8 branch. Discussion ---------- [HttpFoundation] Allow reuse of Session between requests if ID did not change | Q | A | ------------- | --- | Branch? | 2.8 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #13450 | License | MIT | Doc PR | - I stumbled upon the issue from symfony/symfony#13450 in a more simple case than what was exposed in the issue. From my understanding, the problem arises when the session is used between an access to the session and a functional test request: because the session was accessed (usually using the container directly), the session has started and the following request fails. This PR checks whether the ID was actually regenerated before throwing (if a setId is called with the same ID, it is the same request context, it shouldn't throw IMO). Not sure I understood everything correctly though, feel free to fix it for me if needed. Commits ------- fd30f4a21d Allow reuse of Session between requests
Hi @sarven and other, This solution works really fine for BrowserKit but I cannot login with Selenium. Any thoughts or ideas why this is happening? Thank you for replying |
@tom10271 did you clear cache for test env? I have to clear cache everytime I run BrowserKit tests and then run Selenium and vise versa. |
Hi there,
the exception is thrown by this line:
https://github.com/symfony/symfony/blob/2.5/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php#L134
My setup works completely fine within a valid PHP environment (without
TestSessionListener
) - data getting stored in the session before theTestSessionListener::onKernelRequest
has been executed (usingMockFileSessionStorage
).What's the intention of this exception? I can't get my head around it. The
TestSessionListener
is explicitly doing this (setId
) and if there is another object accessing the session before theTestSessionListener
sets the id, an id is automatically generated. The listener is not correctly mimicking the session creation of PHP and this exception makes it (for some parts) unusable.If there is no actual use on this exception, it may be removed, no?
The text was updated successfully, but these errors were encountered: