Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1564985

Browse files
committed
[Security] Allow switching to another user when already switched
1 parent b3b368b commit 1564985

File tree

4 files changed

+40
-7
lines changed

4 files changed

+40
-7
lines changed

src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ public function testSwitchUser($originalUser, $targetUser, $expectedUser, $expec
2929
$this->assertEquals($expectedUser, $client->getProfile()->getCollector('security')->getUser());
3030
}
3131

32-
public function testSwitchedUserCannotSwitchToOther()
32+
public function testSwitchedUserCanSwitchToOther()
3333
{
3434
$client = $this->createAuthenticatedClient('user_can_switch');
3535

3636
$client->request('GET', '/profile?_switch_user=user_cannot_switch_1');
3737
$client->request('GET', '/profile?_switch_user=user_cannot_switch_2');
3838

39-
$this->assertEquals(500, $client->getResponse()->getStatusCode());
40-
$this->assertEquals('user_cannot_switch_1', $client->getProfile()->getCollector('security')->getUser());
39+
$this->assertEquals(200, $client->getResponse()->getStatusCode());
40+
$this->assertEquals('user_cannot_switch_2', $client->getProfile()->getCollector('security')->getUser());
4141
}
4242

4343
public function testSwitchedUserExit()

src/Symfony/Component/Security/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
-----
66

77
* Added access decision strategy to override access decisions by voter service priority
8+
* Added `bool $allowAlreadySwitched` argument to the `SwitchUserListener` constructor (default `false`)
89

910
5.0.0
1011
-----

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class SwitchUserListener extends AbstractListener
5151
private $logger;
5252
private $dispatcher;
5353
private $stateless;
54+
private $allowAlreadySwitched;
5455

5556
public function __construct(TokenStorageInterface $tokenStorage, UserProviderInterface $provider, UserCheckerInterface $userChecker, string $providerKey, AccessDecisionManagerInterface $accessDecisionManager, LoggerInterface $logger = null, string $usernameParameter = '_switch_user', string $role = 'ROLE_ALLOWED_TO_SWITCH', EventDispatcherInterface $dispatcher = null, bool $stateless = false)
5657
{
@@ -94,8 +95,6 @@ public function supports(Request $request): ?bool
9495

9596
/**
9697
* Handles the switch to another user.
97-
*
98-
* @throws \LogicException if switching to a user failed
9998
*/
10099
public function authenticate(RequestEvent $event)
101100
{
@@ -131,7 +130,6 @@ public function authenticate(RequestEvent $event)
131130
/**
132131
* Attempts to switch to another user and returns the new token if successfully switched.
133132
*
134-
* @throws \LogicException
135133
* @throws AccessDeniedException
136134
*/
137135
private function attemptSwitchUser(Request $request, string $username): ?TokenInterface
@@ -144,7 +142,8 @@ private function attemptSwitchUser(Request $request, string $username): ?TokenIn
144142
return $token;
145143
}
146144

147-
throw new \LogicException(sprintf('You are already switched to "%s" user.', $token->getUsername()));
145+
// User already switched, exit before seamlessly switching to another user
146+
$token = $this->attemptExitUser($request);
148147
}
149148

150149
$currentUsername = $token->getUsername();

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,39 @@ public function testSwitchUser()
223223
$this->assertInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken', $this->tokenStorage->getToken());
224224
}
225225

226+
public function testSwitchUserAlreadySwitched()
227+
{
228+
$originalToken = new UsernamePasswordToken('original', null, 'key', ['ROLE_FOO']);
229+
$alreadySwitchedToken = new SwitchUserToken('switched_1', null, 'key', ['ROLE_BAR'], $originalToken);
230+
231+
$tokenStorage = new TokenStorage();
232+
$tokenStorage->setToken($alreadySwitchedToken);
233+
234+
$targetUser = new User('kuba', 'password', ['ROLE_FOO', 'ROLE_BAR']);
235+
236+
$this->request->query->set('_switch_user', 'kuba');
237+
238+
$this->accessDecisionManager->expects($this->once())
239+
->method('decide')->with($originalToken, ['ROLE_ALLOWED_TO_SWITCH'], $targetUser)
240+
->willReturn(true);
241+
242+
$this->userProvider->expects($this->exactly(2))
243+
->method('loadUserByUsername')
244+
->withConsecutive(['kuba'])
245+
->will($this->onConsecutiveCalls($targetUser, $this->throwException(new UsernameNotFoundException())));
246+
$this->userChecker->expects($this->once())
247+
->method('checkPostAuth')->with($targetUser);
248+
249+
$listener = new SwitchUserListener($tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager, null, '_switch_user', 'ROLE_ALLOWED_TO_SWITCH', null, false, true);
250+
$listener($this->event);
251+
252+
$this->assertSame([], $this->request->query->all());
253+
$this->assertSame('', $this->request->server->get('QUERY_STRING'));
254+
$this->assertInstanceOf(SwitchUserToken::class, $tokenStorage->getToken());
255+
$this->assertSame('kuba', $tokenStorage->getToken()->getUsername());
256+
$this->assertSame($originalToken, $tokenStorage->getToken()->getOriginalToken());
257+
}
258+
226259
public function testSwitchUserWorksWithFalsyUsernames()
227260
{
228261
$token = new UsernamePasswordToken('username', '', 'key', ['ROLE_FOO']);

0 commit comments

Comments
 (0)