-
Symfony version(s) affected5.4.x DescriptionThis issue is explained by someone else here: https://stackoverflow.com/questions/70669443/symfony-deprecation-on-sessiontokenstorage-when-generating-a-csrf-token-in-phpun I am running into it as well. I realize I could get around it by first requesting the page with the form and using the token from the form, or just using the Any thoughts are greatly appreciated. How to reproducePossible Solutioneither don't deprecate this, or create some workaround for testing environment. Additional ContextNo response |
Beta Was this translation helpful? Give feedback.
Replies: 7 comments 15 replies
-
the answer in the SO post actually seems to work in terms of suppressing the deprecation warning, but it causes the form POST submission to throw a "CSRF Token Invalid" error. |
Beta Was this translation helpful? Give feedback.
-
the other weird bit is that I am getting the token manager after So, if I'm logging in, thereby creating a session, why would the token manager complain that there is no session? |
Beta Was this translation helpful? Give feedback.
-
Thanks for converting this to a discussion @derrabus. I am not sure if this is an actual bug or not, but the more I poke into it, the more I think it might actually be, or that I might be misunderstanding something.
Since
If this is confusing, or unbelievable, I can try to reproduce in a test repo if that would be helpful. My testing thusfar seems like one can simply never retrieve the TokenManager in a functional test, as it will never recognize the client session. Might I be misunderstanding something? Or is it intended that the TokenManager should never be retreivable/used in functional tests? |
Beta Was this translation helpful? Give feedback.
-
One option would be to disable csrf in tests, but this feels like a last resort option to me. I'd like my functional.integration tests to be as close to the real app behavior as possible. |
Beta Was this translation helpful? Give feedback.
-
As I continue researching this, if the behavior is expected, it seems to me that functional test implementers have two options:
The primary assumption being:
I'd love to hear some symfony's dev's chime in to see if I am understanding this correctly. If this is correct, I think it might be worth updating the documentation and deprecation notes to make this explicitly clear. |
Beta Was this translation helpful? Give feedback.
-
I've figured it out. Right now, the solution requires replicating and enhancing the
|
Beta Was this translation helpful? Give feedback.
-
Hello @arderyp. Following my answer to #45662 (comment), I've found a way to get a session from a client and set the CSRF token in it. This allows two things:
I've extracted my code in a trait to be used in all my tests. <?php
namespace App\Tests;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage;
use Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface;
use Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage;
trait SessionHelper
{
public function getSession(KernelBrowser $client): Session
{
$cookie = $client->getCookieJar()->get('MOCKSESSID');
// create a new session object
$container = static::getContainer();
$session = $container->get('session.factory')->createSession();
if ($cookie) {
// get the session id from the session cookie if it exists
$session->setId($cookie->getValue());
$session->start();
} else {
// or create a new session id and a session cookie
$session->start();
$session->save();
$sessionCookie = new Cookie(
$session->getName(),
$session->getId(),
null,
null,
'localhost',
);
$client->getCookieJar()->set($sessionCookie);
}
return $session;
}
public function generateCsrfToken(KernelBrowser $client, string $tokenId): string
{
$session = $this->getSession($client);
$container = static::getContainer();
$tokenGenerator = $container->get('security.csrf.token_generator');
$csrfToken = $tokenGenerator->generateToken();
$session->set(SessionTokenStorage::SESSION_NAMESPACE . "/{$tokenId}", $csrfToken);
$session->save();
return $csrfToken;
}
} It can be used this way: <?php
namespace App\Tests\Controller;
use App\Tests\SessionHelper;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class SessionControllerTest extends WebTestCase
{
use SessionHelper;
public function testSomething(): void
{
$client = static::createClient();
$client->request('POST', '/something', [
'_csrf_token' => $this->generateCsrfToken($client, 'expected token id'),
]);
// assert something
}
} I hope it helps! |
Beta Was this translation helpful? Give feedback.
I've figured it out. Right now, the solution requires replicating and enhancing the
loginUser()
function onKernelBrowser
. I will submit a PR to symfony to make this achievable without needing to do so. Who knows if they will accept it. For now: