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

Skip to content

[Security] Do not deauthenticate token on user change if not an AbstractToken #42776

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver;
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
Expand Down Expand Up @@ -237,7 +238,7 @@ protected function refreshUser(TokenInterface $token): ?TokenInterface
$newToken->setUser($refreshedUser, false);

// tokens can be deauthenticated if the user has been changed.
if ($this->hasUserChanged($user, $newToken)) {
if ($token instanceof AbstractToken && $this->hasUserChanged($user, $newToken)) {
$userDeauthenticated = true;
// @deprecated since Symfony 5.4
if (method_exists($newToken, 'setAuthenticated')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\UsageTrackingTokenStorage;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
Expand Down Expand Up @@ -233,6 +234,27 @@ public function testIfTokenIsDeauthenticated()
$this->assertNull($tokenStorage->getToken());
}

public function testTokenIsNotDeauthenticatedOnUserChangeIfNotAnInstanceOfAbstractToken()
{
$tokenStorage = new TokenStorage();
$refreshedUser = new InMemoryUser('changed', 'baz');

$token = new CustomToken(new InMemoryUser('original', 'foo'), ['ROLE_FOO']);

$session = new Session(new MockArraySessionStorage());
$session->set('_security_context_key', serialize($token));

$request = new Request();
$request->setSession($session);
$request->cookies->set('MOCKSESSID', true);

$listener = new ContextListener($tokenStorage, [new NotSupportingUserProvider(true), new NotSupportingUserProvider(false), new SupportingUserProvider($refreshedUser)], 'context_key');
$listener(new RequestEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST));

$this->assertInstanceOf(CustomToken::class, $tokenStorage->getToken());
$this->assertSame($refreshedUser, $tokenStorage->getToken()->getUser());
}

public function testIfTokenIsNotDeauthenticated()
{
$tokenStorage = new TokenStorage();
Expand Down Expand Up @@ -523,3 +545,104 @@ public function supportsClass($class): bool
return InMemoryUser::class === $class;
}
}

class CustomToken implements TokenInterface
{
private $user;
private $roles;

public function __construct(UserInterface $user, array $roles)
{
$this->user = $user;
$this->roles = $roles;
}

public function __serialize(): array
{
return [$this->user, $this->roles];
}

public function serialize(): string
{
return serialize($this->__serialize());
}

public function __unserialize(array $data): void
{
[$this->user, $this->roles] = $data;
}

public function unserialize($serialized)
{
$this->__unserialize(\is_array($serialized) ? $serialized : unserialize($serialized));
}

public function __toString(): string
{
return $this->user->getUserIdentifier();
}

public function getRoleNames(): array
{
return $this->roles;
}

public function getCredentials()
{
}

public function getUser(): UserInterface
{
return $this->user;
}

public function setUser($user)
{
$this->user = $user;
}

public function getUsername(): string
{
return $this->user->getUserIdentifier();
}

public function getUserIdentifier(): string
{
return $this->getUserIdentifier();
}

public function isAuthenticated(): bool
{
return true;
}

public function setAuthenticated(bool $isAuthenticated)
{
}

public function eraseCredentials()
{
}

public function getAttributes(): array
{
return [];
}

public function setAttributes(array $attributes)
{
}

public function hasAttribute(string $name): bool
{
return false;
}

public function getAttribute(string $name)
{
}

public function setAttribute(string $name, $value)
{
}
}