8000 [Security] Deprecate UserInterface & TokenInterface's `eraseCredentials()` by nicolas-grekas · Pull Request #59682 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Security] Deprecate UserInterface & TokenInterface's eraseCredentials() #59682

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
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
37 changes: 36 additions & 1 deletion UPGRADE-7.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,42 @@ backward compatibility breaks. Minor backward compatibility breaks are prefixed
`[BC BREAK]`, make sure your code is compatible with these entries before upgrading.
Read more about this in the [Symfony documentation](https://symfony.com/doc/7.3/setup/upgrade_minor.html).

If you're upgrading from a version below 7.1, follow the [7.2 upgrade guide](UPGRADE-7.2.md) first.
If you're upgrading from a version below 7.2, follow the [7.2 upgrade guide](UPGRADE-7.2.md) first.

Ldap
----

* Deprecate `LdapUser::eraseCredentials()` in favor of `__serialize()`

Security
--------

* Deprecate `UserInterface::eraseCredentials()` and `TokenInterface::eraseCredentials()`,
erase credentials e.g. using `__serialize()` instead

*Before*
```php
public function eraseCredentials(): void
{
}
```

*After*
```php
#[\Deprecated]
public function eraseCredentials(): void
{
}

// If your eraseCredentials() method was used to empty a "password" property:
public function __serialize(): array
{
$data = (array) $this;
unset($data["\0".self::class."\0password"]);

return $data;
}
```

Console
-------
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Bridge/Doctrine/Tests/Fixtures/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public function getUserIdentifier(): string
return $this->name;
}

#[\Deprecated]
public function eraseCredentials(): void
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ public static function handleError($type, $msg, $file, $line, $context = [])

return $h ? $h($type, $msg, $file, $line, $context) : false;
}
// If the message is serialized we need to extract the message. This occurs when the error is triggered by
// If the message is serialized we need to extract the message. This occurs when the error is triggered
// by the isolated test path in \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest().
$parsedMsg = @unserialize($msg);
if (\is_array($parsedMsg)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticatorManager;
Expand Down Expand Up @@ -89,7 +90,7 @@ public function testOnKernelRequestRecordsAuthenticatorsInfo()
$supportingAuthenticator
->expects($this->once())
->method('createToken')
->willReturn($this->createMock(TokenInterface::class));
->willReturn(new class extends AbstractToken {});

$notSupportingAuthenticator = $this->createMock(DummyAuthenticator::class);
$notSupportingAuthenticator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ public function isEnabled(): bool
return $this->enabled;
}

#[\Deprecated]
public function eraseCredentials(): void
{
}
Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/Ldap/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

7.3
---

* Deprecate `LdapUser::eraseCredentials()` in favor of `__serialize()`

7.2
---

Expand Down
18 changes: 17 additions & 1 deletion src/Symfony/Component/Ldap/Security/LdapUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,16 @@ public function getUserIdentifier(): string
return $this->identifier;
}

/**
* @deprecated since Symfony 7.3
*/
#[\Deprecated(since: 'symfony/ldap 7.3')]
public function eraseCredentials(): void
{
if (\PHP_VERSION_ID < 80400) {
@trigger_error(\sprintf('Method %s::eraseCredentials() is deprecated since symfony/ldap 7.3', self::class), \E_USER_DEPRECATED);
}

$this->password = null;
}

Expand All @@ -70,7 +78,7 @@ public function getExtraFields(): array
return $this->extraFields;
}

public function setPassword(#[\SensitiveParameter] string $password): void
public function setPassword(#[\SensitiveParameter] ?string $password): void
{
$this->password = $password;
}
Expand All @@ -95,4 +103,12 @@ public function isEqualTo(UserInterface $user): bool

return true;
}

public function __serialize(): array
{
$data = (array) $this;
unset($data[\sprintf("\0%s\0password", self::class)]);

return $data;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ public function getRoles(): array
return $this->roles;
}

#[\Deprecated]
public function eraseCredentials(): void
{
// Do nothing
return;
}

public function getUserIdentifier(): string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,25 +238,9 @@ public function testMigrateFromWithCustomInstance()

class SomeUser implements PasswordAuthenticatedUserInterface
{
public function getRoles(): array
{
}

public function getPassword(): ?string
{
}

public function getSalt(): ?string
{
}

public function getUserIdentifier(): string
{
}

public function eraseCredentials()
{
}
}

class SomeChildUser extends SomeUser
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,15 @@ public function setUser(UserInterface $user): void
$this->user = $user;
}

/**
* Removes sensitive information from the token.
*
* @deprecated since Symfony 7.3, erase credentials using the "__serialize()" method instead
*/
public function eraseCredentials(): void
{
trigger_deprecation('symfony/security-core', '7.3', \sprintf('The "%s::eraseCredentials()" method is deprecated and will be removed in 8.0, erase credentials using the "__serialize()" method instead.', TokenInterface::class));

if ($this->getUser() instanceof UserInterface) {
$this->getUser()->eraseCredentials();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,15 @@ public function getUserIdentifier(): string
return '';
}

/**
* @deprecated since Symfony 7.3
*/
#[\Deprecated(since: 'symfony/security-core 7.3')]
public function eraseCredentials(): void
{
if (\PHP_VERSION_ID < 80400) {
@trigger_error(\sprintf('Method %s::eraseCredentials() is deprecated since symfony/security-core 7.3', self::class), \E_USER_DEPRECATED);
}
}

public function getAttributes(): array
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
/**
* TokenInterface is the interface for the user authentication information.
*
* The __serialize/__unserialize() magic methods can be implemented on the token
* class to prevent sensitive credentials from being put in the session storage.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
Expand Down Expand Up @@ -56,6 +59,8 @@ public function setUser(UserInterface $user): void;

/**
* Removes sensitive information from the token.
*
* @deprecated since Symfony 7.3; erase credentials using the "__serialize()" method instead
*/
public function eraseCredentials(): void;

Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Component/Security/Core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ CHANGELOG
* Add `UserAuthorizationChecker::isGrantedForUser()` to test user authorization without relying on the session.
For example, users not currently logged in, or while processing a message from a message queue.
* Add `OfflineTokenInterface` to mark tokens that do not represent the currently logged-in user
* Deprecate `UserInterface::eraseCredentials()` and `TokenInterface::eraseCredentials()`,
erase credentials e.g. using `__serialize()` instead

7.2
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ public function getUserIdentifier(): string
{
}

#[\Deprecated]
public function eraseCredentials(): void
{
}
Expand Down
10000
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@
namespace Symfony\Component\Security\Core\Tests\Authentication\Token;

use PHPUnit\Framework\TestCase;
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\User\InMemoryUser;
use Symfony\Component\Security\Core\User\UserInterface;

class AbstractTokenTest extends TestCase
{
use ExpectDeprecationTrait;

/**
* @dataProvider provideUsers
*/
Expand All @@ -33,6 +37,9 @@ public static function provideUsers()
yield [new InMemoryUser('fabien', null), 'fabien'];
}

/**
* @group legacy
*/
public function testEraseCredentials()
{
$token = new ConcreteToken(['ROLE_FOO']);
Expand All @@ -41,6 +48,8 @@ public function testEraseCredentials()
$user->expects($this->once())->method('eraseCredentials');
$token->setUser($user);

$this->expectDeprecation(\sprintf('Since symfony/security-core 7.3: The "%s::eraseCredentials()" method is deprecated and will be removed in 8.0, erase credentials using the "__serialize()" method instead.', TokenInterface::class));

$token->eraseCredentials();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ public function getRoles(): array
return $this->roles;
}

public function getPassword(): ?string
{
return null;
}

#[\Deprecated]
public function eraseCredentials(): void
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
namespace Symfony\Component\Security\Core\Tests\User;

use PHPUnit\Framework\TestCase;
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
use Symfony\Component\Security\Core\User\InMemoryUser;
use Symfony\Component\Security\Core\User\UserInterface;

class InMemoryUserTest extends TestCase
{
use ExpectDeprecationTrait;

public function testConstructorException()
{
$this->expectException(\InvalidArgumentException::class);
Expand Down Expand Up @@ -53,9 +56,13 @@ public function testIsEnabled()
$this->assertFalse($user->isEnabled());
}

/**
* @group legacy
*/
public function testEraseCredentials()
{
$user = new InMemoryUser('fabien', 'superpass');
$this->expectDeprecation(\sprintf('%sMethod %s::eraseCredentials() is deprecated since symfony/security-core 7.3', \PHP_VERSION_ID >= 80400 ? 'Unsilenced deprecation: ' : '', InMemoryUser::class));
$user->eraseCredentials();
$this->assertEquals('superpass', $user->getPassword());
}
Expand Down
7 changes: 7 additions & 0 deletions src/Symfony/Component/Security/Core/User/InMemoryUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,15 @@ public function isEnabled(): bool
return $this->enabled;
}

/**
* @deprecated since Symfony 7.3
*/
#[\Deprecated(since: 'symfony/security-core 7.3')]
public function eraseCredentials(): void
{
if (\PHP_VERSION_ID < 80400) {
@trigger_error(\sprintf('Method %s::eraseCredentials() is deprecated since symfony/security-core 7.3', self::class), \E_USER_DEPRECATED);
}
}

public function isEqualTo(UserInterface $user): bool
Expand Down
7 changes: 7 additions & 0 deletions src/Symfony/Component/Security/Core/User/OidcUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,15 @@ public function getUserIdentifier(): string
return (string) ($this->userIdentifier ?? $this->getSub());
}

/**
* @deprecated since Symfony 7.3
*/
#[\Deprecated(since: 'symfony/security-core 7.3')]
public function eraseCredentials(): void
{
if (\PHP_VERSION_ID < 80400) {
@trigger_error(\sprintf('Method %s::eraseCredentials() is deprecated since symfony/security-core 7.3', self::class), \E_USER_DEPRECATED);
}
}

public function getSub(): ?string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ interface PasswordAuthenticatedUserInterface
* Returns the hashed password used to authenticate the user.
*
* Usually on authentication, a plain-text password will be compared to this value.
*
* The __serialize/__unserialize() magic methods can be implemented on the user
* class to prevent hashed passwords from being put in the session storage.
*/
public function getPassword(): ?string;
}
5 changes: 5 additions & 0 deletions src/Symfony/Component/Security/Core/User/UserInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
* this interface. Objects that implement this interface are created and
* loaded by different objects that implement UserProviderInterface.
*
* The __serialize/__unserialize() magic methods can be implemented on the user
* class to prevent sensitive credentials from being put in the session storage.
*
* @see UserProviderInterface
*
* @author Fabien Potencier <fabien@symfony.com>
Expand Down Expand Up @@ -51,6 +54,8 @@ public function getRoles(): array;
*
* This is important if, at any given point, sensitive information like
* the plain-text password is stored on this object.
*
* @deprecated since Symfony 7.3, erase credentials using the "__serialize()" method instead
*/
public function eraseCredentials(): void;

Expand Down
Loading
Loading
0