Skip to content

[Security] Deprecate PassportInterface #42198

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
Aug 6, 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
23 changes: 23 additions & 0 deletions UPGRADE-5.4.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,26 @@ Security
* Deprecate `DeauthenticatedEvent`, use `TokenDeauthenticatedEvent` instead
* Deprecate `CookieClearingLogoutHandler`, `SessionLogoutHandler` and `CsrfTokenClearingLogoutHandler`.
Use `CookieClearingLogoutListener`, `SessionLogoutListener` and `CsrfTokenClearingLogoutListener` instead
* Deprecate `AuthenticatorInterface::createAuthenticatedToken()`, use `AuthenticatorInterface::createToken()` instead
* Deprecate `PassportInterface` and `UserPassportInterface`, use `Passport` instead.
As such, the return type declaration of `AuthenticatorInterface::authenticate()` will change to `Passport` in 6.0

Before:
```php
class MyAuthenticator implements AuthenticatorInterface
{
public function authenticate(Request $request): PassportInterface
{
}
}
```

After:
```php
class MyAuthenticator implements AuthenticatorInterface
{
public function authenticate(Request $request): Passport
{
}
}
```
23 changes: 23 additions & 0 deletions UPGRADE-6.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,29 @@ Security
* Remove `DeauthenticatedEvent`, use `TokenDeauthenticatedEvent` instead
* Remove `CookieClearingLogoutHandler`, `SessionLogoutHandler` and `CsrfTokenClearingLogoutHandler`.
Use `CookieClearingLogoutListener`, `SessionLogoutListener` and `CsrfTokenClearingLogoutListener` instead
* Remove `AuthenticatorInterface::createAuthenticatedToken()`, use `AuthenticatorInterface::createToken()` instead
* Remove `PassportInterface` and `UserPassportInterface`, use `Passport` instead.
Also, the return type declaration of `AuthenticatorInterface::authenticate()` was changed to `Passport`

Before:
```php
class MyAuthenticator implements AuthenticatorInterface
{
public function authenticate(Request $request): PassportInterface
{
}
}
```

After:
```php
class MyAuthenticator implements AuthenticatorInterface
{
public function authenticate(Request $request): Passport
{
}
}
```

SecurityBundle
--------------
Expand Down
19 changes: 17 additions & 2 deletions src/Symfony/Component/Ldap/Security/LdapAuthenticator.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;

/**
Expand Down Expand Up @@ -53,17 +54,31 @@ public function supports(Request $request): ?bool
return $this->authenticator->supports($request);
}

public function authenticate(Request $request): PassportInterface
public function authenticate(Request $request): Passport
{
$passport = $this->authenticator->authenticate($request);
$passport->addBadge(new LdapBadge($this->ldapServiceId, $this->dnString, $this->searchDn, $this->searchPassword, $this->queryString));

return $passport;
}

/**
* @deprecated since Symfony 5.4, use {@link createToken()} instead
*/
public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface
{
return $this->authenticator->createAuthenticatedToken($passport, $firewallName);
trigger_deprecation('symfony/ldap', '5.4', 'Method "%s()" is deprecated, use "%s::createToken()" instead.', __METHOD__, __CLASS__);

return $this->createToken($passport, $firewallName);
}

public function createToken(PassportInterface $passport, string $firewallName): TokenInterface
{
// @deprecated since Symfony 5.4, in 6.0 change to:
// return $this->authenticator->createToken($passport, $firewallName);
return method_exists($this->authenticator, 'createToken')
? $this->authenticator->createToken($passport, $firewallName)
: $this->authenticator->createAuthenticatedToken($passport, $firewallName);
}

public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
namespace Symfony\Component\Security\Core\Exception;

/**
* AuthenticationExpiredException is thrown when an authenticated token becomes un-authenticated between requests.
* AuthenticationExpiredException is thrown when an authentication token becomes un-authenticated between requests.
*
* In practice, this is due to the User changing between requests (e.g. password changes),
* causes the token to become un-authenticated.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,12 @@ public function __construct(iterable $authenticators, TokenStorageInterface $tok
*/
public function authenticateUser(UserInterface $user, AuthenticatorInterface $authenticator, Request $request, array $badges = []): ?Response
{
// create an authenticated token for the User
// create an authentication token for the User
// @deprecated since 5.3, change to $user->getUserIdentifier() in 6.0
$token = $authenticator->createAuthenticatedToken($passport = new SelfValidatingPassport(new UserBadge(method_exists($user, 'getUserIdentifier') ? $user->getUserIdentifier() : $user->getUsername(), function () use ($user) { return $user; }), $badges), $this->firewallName);
$passport = new SelfValidatingPassport(new UserBadge(method_exists($user, 'getUserIdentifier') ? $user->getUserIdentifier() : $user->getUsername(), function () use ($user) { return $user; }), $badges);
$token = method_exists($authenticator, 'createToken') ? $authenticator->createToken($passport, $this->firewallName) : $authenticator->createAuthenticatedToken($passport, $this->firewallName);

// announce the authenticated token
// announce the authentication token
$token = $this->eventDispatcher->dispatch(new AuthenticationTokenCreatedEvent($token, $passport))->getAuthenticatedToken();

// authenticate this in the system
Expand Down Expand Up @@ -189,10 +190,10 @@ private function executeAuthenticator(AuthenticatorInterface $authenticator, Req
throw new BadCredentialsException(sprintf('Authentication failed; Some badges marked as required by the firewall config are not available on the passport: "%s".', implode('", "', $missingRequiredBadges)));
}

// create the authenticated token
$authenticatedToken = $authenticator->createAuthenticatedToken($passport, $this->firewallName);
// create the authentication token
$authenticatedToken = method_exists($authenticator, 'createToken') ? $authenticator->createToken($passport, $this->firewallName) : $authenticator->createAuthenticatedToken($passport, $this->firewallName);

// announce the authenticated token
// announce the authentication token
$authenticatedToken = $this->eventDispatcher->dispatch(new AuthenticationTokenCreatedEvent($authenticatedToken, $passport))->getAuthenticatedToken();

if (true === $this->eraseCredentials) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\LogicException;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\UserPassportInterface;
use Symfony\Component\Security\Http\Authenticator\Token\PostAuthenticationToken;
Expand All @@ -30,12 +31,23 @@ abstract class AbstractAuthenticator implements AuthenticatorInterface
*
* @return PostAuthenticationToken
*/
public function createToken(Passport $passport, string $firewallName): TokenInterface
{
return new PostAuthenticationToken($passport->getUser(), $firewallName, $passport->getUser()->getRoles());
}

/**
* @deprecated since Symfony 5.4, use {@link createToken()} instead
*/
public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface
{
// @deprecated since Symfony 5.4
if (!$passport instanceof UserPassportInterface) {
throw new LogicException(sprintf('Passport does not contain a user, overwrite "createAuthenticatedToken()" in "%s" to create a custom authenticated token.', static::class));
throw new LogicException(sprintf('Passport does not contain a user, overwrite "createToken()" in "%s" to create a custom authentication token.', static::class));
}

return new PostAuthenticationToken($passport->getUser(), $firewallName, $passport->getUser()->getRoles());
trigger_deprecation('symfony/security-http', '5.4', 'Method "%s()" is deprecated, use "%s::createToken()" instead.', __METHOD__, __CLASS__);

return $this->createToken($passport, $firewallName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\PreAuthenticatedUserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;

Expand Down Expand Up @@ -84,7 +85,7 @@ public function supports(Request $request): ?bool
return true;
}

public function authenticate(Request $request): PassportInterface
public function authenticate(Request $request): Passport
{
// @deprecated since 5.3, change to $this->userProvider->loadUserByIdentifier() in 6.0
$method = 'loadUserByIdentifier';
Expand All @@ -100,7 +101,17 @@ public function authenticate(Request $request): PassportInterface
);
}

/**
* @deprecated since Symfony 5.4, use {@link createToken()} instead
*/
public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface
{
trigger_deprecation('symfony/security-http', '5.4', 'Method "%s()" is deprecated, use "%s::createToken()" instead.', __METHOD__, __CLASS__);

return $this->createToken($passport, $firewallName);
}

public function createToken(Passport $passport, string $firewallName): TokenInterface
{
return new PreAuthenticatedToken($passport->getUser(), null, $firewallName, $passport->getUser()->getRoles());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;

/**
Expand All @@ -23,6 +24,10 @@
* @author Ryan Weaver <ryan@symfonycasts.com>
* @author Amaury Leroux de Lens <amaury@lerouxdelens.com>
* @author Wouter de Jong <wouter@wouterj.nl>
*
* @method TokenInterface createToken(Passport $passport, string $firewallName) Creates a token for the given user.
* If you don't care about which token class is used, you can skip this method by extending
* the AbstractAuthenticator class from your authenticator.
*/
interface AuthenticatorInterface
{
Expand All @@ -47,8 +52,10 @@ public function supports(Request $request): ?bool;
* a UserNotFoundException when the user cannot be found).
*
* @throws AuthenticationException
*
* @return Passport
*/
public function authenticate(Request $request): PassportInterface;
public function authenticate(Request $request); /*: Passport;*/
Copy link
Member

Choose a reason for hiding this comment

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

Well, maybe we should keep the existing return type while documenting the new one, instead of widening the explicit return type now (the new one is only documented anyway).

Copy link
Member

Choose a reason for hiding this comment

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

👍 if the DebugClassLoader still correctly reports the deprecation.

Copy link
Member Author

@chalasr chalasr Jul 23, 2021

Choose a reason for hiding this comment

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

Keeping the return type would forbid upgrading userland authenticators on PHP versions prior to 7.4 https://3v4l.org/LcLRN#veol

Copy link
Member

Choose a reason for hiding this comment

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

I don't see much issue in requiring a user to be on PHP 7.4 to fix a deprecation (i.e. it's not breaking support for older versions, it's just triggering a deprecation if you stay on : PassportInterface). They would need PHP 8 anyways if they want to upgrade to Symfony 6 and even PHP 7.4 will be eom when we release Symfony 5.4.

Copy link
Member Author

@chalasr chalasr Jul 24, 2021

Choose a reason for hiding this comment

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

Pushing our users to upgrade their PHP versions has never been our take, at least not by making symfony upgrades harder. Moreover, that would break our CI on 7.2 given that core authenticators have been upgraded.


/**
* Create an authenticated token for the given user.
Expand All @@ -60,6 +67,8 @@ public function authenticate(Request $request): PassportInterface;
* @see AbstractAuthenticator
*
* @param PassportInterface $passport The passport returned from authenticate()
*
* @deprecated since Symfony 5.4, use {@link createToken()} instead
*/
public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public function supports(Request $request): bool
&& $this->httpUtils->checkRequestPath($request, $this->options['check_path']);
}

public function authenticate(Request $request): PassportInterface
public function authenticate(Request $request): Passport
{
$credentials = $this->getCredentials($request);

Expand Down Expand Up @@ -106,9 +106,19 @@ public function authenticate(Request $request): PassportInterface
}

/**
* @param Passport $passport
* @deprecated since Symfony 5.4, use {@link createToken()} instead
*/
public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface
{
trigger_deprecation('symfony/security-http', '5.4', 'Method "%s()" is deprecated, use "%s::createToken()" instead.', __METHOD__, __CLASS__);

return $this->createToken($passport, $firewallName);
}

/**
* @return UsernamePasswordToken
*/
public function createToken(Passport $passport, string $firewallName): TokenInterface
{
return new UsernamePasswordToken($passport->getUser(), null, $firewallName, $passport->getUser()->getRoles());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,16 @@ public function authenticate(Request $request): PassportInterface
}

/**
* @param Passport $passport
* @deprecated since Symfony 5.4, use {@link createToken()} instead
*/
public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface
{
trigger_deprecation('symfony/security-http', '5.4', 'Method "%s()" is deprecated, use "%s::createToken()" instead.', __METHOD__, __CLASS__);

return $this->createToken($passport, $firewallName);
}

public function createToken(Passport $passport, string $firewallName): TokenInterface
{
return new UsernamePasswordToken($passport->getUser(), null, $firewallName, $passport->getUser()->getRoles());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,17 @@ public function authenticate(Request $request): PassportInterface
return $passport;
}

/**
* @deprecated since Symfony 5.4, use {@link createToken()} instead
*/
public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface
{
trigger_deprecation('symfony/security-http', '5.4', 'Method "%s()" is deprecated, use "%s::createToken()" instead.', __METHOD__, __CLASS__);

return $this->createToken($passport, $firewallName);
}

public function createToken(Passport $passport, string $firewallName): TokenInterface
{
return new UsernamePasswordToken($passport->getUser(), null, $firewallName, $passport->getUser()->getRoles());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
* passport.
*
* @author Wouter de Jong <wouter@wouterj.nl>
*
* @deprecated since Symfony 5.4, use {@link Passport} instead
*/
interface PassportInterface
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
* Represents a passport for a Security User.
*
* @author Wouter de Jong <wouter@wouterj.nl>
*
* @deprecated since Symfony 5.4, use {@link Passport} instead
*/
interface UserPassportInterface extends PassportInterface
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
use Symfony\Component\Security\Http\RememberMe\RememberMeDetails;
Expand Down Expand Up @@ -95,7 +96,17 @@ public function authenticate(Request $request): PassportInterface
}));
}

/**
* @deprecated since Symfony 5.4, use {@link createToken()} instead
*/
public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface
{
trigger_deprecation('symfony/security-http', '5.4', 'Method "%s()" is deprecated, use "%s::createToken()" instead.', __METHOD__, __CLASS__);

return $this->createToken($passport, $firewallName);
}

public function createToken(Passport $passport, string $firewallName): TokenInterface
{
return new RememberMeToken($passport->getUser(), $firewallName, $this->secret);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public function __construct(UserInterface $user, string $firewallName, array $ro
}

/**
* This is meant to be only an authenticated token, where credentials
* This is meant to be only a token, where credentials
* have already been used and are thus cleared.
*
* {@inheritdoc}
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/Security/Http/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ CHANGELOG
* Deprecate `DeauthenticatedEvent`, use `TokenDeauthenticatedEvent` instead
* Deprecate `CookieClearingLogoutHandler`, `SessionLogoutHandler` and `CsrfTokenClearingLogoutHandler`.
Use `CookieClearingLogoutListener`, `SessionLogoutListener` and `CsrfTokenClearingLogoutListener` instead
* Deprecate `PassportInterface` and `UserPassportInterface`, use `Passport` instead

5.3
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
/**
* This event is dispatched after authentication has successfully completed.
*
* At this stage, the authenticator created an authenticated token
* and generated an authentication success response. Listeners to
* At this stage, the authenticator created a token and
* generated an authentication success response. Listeners to
* this event can do actions related to successful authentication
* (such as migrating the password).
*
Expand Down
Loading