[Security] Fix BC layer

This commit is contained in:
Robin Chalas 2021-03-16 21:07:52 +01:00
parent db87d72869
commit 2d7f7b5072
7 changed files with 58 additions and 110 deletions

View File

@ -12,8 +12,8 @@
namespace Symfony\Bundle\SecurityBundle\Tests\Functional; namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\User\InMemoryUser;
use Symfony\Component\Security\Core\User\InMemoryUserProvider; use Symfony\Component\Security\Core\User\InMemoryUserProvider;
use Symfony\Component\Security\Core\User\User;
use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Core\User\UserProviderInterface;
@ -73,7 +73,7 @@ class RememberMeUserProvider implements UserProviderInterface
{ {
$user = $this->inner->refreshUser($user); $user = $this->inner->refreshUser($user);
$alterUser = \Closure::bind(function (InMemoryUser $user) { $user->password = 'foo'; }, null, InMemoryUser::class); $alterUser = \Closure::bind(function (User $user) { $user->password = 'foo'; }, null, User::class);
$alterUser($user); $alterUser($user);
return $user; return $user;

View File

@ -19,6 +19,7 @@ use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasher;
use Symfony\Component\PasswordHasher\PasswordHasherInterface; use Symfony\Component\PasswordHasher\PasswordHasherInterface;
use Symfony\Component\Security\Core\User\InMemoryUser; use Symfony\Component\Security\Core\User\InMemoryUser;
use Symfony\Component\Security\Core\User\LegacyPasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\LegacyPasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\User;
use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserInterface;
class UserPasswordHasherTest extends TestCase class UserPasswordHasherTest extends TestCase
@ -121,7 +122,7 @@ class UserPasswordHasherTest extends TestCase
$passwordHasher = new UserPasswordHasher($mockPasswordHasherFactory); $passwordHasher = new UserPasswordHasher($mockPasswordHasherFactory);
\Closure::bind(function () use ($passwordHasher) { $this->password = $passwordHasher->hashPassword($this, 'foo', 'salt'); }, $user, InMemoryUser::class)(); \Closure::bind(function () use ($passwordHasher) { $this->password = $passwordHasher->hashPassword($this, 'foo', 'salt'); }, $user, User::class)();
$this->assertFalse($passwordHasher->needsRehash($user)); $this->assertFalse($passwordHasher->needsRehash($user));
$this->assertTrue($passwordHasher->needsRehash($user)); $this->assertTrue($passwordHasher->needsRehash($user));
$this->assertFalse($passwordHasher->needsRehash($user)); $this->assertFalse($passwordHasher->needsRehash($user));

View File

@ -74,7 +74,7 @@ class InMemoryUserProviderTest extends TestCase
public function testCreateUser() public function testCreateUser()
{ {
$provider = new InMemoryUserProvider(); $provider = new InMemoryUserProvider();
$provider->createUser(new User('fabien', 'foo')); $provider->createUser(new InMemoryUser('fabien', 'foo'));
$user = $provider->loadUserByUsername('fabien'); $user = $provider->loadUserByUsername('fabien');
$this->assertEquals('foo', $user->getPassword()); $this->assertEquals('foo', $user->getPassword());
@ -84,8 +84,8 @@ class InMemoryUserProviderTest extends TestCase
{ {
$this->expectException(\LogicException::class); $this->expectException(\LogicException::class);
$provider = new InMemoryUserProvider(); $provider = new InMemoryUserProvider();
$provider->createUser(new User('fabien', 'foo')); $provider->createUser(new InMemoryUser('fabien', 'foo'));
$provider->createUser(new User('fabien', 'foo')); $provider->createUser(new InMemoryUser('fabien', 'foo'));
} }
public function testLoadUserByUsernameDoesNotExist() public function testLoadUserByUsernameDoesNotExist()

View File

@ -19,115 +19,58 @@ namespace Symfony\Component\Security\Core\User;
* @author Robin Chalas <robin.chalas@gmail.com> * @author Robin Chalas <robin.chalas@gmail.com>
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*/ */
final class InMemoryUser implements UserInterface, PasswordAuthenticatedUserInterface, EquatableInterface final class InMemoryUser extends User
{ {
private $username;
private $password;
private $enabled;
private $roles;
/**
* @param string[] $roles
*/
public function __construct(string $username, ?string $password, array $roles = [], bool $enabled = true)
{
if ('' === $username) {
throw new \InvalidArgumentException('The username cannot be empty.');
}
$this->username = $username;
$this->password = $password;
$this->roles = $roles;
$this->enabled = $enabled;
}
public function __toString(): string
{
return $this->getUsername();
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/
public function getRoles(): array
{
return $this->roles;
}
/**
* {@inheritdoc}
*/
public function getPassword(): ?string
{
return $this->password;
}
/**
* {@inheritdoc}
*/
public function getSalt(): ?string
{
return null;
}
/**
* {@inheritdoc}
*/
public function getUsername(): string
{
return $this->username;
}
/**
* Checks whether the user is enabled.
* *
* Internally, if this method returns false, the authentication system * @deprecated since Symfony 5.3
* will throw a DisabledException and prevent login.
*
* @return bool true if the user is enabled, false otherwise
*
* @see DisabledException
*/ */
public function isEnabled(): bool public function isAccountNonExpired(): bool
{ {
return $this->enabled; trigger_deprecation('symfony/security-core', '5.3', 'Method "%s()" is deprecated, you should stop using it.', __METHOD__);
return parent::isAccountNonExpired();
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @deprecated since Symfony 5.3
*/ */
public function eraseCredentials() public function isAccountNonLocked(): bool
{ {
trigger_deprecation('symfony/security-core', '5.3', 'Method "%s()" is deprecated, you should stop using it.', __METHOD__);
return parent::isAccountNonLocked();
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @deprecated since Symfony 5.3
*/ */
public function isEqualTo(UserInterface $user): bool public function isCredentialsNonExpired(): bool
{ {
if (!$user instanceof self) { trigger_deprecation('symfony/security-core', '5.3', 'Method "%s()" is deprecated, you should stop using it.', __METHOD__);
return false;
}
if ($this->getPassword() !== $user->getPassword()) { return parent::isCredentialsNonExpired();
return false; }
}
$currentRoles = array_map('strval', (array) $this->getRoles()); /**
$newRoles = array_map('strval', (array) $user->getRoles()); * @deprecated since Symfony 5.3
$rolesChanged = \count($currentRoles) !== \count($newRoles) || \count($currentRoles) !== \count(array_intersect($currentRoles, $newRoles)); */
if ($rolesChanged) { public function getExtraFields(): array
return false; {
} trigger_deprecation('symfony/security-core', '5.3', 'Method "%s()" is deprecated, you should stop using it.', __METHOD__);
if ($this->getUsername() !== $user->getUsername()) { return parent::getExtraFields();
return false; }
}
if ($this->isEnabled() !== $user->isEnabled()) { public function setPassword(string $password)
return false; {
} trigger_deprecation('symfony/security-core', '5.3', 'Method "%s()" is deprecated, you should stop using it.', __METHOD__);
return true; parent::setPassword($password);
} }
} }

View File

@ -38,7 +38,7 @@ class InMemoryUserChecker implements UserCheckerInterface
} }
// @deprecated since Symfony 5.3 // @deprecated since Symfony 5.3
if ($user instanceof User) { if (User::class === \get_class($user)) {
if (!$user->isAccountNonLocked()) { if (!$user->isAccountNonLocked()) {
$ex = new LockedException('User account is locked.'); $ex = new LockedException('User account is locked.');
$ex->setUser($user); $ex->setUser($user);
@ -56,7 +56,7 @@ class InMemoryUserChecker implements UserCheckerInterface
public function checkPostAuth(UserInterface $user) public function checkPostAuth(UserInterface $user)
{ {
// @deprecated since Symfony 5.3, noop in 6.0 // @deprecated since Symfony 5.3, noop in 6.0
if (!$user instanceof User) { if (User::class !== \get_class($user)) {
return; return;
} }

View File

@ -80,8 +80,8 @@ class InMemoryUserProvider implements UserProviderInterface
$storedUser = $this->getUser($user->getUsername()); $storedUser = $this->getUser($user->getUsername());
// @deprecated since Symfony 5.3 // @deprecated since Symfony 5.3
if ($user instanceof User) { if (User::class === \get_class($user)) {
if (!$storedUser instanceof User) { if (User::class !== \get_class($storedUser)) {
$accountNonExpired = true; $accountNonExpired = true;
$credentialsNonExpired = $storedUser->getPassword() === $user->getPassword(); $credentialsNonExpired = $storedUser->getPassword() === $user->getPassword();
$accountNonLocked = true; $accountNonLocked = true;

View File

@ -11,8 +11,6 @@
namespace Symfony\Component\Security\Core\User; namespace Symfony\Component\Security\Core\User;
trigger_deprecation('symfony/security-core', '5.3', 'The "%s" class is deprecated, use "%s" instead.', User::class, InMemoryUser::class);
/** /**
* User is the user implementation used by the in-memory user provider. * User is the user implementation used by the in-memory user provider.
* *
@ -22,7 +20,7 @@ trigger_deprecation('symfony/security-core', '5.3', 'The "%s" class is deprecate
* *
* @deprecated since Symfony 5.3, use {@link InMemoryUser} instead * @deprecated since Symfony 5.3, use {@link InMemoryUser} instead
*/ */
final class User implements UserInterface, PasswordAuthenticatedUserInterface, EquatableInterface class User implements UserInterface, PasswordAuthenticatedUserInterface, EquatableInterface
{ {
private $username; private $username;
private $password; private $password;
@ -35,6 +33,10 @@ final class User implements UserInterface, PasswordAuthenticatedUserInterface, E
public function __construct(?string $username, ?string $password, array $roles = [], bool $enabled = true, bool $userNonExpired = true, bool $credentialsNonExpired = true, bool $userNonLocked = true, array $extraFields = []) public function __construct(?string $username, ?string $password, array $roles = [], bool $enabled = true, bool $userNonExpired = true, bool $credentialsNonExpired = true, bool $userNonLocked = true, array $extraFields = [])
{ {
if (InMemoryUser::class !== static::class) {
trigger_deprecation('symfony/security-core', '5.3', 'The "%s" class is deprecated, use "%s" instead.', self::class, InMemoryUser::class);
}
if ('' === $username || null === $username) { if ('' === $username || null === $username) {
throw new \InvalidArgumentException('The username cannot be empty.'); throw new \InvalidArgumentException('The username cannot be empty.');
} }
@ -175,8 +177,8 @@ final class User implements UserInterface, PasswordAuthenticatedUserInterface, E
return false; return false;
} }
$currentRoles = array_map('strval', (array)$this->getRoles()); $currentRoles = array_map('strval', (array) $this->getRoles());
$newRoles = array_map('strval', (array)$user->getRoles()); $newRoles = array_map('strval', (array) $user->getRoles());
$rolesChanged = \count($currentRoles) !== \count($newRoles) || \count($currentRoles) !== \count(array_intersect($currentRoles, $newRoles)); $rolesChanged = \count($currentRoles) !== \count($newRoles) || \count($currentRoles) !== \count(array_intersect($currentRoles, $newRoles));
if ($rolesChanged) { if ($rolesChanged) {
return false; return false;
@ -186,16 +188,18 @@ final class User implements UserInterface, PasswordAuthenticatedUserInterface, E
return false; return false;
} }
if ($this->isAccountNonExpired() !== $user->isAccountNonExpired()) { if (self::class === static::class) {
return false; if ($this->isAccountNonExpired() !== $user->isAccountNonExpired()) {
} return false;
}
if ($this->isAccountNonLocked() !== $user->isAccountNonLocked()) { if ($this->isAccountNonLocked() !== $user->isAccountNonLocked()) {
return false; return false;
} }
if ($this->isCredentialsNonExpired() !== $user->isCredentialsNonExpired()) { if ($this->isCredentialsNonExpired() !== $user->isCredentialsNonExpired()) {
return false; return false;
}
} }
if ($this->isEnabled() !== $user->isEnabled()) { if ($this->isEnabled() !== $user->isEnabled()) {