Moved new authenticator to the HTTP namespace

This removes the introduced dependency on Guard from core. It also allows an
easier migration path, as the complete Guard subcomponent can now be deprecated
later in the 5.x life.
This commit is contained in:
Wouter de Jong 2020-01-26 22:07:27 +01:00
parent b923e4c4f6
commit b14a5e8c52
23 changed files with 273 additions and 209 deletions

View File

@ -20,7 +20,7 @@
</service>
<service id="security.authenticator.http_basic"
class="Symfony\Component\Security\Core\Authentication\Authenticator\HttpBasicAuthenticator"
class="Symfony\Component\Security\Http\Authentication\Authenticator\HttpBasicAuthenticator"
abstract="true">
<argument type="abstract">realm name</argument>
<argument type="abstract">user provider</argument>
@ -29,7 +29,7 @@
</service>
<service id="security.authenticator.form_login"
class="Symfony\Component\Security\Core\Authentication\Authenticator\FormLoginAuthenticator"
class="Symfony\Component\Security\Http\Authentication\Authenticator\FormLoginAuthenticator"
abstract="true">
<argument type="service" id="security.http_utils" />
<argument /> <!-- csrf token generator -->
@ -39,7 +39,7 @@
</service>
<service id="security.authenticator.anonymous"
class="Symfony\Component\Security\Core\Authentication\Authenticator\AnonymousAuthenticator"
class="Symfony\Component\Security\Http\Authentication\Authenticator\AnonymousAuthenticator"
abstract="true">
<argument /> <!-- secret -->
<argument type="service" id="security.token_storage" />

View File

@ -52,7 +52,7 @@
<argument type="service" id="event_dispatcher" />
</call>
</service>
<service id="security.authentication.manager.guard" class="Symfony\Component\Security\Core\Authentication\GuardAuthenticationManager">
<service id="security.authentication.manager.guard" class="Symfony\Component\Security\Http\Authentication\GuardAuthenticationManager">
<argument /> <!-- guard authenticators -->
<argument type="service" id="Symfony\Component\Security\Core\User\UserCheckerInterface" /> <!-- User Checker -->
<argument>%security.authentication.manager.erase_credentials%</argument>

View File

@ -0,0 +1,71 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Core\Authentication\Token;
/**
* The token used by the guard auth system before authentication.
*
* The GuardAuthenticationListener creates this, which is then consumed
* immediately by the GuardAuthenticationProvider. If authentication is
* successful, a different authenticated token is returned
*
* @author Ryan Weaver <ryan@knpuniversity.com>
*/
class PreAuthenticationGuardToken extends AbstractToken
{
private $credentials;
private $guardProviderKey;
private $providerKey;
/**
* @param mixed $credentials
* @param string $guardProviderKey Unique key that bind this token to a specific AuthenticatorInterface
* @param string|null $providerKey The general provider key (when using with HTTP, this is the firewall name)
*/
public function __construct($credentials, string $guardProviderKey, ?string $providerKey = null)
{
$this->credentials = $credentials;
$this->guardProviderKey = $guardProviderKey;
$this->providerKey = $providerKey;
parent::__construct([]);
// never authenticated
parent::setAuthenticated(false);
}
public function getProviderKey(): ?string
{
return $this->providerKey;
}
public function getGuardProviderKey()
{
return $this->guardProviderKey;
}
/**
* Returns the user credentials, which might be an array of anything you
* wanted to put in there (e.g. username, password, favoriteColor).
*
* @return mixed The user credentials
*/
public function getCredentials()
{
return $this->credentials;
}
public function setAuthenticated(bool $authenticated)
{
throw new \LogicException('The PreAuthenticationGuardToken is *never* authenticated.');
}
}

View File

@ -5,7 +5,7 @@ namespace Symfony\Component\Security\Core\Tests\Authentication\Authenticator;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Authenticator\HttpBasicAuthenticator;
use Symfony\Component\Security\Http\Authentication\Authenticator\HttpBasicAuthenticator;
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;

View File

@ -20,7 +20,6 @@
"symfony/event-dispatcher-contracts": "^1.1|^2",
"symfony/polyfill-php80": "^1.15",
"symfony/service-contracts": "^1.1.6|^2",
"symfony/security-guard": "^4.4",
"symfony/deprecation-contracts": "^2.1"
},
"require-dev": {

View File

@ -15,9 +15,12 @@ use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticationGuardToken;
use Symfony\Component\Security\Guard\AuthenticatorInterface;
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken as GuardPreAuthenticationGuardToken;
use Symfony\Component\Security\Http\Firewall\AbstractListener;
use Symfony\Component\Security\Http\Firewall\GuardManagerListenerTrait;
use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
/**
@ -30,7 +33,7 @@ use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
*/
class GuardAuthenticationListener extends AbstractListener
{
use GuardAuthenticatorListenerTrait;
use GuardManagerListenerTrait;
private $guardHandler;
private $authenticationManager;
@ -101,6 +104,11 @@ class GuardAuthenticationListener extends AbstractListener
$this->rememberMeServices = $rememberMeServices;
}
protected function createPreAuthenticatedToken($credentials, string $uniqueGuardKey, string $providerKey): PreAuthenticationGuardToken
{
return new GuardPreAuthenticationGuardToken($credentials, $uniqueGuardKey, $providerKey);
}
protected function getGuardKey(string $key): string
{
// get a key that's unique to *this* guard authenticator

View File

@ -11,17 +11,7 @@
namespace Symfony\Component\Security\Guard;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Authenticator\AuthenticatorInterface as CoreAuthenticatorInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\SecurityEvents;
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Security\Http\Authentication\GuardAuthenticatorHandler as CoreAuthenticatorHandlerAlias;
/**
* A utility class that does much of the *work* during the guard authentication process.
@ -33,116 +23,6 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
*
* @final
*/
class GuardAuthenticatorHandler
class GuardAuthenticatorHandler extends CoreAuthenticatorHandlerAlias
{
private $tokenStorage;
private $dispatcher;
private $sessionStrategy;
private $statelessProviderKeys;
/**
* @param array $statelessProviderKeys An array of provider/firewall keys that are "stateless" and so do not need the session migrated on success
*/
public function __construct(TokenStorageInterface $tokenStorage, EventDispatcherInterface $eventDispatcher = null, array $statelessProviderKeys = [])
{
$this->tokenStorage = $tokenStorage;
$this->dispatcher = $eventDispatcher;
$this->statelessProviderKeys = $statelessProviderKeys;
}
/**
* Authenticates the given token in the system.
*/
public function authenticateWithToken(TokenInterface $token, Request $request, string $providerKey = null)
{
$this->migrateSession($request, $token, $providerKey);
$this->tokenStorage->setToken($token);
if (null !== $this->dispatcher) {
$loginEvent = new InteractiveLoginEvent($request, $token);
$this->dispatcher->dispatch($loginEvent, SecurityEvents::INTERACTIVE_LOGIN);
}
}
/**
* Returns the "on success" response for the given GuardAuthenticator.
*
* @param CoreAuthenticatorInterface|AuthenticatorInterface $guardAuthenticator
*/
public function handleAuthenticationSuccess(TokenInterface $token, Request $request, $guardAuthenticator, string $providerKey): ?Response
{
if (!$guardAuthenticator instanceof AuthenticatorInterface && !$guardAuthenticator instanceof CoreAuthenticatorInterface) {
throw new \UnexpectedValueException('Invalid guard authenticator passed to '.__METHOD__.'. Expected AuthenticatorInterface of either Security Core or Security Guard.');
}
$response = $guardAuthenticator->onAuthenticationSuccess($request, $token, $providerKey);
// check that it's a Response or null
if ($response instanceof Response || null === $response) {
return $response;
}
throw new \UnexpectedValueException(sprintf('The "%s::onAuthenticationSuccess()" method must return null or a Response object. You returned "%s".', \get_class($guardAuthenticator), get_debug_type($response)));
}
/**
* Convenience method for authenticating the user and returning the
* Response *if any* for success.
*
* @param CoreAuthenticatorInterface|AuthenticatorInterface $authenticator
*/
public function authenticateUserAndHandleSuccess(UserInterface $user, Request $request, $authenticator, string $providerKey): ?Response
{
if (!$authenticator instanceof AuthenticatorInterface && !$authenticator instanceof CoreAuthenticatorInterface) {
throw new \UnexpectedValueException('Invalid guard authenticator passed to '.__METHOD__.'. Expected AuthenticatorInterface of either Security Core or Security Guard.');
}
// create an authenticated token for the User
$token = $authenticator->createAuthenticatedToken($user, $providerKey);
// authenticate this in the system
$this->authenticateWithToken($token, $request, $providerKey);
// return the success metric
return $this->handleAuthenticationSuccess($token, $request, $authenticator, $providerKey);
}
/**
* Handles an authentication failure and returns the Response for the
* GuardAuthenticator.
*
* @param CoreAuthenticatorInterface|AuthenticatorInterface $guardAuthenticator
*/
public function handleAuthenticationFailure(AuthenticationException $authenticationException, Request $request, $guardAuthenticator, string $providerKey): ?Response
{
if (!$guardAuthenticator instanceof AuthenticatorInterface && !$guardAuthenticator instanceof CoreAuthenticatorInterface) {
throw new \UnexpectedValueException('Invalid guard authenticator passed to '.__METHOD__.'. Expected AuthenticatorInterface of either Security Core or Security Guard.');
}
$response = $guardAuthenticator->onAuthenticationFailure($request, $authenticationException);
if ($response instanceof Response || null === $response) {
// returning null is ok, it means they want the request to continue
return $response;
}
throw new \UnexpectedValueException(sprintf('The "%s::onAuthenticationFailure()" method must return null or a Response object. You returned "%s".', \get_class($guardAuthenticator), get_debug_type($response)));
}
/**
* Call this method if your authentication token is stored to a session.
*
* @final
*/
public function setSessionAuthenticationStrategy(SessionAuthenticationStrategyInterface $sessionStrategy)
{
$this->sessionStrategy = $sessionStrategy;
}
private function migrateSession(Request $request, TokenInterface $token, ?string $providerKey)
{
if (\in_array($providerKey, $this->statelessProviderKeys, true) || !$this->sessionStrategy || !$request->hasSession() || !$request->hasPreviousSession()) {
return;
}
$this->sessionStrategy->onAuthentication($request, $token);
}
}

View File

@ -11,6 +11,7 @@
namespace Symfony\Component\Security\Guard\Provider;
use Symfony\Component\Security\Http\Authentication\GuardAuthenticationManagerTrait;
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
@ -30,7 +31,7 @@ use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
*/
class GuardAuthenticationProvider implements AuthenticationProviderInterface
{
use GuardAuthenticationProviderTrait;
use GuardAuthenticationManagerTrait;
/**
* @var AuthenticatorInterface[]

View File

@ -11,7 +11,7 @@
namespace Symfony\Component\Security\Guard\Token;
use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticationGuardToken as CorePreAuthenticationGuardToken;
/**
* The token used by the guard auth system before authentication.
@ -22,52 +22,6 @@ use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
*
* @author Ryan Weaver <ryan@knpuniversity.com>
*/
class PreAuthenticationGuardToken extends AbstractToken implements GuardTokenInterface
class PreAuthenticationGuardToken extends CorePreAuthenticationGuardToken implements GuardTokenInterface
{
private $credentials;
private $guardProviderKey;
private $providerKey;
/**
* @param mixed $credentials
* @param string $guardProviderKey Unique key that bind this token to a specific AuthenticatorInterface
* @param string|null $providerKey The general provider key (when using with HTTP, this is the firewall name)
*/
public function __construct($credentials, string $guardProviderKey, ?string $providerKey = null)
{
$this->credentials = $credentials;
$this->guardProviderKey = $guardProviderKey;
$this->providerKey = $providerKey;
parent::__construct([]);
// never authenticated
parent::setAuthenticated(false);
}
public function getProviderKey(): ?string
{
return $this->providerKey;
}
public function getGuardProviderKey()
{
return $this->guardProviderKey;
}
/**
* Returns the user credentials, which might be an array of anything you
* wanted to put in there (e.g. username, password, favoriteColor).
*
* @return mixed The user credentials
*/
public function getCredentials()
{
return $this->credentials;
}
public function setAuthenticated(bool $authenticated)
{
throw new \LogicException('The PreAuthenticationGuardToken is *never* authenticated.');
}
}

View File

@ -17,7 +17,7 @@
],
"require": {
"php": "^7.2.5",
"symfony/security-core": "^5.0",
"symfony/security-core": "^5.1",
"symfony/security-http": "^4.4.1|^5.0.1",
"symfony/polyfill-php80": "^1.15"
},

View File

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Core\Authentication\Authenticator;
namespace Symfony\Component\Security\Http\Authentication\Authenticator;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\User\UserInterface;

View File

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Core\Authentication\Authenticator;
namespace Symfony\Component\Security\Http\Authentication\Authenticator;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;

View File

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Core\Authentication\Authenticator;
namespace Symfony\Component\Security\Http\Authentication\Authenticator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

View File

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Core\Authentication\Authenticator;
namespace Symfony\Component\Security\Http\Authentication\Authenticator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

View File

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Core\Authentication\Authenticator;
namespace Symfony\Component\Security\Http\Authentication\Authenticator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

View File

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Core\Authentication\Authenticator;
namespace Symfony\Component\Security\Http\Authentication\Authenticator;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;

View File

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Core\Authentication\Authenticator;
namespace Symfony\Component\Security\Http\Authentication\Authenticator;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;

View File

@ -9,9 +9,11 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Core\Authentication;
namespace Symfony\Component\Security\Http\Authentication;
use Symfony\Component\Security\Core\Authentication\Authenticator\AuthenticatorInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Http\Authentication\Authenticator\AuthenticatorInterface;
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticationGuardToken;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\AuthenticationEvents;
use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent;
@ -20,9 +22,6 @@ use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\AuthenticationExpiredException;
use Symfony\Component\Security\Core\Exception\ProviderNotFoundException;
use Symfony\Component\Security\Core\User\UserCheckerInterface;
use Symfony\Component\Security\Guard\Provider\GuardAuthenticationProviderTrait;
use Symfony\Component\Security\Guard\Token\GuardTokenInterface;
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
/**
@ -33,7 +32,7 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
*/
class GuardAuthenticationManager implements AuthenticationManagerInterface
{
use GuardAuthenticationProviderTrait;
use GuardAuthenticationManagerTrait;
private $guardAuthenticators;
private $userChecker;
@ -58,10 +57,6 @@ class GuardAuthenticationManager implements AuthenticationManagerInterface
public function authenticate(TokenInterface $token)
{
if (!$token instanceof GuardTokenInterface) {
throw new \InvalidArgumentException('GuardAuthenticationManager only supports GuardTokenInterface.');
}
if (!$token instanceof PreAuthenticationGuardToken) {
/*
* The listener *only* passes PreAuthenticationGuardToken instances.

View File

@ -9,9 +9,10 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Guard\Provider;
namespace Symfony\Component\Security\Http\Authentication;
use Symfony\Component\Security\Core\Authentication\Authenticator\AuthenticatorInterface as CoreAuthenticatorInterface;
use Symfony\Component\Security\Http\Authentication\Authenticator\AuthenticatorInterface as CoreAuthenticatorInterface;
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticationGuardToken;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\Exception\LogicException;
@ -20,14 +21,13 @@ use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Guard\AuthenticatorInterface;
use Symfony\Component\Security\Guard\PasswordAuthenticatedInterface;
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
/**
* @author Ryan Weaver <ryan@knpuniversity.com>
*
* @internal
*/
trait GuardAuthenticationProviderTrait
trait GuardAuthenticationManagerTrait
{
/**
* @param CoreAuthenticatorInterface|AuthenticatorInterface $guardAuthenticator

View File

@ -0,0 +1,149 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Http\Authentication;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Http\Authentication\Authenticator\AuthenticatorInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Guard\AuthenticatorInterface as GuardAuthenticatorInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\SecurityEvents;
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
/**
* A utility class that does much of the *work* during the guard authentication process.
*
* By having the logic here instead of the listener, more of the process
* can be called directly (e.g. for manual authentication) or overridden.
*
* @author Ryan Weaver <ryan@knpuniversity.com>
*
* @internal
*/
class GuardAuthenticatorHandler
{
private $tokenStorage;
private $dispatcher;
private $sessionStrategy;
private $statelessProviderKeys;
/**
* @param array $statelessProviderKeys An array of provider/firewall keys that are "stateless" and so do not need the session migrated on success
*/
public function __construct(TokenStorageInterface $tokenStorage, EventDispatcherInterface $eventDispatcher = null, array $statelessProviderKeys = [])
{
$this->tokenStorage = $tokenStorage;
$this->dispatcher = $eventDispatcher;
$this->statelessProviderKeys = $statelessProviderKeys;
}
/**
* Authenticates the given token in the system.
*/
public function authenticateWithToken(TokenInterface $token, Request $request, string $providerKey = null)
{
$this->migrateSession($request, $token, $providerKey);
$this->tokenStorage->setToken($token);
if (null !== $this->dispatcher) {
$loginEvent = new InteractiveLoginEvent($request, $token);
$this->dispatcher->dispatch($loginEvent, SecurityEvents::INTERACTIVE_LOGIN);
}
}
/**
* Returns the "on success" response for the given GuardAuthenticator.
*
* @param AuthenticatorInterface|GuardAuthenticatorInterface $guardAuthenticator
*/
public function handleAuthenticationSuccess(TokenInterface $token, Request $request, $guardAuthenticator, string $providerKey): ?Response
{
if (!$guardAuthenticator instanceof AuthenticatorInterface && !$guardAuthenticator instanceof GuardAuthenticatorInterface) {
throw new \UnexpectedValueException('Invalid guard authenticator passed to '.__METHOD__.'. Expected AuthenticatorInterface of either Security Core or Security Guard.');
}
$response = $guardAuthenticator->onAuthenticationSuccess($request, $token, $providerKey);
// check that it's a Response or null
if ($response instanceof Response || null === $response) {
return $response;
}
throw new \UnexpectedValueException(sprintf('The "%s::onAuthenticationSuccess()" method must return null or a Response object. You returned "%s".', \get_class($guardAuthenticator), get_debug_type($response)));
}
/**
* Convenience method for authenticating the user and returning the
* Response *if any* for success.
*
* @param AuthenticatorInterface|GuardAuthenticatorInterface $authenticator
*/
public function authenticateUserAndHandleSuccess(UserInterface $user, Request $request, $authenticator, string $providerKey): ?Response
{
if (!$authenticator instanceof AuthenticatorInterface && !$authenticator instanceof GuardAuthenticatorInterface) {
throw new \UnexpectedValueException('Invalid guard authenticator passed to '.__METHOD__.'. Expected AuthenticatorInterface of either Security Core or Security Guard.');
}
// create an authenticated token for the User
$token = $authenticator->createAuthenticatedToken($user, $providerKey);
// authenticate this in the system
$this->authenticateWithToken($token, $request, $providerKey);
// return the success metric
return $this->handleAuthenticationSuccess($token, $request, $authenticator, $providerKey);
}
/**
* Handles an authentication failure and returns the Response for the
* GuardAuthenticator.
*
* @param AuthenticatorInterface|GuardAuthenticatorInterface $guardAuthenticator
*/
public function handleAuthenticationFailure(AuthenticationException $authenticationException, Request $request, $guardAuthenticator, string $providerKey): ?Response
{
if (!$guardAuthenticator instanceof AuthenticatorInterface && !$guardAuthenticator instanceof GuardAuthenticatorInterface) {
throw new \UnexpectedValueException('Invalid guard authenticator passed to '.__METHOD__.'. Expected AuthenticatorInterface of either Security Core or Security Guard.');
}
$response = $guardAuthenticator->onAuthenticationFailure($request, $authenticationException);
if ($response instanceof Response || null === $response) {
// returning null is ok, it means they want the request to continue
return $response;
}
throw new \UnexpectedValueException(sprintf('The "%s::onAuthenticationFailure()" method must return null or a Response object. You returned "%s".', \get_class($guardAuthenticator), get_debug_type($response)));
}
/**
* Call this method if your authentication token is stored to a session.
*
* @final
*/
public function setSessionAuthenticationStrategy(SessionAuthenticationStrategyInterface $sessionStrategy)
{
$this->sessionStrategy = $sessionStrategy;
}
private function migrateSession(Request $request, TokenInterface $token, ?string $providerKey)
{
if (\in_array($providerKey, $this->statelessProviderKeys, true) || !$this->sessionStrategy || !$request->hasSession() || !$request->hasPreviousSession()) {
return;
}
$this->sessionStrategy->onAuthentication($request, $token);
}
}

View File

@ -14,8 +14,8 @@ namespace Symfony\Component\Security\Http\Firewall;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\Authenticator\AuthenticatorInterface;
use Symfony\Component\Security\Guard\Firewall\GuardAuthenticatorListenerTrait;
use Symfony\Component\Security\Http\Authentication\Authenticator\AuthenticatorInterface;
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticationGuardToken;
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
@ -28,7 +28,7 @@ use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
*/
class GuardManagerListener
{
use GuardAuthenticatorListenerTrait;
use GuardManagerListenerTrait;
private $authenticationManager;
private $guardHandler;
@ -65,6 +65,11 @@ class GuardManagerListener
$this->rememberMeServices = $rememberMeServices;
}
protected function createPreAuthenticatedToken($credentials, string $uniqueGuardKey, string $providerKey): PreAuthenticationGuardToken
{
return new PreAuthenticationGuardToken($credentials, $uniqueGuardKey, $providerKey);
}
protected function getGuardKey(string $key): string
{
// Guard authenticators in the GuardManagerListener are already indexed

View File

@ -9,16 +9,16 @@
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Guard\Firewall;
namespace Symfony\Component\Security\Http\Firewall;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Security\Core\Authentication\Authenticator\AuthenticatorInterface as CoreAuthenticatorInterface;
use Symfony\Component\Security\Http\Authentication\Authenticator\AuthenticatorInterface as CoreAuthenticatorInterface;
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticationGuardToken;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Guard\AuthenticatorInterface;
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
/**
* @author Ryan Weaver <ryan@knpuniversity.com>
@ -26,7 +26,7 @@ use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
*
* @internal
*/
trait GuardAuthenticatorListenerTrait
trait GuardManagerListenerTrait
{
protected function getSupportingGuardAuthenticators(Request $request): array
{
@ -89,7 +89,7 @@ trait GuardAuthenticatorListenerTrait
}
// create a token with the unique key, so that the provider knows which authenticator to use
$token = new PreAuthenticationGuardToken($credentials, $uniqueGuardKey, $this->providerKey);
$token = $this->createPreAuthenticatedToken($credentials, $uniqueGuardKey, $this->providerKey);
if (null !== $this->logger) {
$this->logger->debug('Passing guard token information to the GuardAuthenticationProvider', ['firewall_key' => $this->providerKey, 'authenticator' => \get_class($guardAuthenticator)]);
@ -174,4 +174,6 @@ trait GuardAuthenticatorListenerTrait
}
abstract protected function getGuardKey(string $key): string;
abstract protected function createPreAuthenticatedToken($credentials, string $uniqueGuardKey, string $providerKey): PreAuthenticationGuardToken;
}

View File

@ -18,7 +18,7 @@
"require": {
"php": "^7.2.5",
"symfony/deprecation-contracts": "^2.1",
"symfony/security-core": "^4.4.8|^5.0.8",
"symfony/security-core": "^5.1",
"symfony/http-foundation": "^4.4.7|^5.0.7",
"symfony/http-kernel": "^4.4|^5.0",
"symfony/polyfill-php80": "^1.15",