Skip to content

[Ldap][Security] Remove deprecated eraseCredentials() from (User|Token)Interface #60742

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
Jun 16, 2025
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
25 changes: 25 additions & 0 deletions UPGRADE-8.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ HttpClient
* Remove support for amphp/http-client < 5
* Remove setLogger() methods on decorators; configure the logger on the wrapped client directly instead

Ldap
----

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

OptionsResolver
---------------

Expand Down Expand Up @@ -207,6 +212,26 @@ PropertyInfo
}
```

Security
--------

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

```diff
-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;
+}
```

TwigBridge
----------

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

#[\Deprecated]
public function eraseCredentials(): void
{
}

public function equals(UserInterface $user)
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,11 +249,6 @@ public function isEnabled(): bool
{
return $this->enabled;
}

#[\Deprecated]
public function eraseCredentials(): void
{
}
}

class ForceLoginController
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
=========

8.0
---

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

7.3
---

Expand Down
9 changes: 0 additions & 9 deletions src/Symfony/Component/Ldap/Security/LdapUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,6 @@ public function getUserIdentifier(): string
return $this->identifier;
}

/**
* @deprecated since Symfony 7.3
*/
#[\Deprecated(since: 'symfony/ldap 7.3')]
public function eraseCredentials(): void
{
$this->password = null;
}

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

#[\Deprecated]
public function eraseCredentials(): void
{
}

public function getUserIdentifier(): string
{
return $this->username;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,6 @@ 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();
}
}

/**
* Returns all the necessary state of the object for serialization purposes.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,6 @@ public function getUserIdentifier(): string
return '';
}

/**
* @deprecated since Symfony 7.3
*/
#[\Deprecated(since: 'symfony/security-core 7.3')]
public function eraseCredentials(): void
{
}

public function getAttributes(): array
{
return [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,6 @@ public function getUser(): ?UserInterface;
*/
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;

public function getAttributes(): array;

/**
Expand Down
6 changes: 6 additions & 0 deletions src/Symfony/Component/Security/Core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
CHANGELOG
=========

8.0
---

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

7.3
---

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

#[\Deprecated]
public function eraseCredentials(): void
{
}

public function getAttributes(): array
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,6 @@ public static function provideUsers()
yield [new InMemoryUser('fabien', null), 'fabien'];
}

/**
* @group legacy
*/
public function testEraseCredentials()
{
$token = new ConcreteToken(['ROLE_FOO']);

$user = $this->createMock(UserInterface::class);
$user->expects($this->once())->method('eraseCredentials');
$token->setUser($user);

$this->expectUserDeprecationMessage(\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();
}

public function testSerialize()
{
$token = new ConcreteToken(['ROLE_FOO', 'ROLE_BAR']);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,4 @@ public function getPassword(): ?string
{
return null;
}

#[\Deprecated]
public function eraseCredentials(): void
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,6 @@ public function testIsEnabled()
$this->assertFalse($user->isEnabled());
}

/**
* @group legacy
*/
public function testEraseCredentials()
{
$user = new InMemoryUser('fabien', 'superpass');
$this->expectUserDeprecationMessage(\sprintf('Unsilenced deprecation: Method %s::eraseCredentials() is deprecated since symfony/security-core 7.3', InMemoryUser::class));
$user->eraseCredentials();
$this->assertEquals('superpass', $user->getPassword());
}

public function testToString()
{
$user = new InMemoryUser('fabien', 'superpass');
Expand Down
8 changes: 0 additions & 8 deletions src/Symfony/Component/Security/Core/User/InMemoryUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,6 @@ public function isEnabled(): bool
return $this->enabled;
}

/**
* @deprecated since Symfony 7.3
*/
#[\Deprecated(since: 'symfony/security-core 7.3')]
public function eraseCredentials(): void
{
}

public function isEqualTo(UserInterface $user): bool
{
if (!$user instanceof self) {
Expand Down
4 changes: 0 additions & 4 deletions src/Symfony/Component/Security/Core/User/OAuth2User.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,4 @@ public function getUserIdentifier(): string
{
return (string) ($this->sub ?? $this->username);
}

public function eraseCredentials(): void
{
}
}
8 changes: 0 additions & 8 deletions src/Symfony/Component/Security/Core/User/OidcUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,6 @@ 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
{
}

public function getSub(): ?string
{
return $this->sub;
Expand Down
10 changes: 0 additions & 10 deletions src/Symfony/Component/Security/Core/User/UserInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,6 @@ interface UserInterface
*/
public function getRoles(): array;

/**
* Removes sensitive data from the user.
*
* 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;

/**
* Returns the identifier for this user (e.g. username or email address).
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,6 @@ private function executeAuthenticator(AuthenticatorInterface $authenticator, Req
// announce the authentication token
$authenticatedToken = $this->eventDispatcher->dispatch(new AuthenticationTokenCreatedEvent($authenticatedToken, $passport))->getAuthenticatedToken();

if ($this->eraseCredentials) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we might need a plan to remove the property now

Copy link
Member Author

@chalasr chalasr Jun 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean deprecating on 7.4?

self::checkEraseCredentials($authenticatedToken)?->eraseCredentials();
}

$this->eventDispatcher->dispatch(new AuthenticationSuccessEvent($authenticatedToken), AuthenticationEvents::AUTHENTICATION_SUCCESS);

$this->logger?->info('Authenticator successful!', ['token' => $authenticatedToken, 'authenticator' => ($authenticator instanceof TraceableAuthenticator ? $authenticator->getAuthenticator() : $authenticator)::class]);
Expand Down Expand Up @@ -288,41 +284,4 @@ private function isSensitiveException(AuthenticationException $exception): bool

return false;
}

/**
* @deprecated since Symfony 7.3
*/
private static function checkEraseCredentials(TokenInterface|UserInterface|null $token): TokenInterface|UserInterface|null
{
if (!$token || !method_exists($token, 'eraseCredentials')) {
return null;
}

static $genericImplementations = [];
$m = null;

if (!isset($genericImplementations[$token::class])) {
$m = new \ReflectionMethod($token, 'eraseCredentials');
$genericImplementations[$token::class] = AbstractToken::class === $m->class;
}

if ($genericImplementations[$token::class]) {
return self::checkEraseCredentials($token->getUser());
}

static $deprecatedImplementations = [];

if (!isset($deprecatedImplementations[$token::class])) {
$m ??= new \ReflectionMethod($token, 'eraseCredentials');
$deprecatedImplementations[$token::class] = !$m->getAttributes(\Deprecated::class);
}

if ($deprecatedImplementations[$token::class]) {
trigger_deprecation('symfony/security-http', '7.3', 'Implementing "%s::eraseCredentials()" is deprecated since Symfony 7.3; add the #[\Deprecated] attribute on the method to signal its either empty or that you moved the logic elsewhere, typically to the "__serialize()" method.', get_debug_type($token));

return $token;
}

return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -204,32 +204,6 @@ public function testAllRequiredBadgesPresent()
$manager->authenticateRequest($this->request);
}

/**
* @dataProvider provideEraseCredentialsData
*
* @group legacy
*/
public function testEraseCredentials($eraseCredentials)
{
$authenticator = $this->createAuthenticator();
$this->request->attributes->set('_security_authenticators', [$authenticator]);

$authenticator->expects($this->any())->method('authenticate')->willReturn(new SelfValidatingPassport(new UserBadge('wouter', fn () => $this->user)));

$authenticator->expects($this->any())->method('createToken')->willReturn($this->token);

$this->token->expects($eraseCredentials ? $this->once() : $this->never())->method('eraseCredentials');

$manager = $this->createManager([$authenticator], 'main', $eraseCredentials, hideUserNotFoundExceptions: true);
$manager->authenticateRequest($this->request);
}

public static function provideEraseCredentialsData()
{
yield [true];
yield [false];
}

/**
* @group legacy
*/
Expand Down
Loading
Loading