Skip to content

[Security] Deprecate using UsageTrackingTokenStorage outside the request-response cycle #40785

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions UPGRADE-5.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ Routing
Security
--------

* Deprecate using `UsageTrackingTokenStorage` with tracking enabled without a main request. Use the untracked token
storage (service ID: `security.untracked_token_storage`) instead, or disable usage tracking
completely using `UsageTrackingTokenStorage::disableUsageTracking()`.
* [BC BREAK] Remove method `checkIfCompletelyResolved()` from `PassportInterface`, checking that passport badges are
resolved is up to `AuthenticatorManager`
* Deprecate class `User`, use `InMemoryUser` or your own implementation instead.
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/Security/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ CHANGELOG
* Add `LegacyPasswordAuthenticatedUserInterface` for user classes that use user-provided salts in addition to passwords
* Deprecate all classes in the `Core\Encoder\` sub-namespace, use the `PasswordHasher` component instead
* Deprecate the `SessionInterface $session` constructor argument of `SessionTokenStorage`, inject a `\Symfony\Component\HttpFoundation\RequestStack $requestStack` instead
* Deprecate using `UsageTrackingTokenStorage` without a main request
* Deprecate the `session` service provided by the ServiceLocator injected in `UsageTrackingTokenStorage`, provide a `request_stack` service instead
* Deprecate using `SessionTokenStorage` outside a request context, it will throw a `SessionNotFoundException` in Symfony 6.0
* Randomize CSRF tokens to harden BREACH attacks
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public function __construct(TokenStorageInterface $storage, ContainerInterface $
*/
public function getToken(): ?TokenInterface
{
if ($this->enableUsageTracking) {
if ($this->shouldTrackUsage()) {
// increments the internal session usage index
$this->getSession()->getMetadataBag();
}
Expand All @@ -54,7 +54,7 @@ public function setToken(TokenInterface $token = null): void
{
$this->storage->setToken($token);

if ($token && $this->enableUsageTracking) {
if ($token && $this->shouldTrackUsage()) {
// increments the internal session usage index
$this->getSession()->getMetadataBag();
}
Expand Down Expand Up @@ -88,4 +88,24 @@ private function getSession(): SessionInterface

return $this->container->get('request_stack')->getSession();
}

private function shouldTrackUsage(): bool
{
if (!$this->enableUsageTracking) {
return false;
}

// BC for symfony/security-bundle < 5.3
if ($this->container->has('session')) {
return true;
}

if (!$this->container->get('request_stack')->getMainRequest()) {
trigger_deprecation('symfony/security-core', '5.3', 'Using "%s" (service ID: "security.token_storage") outside the request-response cycle is deprecated, use the "%s" class (service ID: "security.untracked_token_storage") instead or disable usage tracking using "disableUsageTracking()".', __CLASS__, TokenStorage::class);

return false;
}

return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,37 @@

use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface;
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Authentication\Token\NullToken;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Core\Authentication\Token\Storage\UsageTrackingTokenStorage;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Contracts\Service\ServiceLocatorTrait;

class UsageTrackingTokenStorageTest extends TestCase
{
use ExpectDeprecationTrait;

public function testGetSetToken()
{
$sessionAccess = 0;
$sessionLocator = new class(['request_stack' => function () use (&$sessionAccess) {
++$sessionAccess;

$session = $this->createMock(SessionInterface::class);
$session->expects($this->once())
->method('getMetadataBag');

$request = new Request();
$request->setSession($session);
$requestStack = new RequestStack();
$requestStack = $this->getMockBuilder(RequestStack::class)->setMethods(['getSession'])->getMock();
$requestStack->push($request);
$requestStack->expects($this->any())->method('getSession')->willReturnCallback(function () use ($session, &$sessionAccess) {
++$sessionAccess;

$session->expects($this->once())
->method('getMetadataBag');

return $session;
});

return $requestStack;
}]) implements ContainerInterface {
Expand All @@ -62,4 +68,22 @@ public function testGetSetToken()
$this->assertSame($token, $trackingStorage->getToken());
$this->assertSame(1, $sessionAccess);
}

/**
* @group legacy
*/
public function testWithoutMainRequest()
{
$locator = new class(['request_stack' => function () {
return new RequestStack();
}]) implements ContainerInterface {
use ServiceLocatorTrait;
};
$tokenStorage = new TokenStorage();
$trackingStorage = new UsageTrackingTokenStorage($tokenStorage, $locator);
$trackingStorage->enableUsageTracking();

$this->expectDeprecation('Since symfony/security-core 5.3: Using "%s" (service ID: "security.token_storage") outside the request-response cycle is deprecated, use the "%s" class (service ID: "security.untracked_token_storage") instead or disable usage tracking using "disableUsageTracking()".');
$trackingStorage->getToken();
}
}