8000 bug #33799 [Security]: Don't let falsy usernames slip through imperso… · symfony/symfony@8622c8c · GitHub
[go: up one dir, main page]

Skip to content

Commit 8622c8c

Browse files
committed
bug #33799 [Security]: Don't let falsy usernames slip through impersonation (j4nr6n)
This PR was merged into the 3.4 branch. Discussion ---------- [Security]: Don't let falsy usernames slip through impersonation | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | | License | MIT | Doc PR | When you try to impersonate users with a falsy username, `SwitchUserListener::handle()` would `return;` and impersonation would fail. I'm using a third party OAuth provider that allows users to change their usernames with no guaranteed protection against re-use. To overcome that issue, I implemented `UserLoaderInterface::loadUserByUsername()` and query by a `providerId`. After loading development fixtures, One user has `0` as it's `providerId`. Commits ------- 64aecab Don't let falsey usernames slip through
2 parents 9adef07 + 64aecab commit 8622c8c

File tree

2 files changed

+35
-2
lines changed

2 files changed

+35
-2
lines changed

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,16 @@ public function __construct(TokenStorageInterface $tokenStorage, UserProviderInt
7777
public function handle(GetResponseEvent $event)
7878
{
7979
$request = $event->getRequest();
80-
$username = $request->get($this->usernameParameter) ?: $request->headers->get($this->usernameParameter);
8180

82-
if (!$username) {
81+
// usernames can be falsy
82+
$username = $request->get($this->usernameParameter);
83+
84+
if (null === $username || '' === $username) {
85+
$username = $request->headers->get($this->usernameParameter);
86+
}
87+
88+
// if it's still "empty", nothing to do.
89+
if (null === $username || '' === $username) {
8390
return;
8491
}
8592

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,32 @@ public function testSwitchUser()
191191
$this->assertInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken', $this->tokenStorage->getToken());
192192
}
193193

194+
public function testSwitchUserWorksWithFalsyUsernames()
195+
{
196+
$token = new UsernamePasswordToken('username', '', 'key', ['ROLE_FOO']);
197+
$user = new User('username', 'password', []);
198+
199+
$this->tokenStorage->setToken($token);
200+
$this->request->query->set('_switch_user', '0');
201+
202+
$this->accessDecisionManager->expects($this->once())
203+
->method('decide')->with($token, ['ROLE_ALLOWED_TO_SWITCH'])
204+
->willReturn(true);
205+
206+
$this->userProvider->expects($this->once())
207+
->method('loadUserByUsername')->with('0')
208+
->willReturn($user);
209+
$this->userChecker->expects($this->once())
210+
->method('checkPostAuth')->with($user);
211+
212+
$listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager);
213+
$listener->handle($this->event);
214+
215+
$this->assertSame([], $this->request->query->all());
216+
$this->assertSame('', $this->request->server->get('QUERY_STRING'));
217+
$this->assertInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken', $this->tokenStorage->getToken());
218+
}
219+
194220
public function testSwitchUserKeepsOtherQueryStringParameters()
195221
{
196222
$token = new UsernamePasswordToken('username', '', 'key', ['ROLE_FOO']);

0 commit comments

Comments
 (0)
0