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

Skip to content

Commit 1e3f9b2

Browse files
committed
[Security] Fixed SwitchUserListener when exiting an impersonication with AnonymousToken
If you configure a firewall with switch user with `role: IS_AUTHENTICATED_ANONYMOUSLY` it's impossible to exit the impersonation because the next line `$this->provider->refreshUser($original->getUser())` will fail. It fails because `RefreshUser` expects an instance of `UserInterface` and here it's a string. Therefore, it does not make sense to refresh an Anonymous Token, right ?
1 parent 1314365 commit 1e3f9b2

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
1515
use Symfony\Component\Security\Core\SecurityContextInterface;
16+
use Symfony\Component\Security\Core\User\UserInterface;
1617
use Symfony\Component\Security\Core\User\UserProviderInterface;
1718
use Symfony\Component\Security\Core\User\UserCheckerInterface;
1819
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
@@ -162,7 +163,7 @@ private function attemptExitUser(Request $request)
162163
throw new AuthenticationCredentialsNotFoundException('Could not find original Token object.');
163164
}
164165

165-
if (null !== $this->dispatcher) {
166+
if (null !== $this->dispatcher && $original->getUser() instanceof UserInterface) {
166167
$user = $this->provider->refreshUser($original->getUser());
167168
$switchEvent = new SwitchUserEvent($request, $user);
168169
$this->dispatcher->dispatch(SecurityEvents::SWITCH_USER, $switchEvent);

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

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,54 @@ public function testExitUserDispatchesEventWithRefreshedUser()
149149
$listener->handle($this->event);
150150
}
151151

152+
public function testExitUserDontDispatchesEventWithStringUser()
153+
{
154+
$originalUser = 'anon.';
155+
$refreshedUser = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
156+
$this
157+
->userProvider
158+
->expects($this->never())
159+
->method('refreshUser');
160+
$originalToken = $this->getToken();
161+
$originalToken
162+
->expects($this->any())
163+
->method('getUser')
164+
->willReturn($originalUser);
165+
$role = $this
166+
->getMockBuilder('Symfony\Component\Security\Core\Role\SwitchUserRole')
167+
->disableOriginalConstructor()
168+
->getMock();
169+
$role
170+
->expects($this->any())
171+
->method('getSource')
172+
->willReturn($originalToken);
173+
$this
174+
->securityContext
175+
->expects($this->any())
176+
->method('getToken')
177+
->willReturn($this->getToken(array($role)));
178+
$this
179+
->request
180+
->expects($this->any())
181+
->method('get')
182+
->with('_switch_user')
183+
->willReturn('_exit');
184+
$this
185+
->request
186+
->expects($this->any())
187+
->method('getUri')
188+
->willReturn('/');
189+
190+
$dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
191+
$dispatcher
192+
->expects($this->never())
193+
->method('dispatch')
194+
;
195+
196+
$listener = new SwitchUserListener($this->securityContext, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager, null, '_switch_user', 'ROLE_ALLOWED_TO_SWITCH', $dispatcher);
197+
$listener->handle($this->event);
198+
}
199+
152200
/**
153201
* @expectedException \Symfony\Component\Security\Core\Exception\AccessDeniedException
154202
*/

0 commit comments

Comments
 (0)