Skip to content

Commit c905bb4

Browse files
committed
bug symfony#58754 [Security] Store original token in token storage when implicitly exiting impersonation (wouterj)
This PR was merged into the 5.4 branch. Discussion ---------- [Security] Store original token in token storage when implicitly exiting impersonation | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | - | License | MIT If you impersonate user A and then start impersonation for user B, Symfony explicitly exits the first impersonation before starting the second one. However, we did not update the token in the token storage at this moment. This creates issues when using a custom voter [like the one documented](https://symfony.com/doc/current/security/impersonating_user.html#limiting-user-switching), as this uses `Security::isGranted()`, which relies on the token in the token storage. So instead of checking if the original user can impersonate, it will check if user A can impersonate. Commits ------- a496ecf [Security] Store original token in token storage when implicitly exiting impersonation
2 parents 5ebc4c3 + a496ecf commit c905bb4

File tree

2 files changed

+8
-2
lines changed

2 files changed

+8
-2
lines changed

src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public function authenticate(RequestEvent $event)
109109
}
110110

111111
if (self::EXIT_VALUE === $username) {
112-
$this->tokenStorage->setToken($this->attemptExitUser($request));
112+
$this->attemptExitUser($request);
113113
} else {
114114
try {
115115
$this->tokenStorage->setToken($this->attemptSwitchUser($request, $username));
@@ -221,6 +221,8 @@ private function attemptExitUser(Request $request): TokenInterface
221221
$original = $switchEvent->getToken();
222222
}
223223

224+
$this->tokenStorage->setToken($original);
225+
224226
return $original;
225227
}
226228

src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Symfony\Component\HttpKernel\HttpKernelInterface;
1919
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
2020
use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
21+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
2122
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
2223
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
2324
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
@@ -228,7 +229,10 @@ public function testSwitchUserAlreadySwitched()
228229

229230
$targetsUser = $this->callback(function ($user) { return 'kuba' === $user->getUserIdentifier(); });
230231
$this->accessDecisionManager->expects($this->once())
231-
->method('decide')->with($originalToken, ['ROLE_ALLOWED_TO_SWITCH'], $targetsUser)
232+
->method('decide')->with(self::callback(function (TokenInterface $token) use ($originalToken, $tokenStorage) {
233+
// the token storage should also contain the original token for voters depending on it
234+
return $token === $originalToken && $tokenStorage->getToken() === $originalToken;
235+
}), ['ROLE_ALLOWED_TO_SWITCH'], $targetsUser)
232236
->willReturn(true);
233237

234238
$this->userChecker->expects($this->once())

0 commit comments

Comments
 (0)