feature #40785 [Security] Deprecate using UsageTrackingTokenStorage outside the request-response cycle (wouterj)
This PR was merged into the 5.3-dev branch.
Discussion
----------
[Security] Deprecate using UsageTrackingTokenStorage outside the request-response cycle
| Q | A
| ------------- | ---
| Branch? | 5.x
| Bug fix? | yes
| New feature? | no
| Deprecations? | yes
| Tickets | Fix #40778
| License | MIT
| Doc PR | -
Currently, you get an "There is currently no session available" exception when using the `security.token_storage` service outside the main request-response cycle (e.g. in a `kernel.terminate` listener). This PR deprecates such usage and requires developers to update their definitions to explicitly use `security.untracked_token_storage` instead.
A different solution would be to silently disable tracking in these cases, but I think that might create some unnecessary technical debt.
Commits
-------
7452476156
[Security] Fix UsageTrackingTokenStorage outside the request cycle
This commit is contained in:
commit
64cc54835d
@ -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.
|
||||
|
@ -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
|
||||
|
@ -39,7 +39,7 @@ final class UsageTrackingTokenStorage implements TokenStorageInterface, ServiceS
|
||||
*/
|
||||
public function getToken(): ?TokenInterface
|
||||
{
|
||||
if ($this->enableUsageTracking) {
|
||||
if ($this->shouldTrackUsage()) {
|
||||
// increments the internal session usage index
|
||||
$this->getSession()->getMetadataBag();
|
||||
}
|
||||
@ -54,7 +54,7 @@ final class UsageTrackingTokenStorage implements TokenStorageInterface, ServiceS
|
||||
{
|
||||
$this->storage->setToken($token);
|
||||
|
||||
if ($token && $this->enableUsageTracking) {
|
||||
if ($token && $this->shouldTrackUsage()) {
|
||||
// increments the internal session usage index
|
||||
$this->getSession()->getMetadataBag();
|
||||
}
|
||||
@ -88,4 +88,24 @@ final class UsageTrackingTokenStorage implements TokenStorageInterface, ServiceS
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -13,31 +13,37 @@ namespace Symfony\Component\Security\Core\Tests\Authentication\Token\Storage;
|
||||
|
||||
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 {
|
||||
@ -62,4 +68,22 @@ class UsageTrackingTokenStorageTest extends TestCase
|
||||
$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();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user