diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index dbecca12e9..57ecde2068 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -23,6 +23,7 @@ use Symfony\Component\Config\FileLocator; use Symfony\Component\Console\Application; use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -278,19 +279,16 @@ class SecurityExtension extends Extension implements PrependExtensionInterface $mapDef->replaceArgument(0, ServiceLocatorTagPass::register($container, $contextRefs)); $mapDef->replaceArgument(1, new IteratorArgument($map)); - // add authentication providers to authentication manager - $authenticationProviders = array_map(function ($id) { - return new Reference($id); - }, array_unique($authenticationProviders)); - $authenticationManagerId = 'security.authentication.manager.provider'; - if ($this->authenticatorManagerEnabled) { - $authenticationManagerId = 'security.authentication.manager.authenticator'; - $container->setAlias('security.authentication.manager', new Alias($authenticationManagerId)); + if (!$this->authenticatorManagerEnabled) { + // add authentication providers to authentication manager + $authenticationProviders = array_map(function ($id) { + return new Reference($id); + }, array_unique($authenticationProviders)); + + $container + ->getDefinition('security.authentication.manager') + ->replaceArgument(0, new IteratorArgument($authenticationProviders)); } - $container - ->getDefinition($authenticationManagerId) - ->replaceArgument(0, new IteratorArgument($authenticationProviders)) - ; // register an autowire alias for the UserCheckerInterface if no custom user checker service is configured if (!$customUserChecker) { @@ -441,17 +439,28 @@ class SecurityExtension extends Extension implements PrependExtensionInterface $authenticationProviders = array_merge($authenticationProviders, $firewallAuthenticationProviders); if ($this->authenticatorManagerEnabled) { + // authenticator manager + $authenticators = array_map(function ($id) { + return new Reference($id); + }, $firewallAuthenticationProviders); + $container + ->setDefinition($managerId = 'security.authenticator.manager.'.$id, new ChildDefinition('security.authentication.manager.authenticator')) + ->replaceArgument(0, $authenticators) + ; + + $managerLocator = $container->getDefinition('security.authenticator.managers_locator'); + $managerLocator->replaceArgument(0, array_merge($managerLocator->getArgument(0), [$id => new ServiceClosureArgument(new Reference($managerId))])); + // authenticator manager listener $container ->setDefinition('security.firewall.authenticator.'.$id.'.locator', new ChildDefinition('security.firewall.authenticator.locator')) - ->setArguments([array_map(function ($id) { - return new Reference($id); - }, $firewallAuthenticationProviders)]) + ->setArguments([$authenticators]) ->addTag('container.service_locator') ; $container ->setDefinition('security.firewall.authenticator.'.$id, new ChildDefinition('security.firewall.authenticator')) + ->replaceArgument(0, new Reference($managerId)) ->replaceArgument(2, new Reference('security.firewall.authenticator.'.$id.'.locator')) ->replaceArgument(3, $id) ; diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator.xml index 4cbc440625..9b52c37ec8 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_authenticator.xml @@ -6,7 +6,10 @@ - + authenticators %security.authentication.manager.erase_credentials% @@ -14,6 +17,18 @@ + + + + + + + + + + - + authenticator manager diff --git a/src/Symfony/Bundle/SecurityBundle/Security/FirewallAwareAuthenticatorManager.php b/src/Symfony/Bundle/SecurityBundle/Security/FirewallAwareAuthenticatorManager.php new file mode 100644 index 0000000000..a3974dd2b3 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Security/FirewallAwareAuthenticatorManager.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\SecurityBundle\Security; + +use Symfony\Component\DependencyInjection\ServiceLocator; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Exception\LogicException; + +/** + * A decorator that delegates all method calls to the authenticator + * manager of the current firewall. + * + * @author Wouter de Jong + */ +class FirewallAwareAuthenticatorManager implements AuthenticationManagerInterface +{ + private $firewallMap; + private $authenticatorManagers; + private $requestStack; + + public function __construct(FirewallMap $firewallMap, ServiceLocator $authenticatorManagers, RequestStack $requestStack) + { + $this->firewallMap = $firewallMap; + $this->authenticatorManagers = $authenticatorManagers; + $this->requestStack = $requestStack; + } + + public function authenticate(TokenInterface $token) + { + $firewallConfig = $this->firewallMap->getFirewallConfig($this->requestStack->getMasterRequest()); + if (null === $firewallConfig) { + throw new LogicException('Cannot call authenticate on this request, as it is not behind a firewall.'); + } + + return $this->authenticatorManagers->get($firewallConfig->getName())->authenticate($token); + } +} diff --git a/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php b/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php index 39208002b0..6a565ad1bb 100644 --- a/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php +++ b/src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php @@ -40,14 +40,16 @@ class AuthenticatorManager implements AuthenticationManagerInterface private $authenticators; private $eventDispatcher; private $eraseCredentials; + private $providerKey; /** * @param AuthenticatorInterface[] $authenticators The authenticators, with keys that match what's passed to AuthenticatorManagerListener */ - public function __construct(iterable $authenticators, EventDispatcherInterface $eventDispatcher, bool $eraseCredentials = true) + public function __construct(iterable $authenticators, EventDispatcherInterface $eventDispatcher, string $providerKey, bool $eraseCredentials = true) { $this->authenticators = $authenticators; $this->eventDispatcher = $eventDispatcher; + $this->providerKey = $providerKey; $this->eraseCredentials = $eraseCredentials; } diff --git a/src/Symfony/Component/Security/Http/Firewall/AuthenticatorManagerListener.php b/src/Symfony/Component/Security/Http/Firewall/AuthenticatorManagerListener.php index b5327bd958..016bb826af 100644 --- a/src/Symfony/Component/Security/Http/Firewall/AuthenticatorManagerListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/AuthenticatorManagerListener.php @@ -33,7 +33,7 @@ use Symfony\Component\Security\Http\Event\LoginSuccessEvent; */ class AuthenticatorManagerListener extends AbstractListener { - private $authenticationManager; + private $authenticatorManager; private $authenticatorHandler; private $authenticators; protected $providerKey; @@ -45,7 +45,7 @@ class AuthenticatorManagerListener extends AbstractListener */ public function __construct(AuthenticationManagerInterface $authenticationManager, AuthenticatorHandler $authenticatorHandler, iterable $authenticators, string $providerKey, EventDispatcherInterface $eventDispatcher, ?LoggerInterface $logger = null) { - $this->authenticationManager = $authenticationManager; + $this->authenticatorManager = $authenticationManager; $this->authenticatorHandler = $authenticatorHandler; $this->authenticators = $authenticators; $this->providerKey = $providerKey; @@ -157,7 +157,7 @@ class AuthenticatorManagerListener extends AbstractListener } // pass the token into the AuthenticationManager system // this indirectly calls AuthenticatorManager::authenticate() - $token = $this->authenticationManager->authenticate($token); + $token = $this->authenticatorManager->authenticate($token); if (null !== $this->logger) { $this->logger->info('Authenticator successful!', ['token' => $token, 'authenticator' => \get_class($authenticator)]);