10000 bug #37008 [Security] Fixed AbstractToken::hasUserChanged() (wouterj) · symfony/symfony@bdb01db · GitHub
[go: up one dir, main page]

Skip to content

Commit bdb01db

Browse files
bug #37008 [Security] Fixed AbstractToken::hasUserChanged() (wouterj)
This PR was squashed before being merged into the 4.4 branch. Discussion ---------- [Security] Fixed AbstractToken::hasUserChanged() | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | Fix #36989 | License | MIT | Doc PR | - This PR completely reverts #35944. That PR tried to fix a BC break (ref #35941, #35509) introduced by #31177. However, this broke many authentications (ref #36989), as the User is serialized in the session (as hinted by @stof). Many applications don't include the `roles` property in the serialization (at least, the MakerBundle doesn't include it). In 5.2, we should probably deprecate having different roles in token and user, which fixes the BC breaks all together. Commits ------- f297beb [Security] Fixed AbstractToken::hasUserChanged()
2 parents d9506ab + f297beb commit bdb01db

File tree

2 files changed

+71
-3
lines changed

2 files changed

+71
-3
lines changed

src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,10 +317,13 @@ private function hasUserChanged(UserInterface $user): bool
317317
return true;
318318
}
319319

320-
$currentUserRoles = array_map('strval', (array) $this->user->getRoles());
321320
$userRoles = array_map('strval', (array) $user->getRoles());
322321

323-
if (\count($userRoles) !== \count($currentUserRoles) || \count($userRoles) !== \count(array_intersect($userRoles, $currentUserRoles))) {
322+
if ($this instanceof SwitchUserToken) {
323+
$userRoles[] = 'ROLE_PREVIOUS_ADMIN';
324+
}
325+
326+
if (\count($userRoles) !== \count($this->getRoleNames()) || \count($userRoles) !== \count(array_intersect($userRoles, $this->getRoleNames()))) {
324327
return true;
325328
}
326329

src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,13 +238,28 @@ public function getUserChangesAdvancedUser()
238238
*/
239239
public function testSetUserDoesNotSetAuthenticatedToFalseWhenUserDoesNotChange($user)
240240
{
241-
$token = new ConcreteToken(['ROLE_FOO']);
241+
$token = new ConcreteToken();
242+
$token->setAuthenticated(true);
243+
$this->assertTrue($token->isAuthenticated());
244+
245+
$token->setUser($user);
246+
$this->assertTrue($token->isAuthenticated());
247+
248+
$token->setUser($user);
249+
$this->assertTrue($token->isAuthenticated());
250+
}
251+
252+
public function testIsUserChangedWhenSerializing()
253+
{
254+
$token = new ConcreteToken(['ROLE_ADMIN']);
242255
$token->setAuthenticated(true);
243256
$this->assertTrue($token->isAuthenticated());
244257

258+
$user = new SerializableUser('wouter', ['ROLE_ADMIN']);
245259
$token->setUser($user);
246260
$this->assertTrue($token->isAuthenticated());
247261

262+
$token = unserialize(serialize($token));
248263
$token->setUser($user);
249264
$this->assertTrue($token->isAuthenticated());
250265
}
@@ -265,6 +280,56 @@ public function __toString(): string
265280
}
266281
}
267282

283+
class SerializableUser implements UserInterface, \Serializable
284+
{
285+
private $roles;
286+
private $name;
287+
288+
public function __construct($name, array $roles = [])
289+
{
290+
$this->name = $name;
291+
$this->roles = $roles;
292+
}
293+
294+
public function getUsername()
295+
{
296+
return $this->name;
297+
}
298+
299+
public function getPassword()
300+
{
301+
return '***';
302+
}
303+
304+
public function getRoles()
305+
{
306+
if (empty($this->roles)) {
307+
return ['ROLE_USER'];
308+
}
309+
310+
return $this->roles;
311+
}
312+
313+
public function eraseCredentials()
314+
{
315+
}
316+
317+
public function getSalt()
318+
{
319+
return null;
320+
}
321+
322+
public function serialize()
323+
{
324+
return serialize($this->name);
325+
}
326+
327+
public function unserialize($serialized)
328+
{
329+
$this->name = unserialize($serialized);
330+
}
331+
}
332+
268333
class ConcreteToken extends AbstractToken
269334
{
270335
private $credentials = 'credentials_value';

0 commit comments

Comments
 (0)
0