login consent app sql
This commit is contained in:
@ -0,0 +1,41 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Registers the expression language providers.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class AddExpressionLanguageProvidersPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if ($container->has('security.expression_language')) {
|
||||
$definition = $container->findDefinition('security.expression_language');
|
||||
foreach ($container->findTaggedServiceIds('security.expression_language_provider', true) as $id => $attributes) {
|
||||
$definition->addMethodCall('registerProvider', [new Reference($id)]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$container->hasDefinition('cache.system')) {
|
||||
$container->removeDefinition('cache.security_expression_language');
|
||||
}
|
||||
}
|
||||
}
|
73
vendor/symfony/security-bundle/DependencyInjection/Compiler/AddSecurityVotersPass.php
vendored
Normal file
73
vendor/symfony/security-bundle/DependencyInjection/Compiler/AddSecurityVotersPass.php
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\LogicException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Security\Core\Authorization\Voter\TraceableVoter;
|
||||
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
|
||||
|
||||
/**
|
||||
* Adds all configured security voters to the access decision manager.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class AddSecurityVotersPass implements CompilerPassInterface
|
||||
{
|
||||
use PriorityTaggedServiceTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition('security.access.decision_manager')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$voters = $this->findAndSortTaggedServices('security.voter', $container);
|
||||
if (!$voters) {
|
||||
throw new LogicException('No security voters found. You need to tag at least one with "security.voter".');
|
||||
}
|
||||
|
||||
$debug = $container->getParameter('kernel.debug');
|
||||
$voterServices = [];
|
||||
foreach ($voters as $voter) {
|
||||
$voterServiceId = (string) $voter;
|
||||
$definition = $container->getDefinition($voterServiceId);
|
||||
|
||||
$class = $container->getParameterBag()->resolveValue($definition->getClass());
|
||||
|
||||
if (!is_a($class, VoterInterface::class, true)) {
|
||||
throw new LogicException(sprintf('"%s" must implement the "%s" when used as a voter.', $class, VoterInterface::class));
|
||||
}
|
||||
|
||||
if ($debug) {
|
||||
$voterServices[] = new Reference($debugVoterServiceId = 'debug.security.voter.'.$voterServiceId);
|
||||
|
||||
$container
|
||||
->register($debugVoterServiceId, TraceableVoter::class)
|
||||
->addArgument($voter)
|
||||
->addArgument(new Reference('event_dispatcher'));
|
||||
} else {
|
||||
$voterServices[] = $voter;
|
||||
}
|
||||
}
|
||||
|
||||
$container->getDefinition('security.access.decision_manager')
|
||||
->replaceArgument(0, new IteratorArgument($voterServices));
|
||||
}
|
||||
}
|
48
vendor/symfony/security-bundle/DependencyInjection/Compiler/AddSessionDomainConstraintPass.php
vendored
Normal file
48
vendor/symfony/security-bundle/DependencyInjection/Compiler/AddSessionDomainConstraintPass.php
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Uses the session domain to restrict allowed redirection targets.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class AddSessionDomainConstraintPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasParameter('session.storage.options') || !$container->has('security.http_utils')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sessionOptions = $container->getParameter('session.storage.options');
|
||||
$domainRegexp = empty($sessionOptions['cookie_domain']) ? '%%s' : sprintf('(?:%%%%s|(?:.+\.)?%s)', preg_quote(trim($sessionOptions['cookie_domain'], '.')));
|
||||
|
||||
if ('auto' === ($sessionOptions['cookie_secure'] ?? null)) {
|
||||
$secureDomainRegexp = sprintf('{^https://%s$}i', $domainRegexp);
|
||||
$domainRegexp = 'https?://'.$domainRegexp;
|
||||
} else {
|
||||
$secureDomainRegexp = null;
|
||||
$domainRegexp = (empty($sessionOptions['cookie_secure']) ? 'https?://' : 'https://').$domainRegexp;
|
||||
}
|
||||
|
||||
$container->findDefinition('security.http_utils')
|
||||
->addArgument(sprintf('{^%s$}i', $domainRegexp))
|
||||
->addArgument($secureDomainRegexp);
|
||||
}
|
||||
}
|
33
vendor/symfony/security-bundle/DependencyInjection/Compiler/CleanRememberMeVerifierPass.php
vendored
Normal file
33
vendor/symfony/security-bundle/DependencyInjection/Compiler/CleanRememberMeVerifierPass.php
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Cleans up the remember me verifier cache if cache is missing.
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class CleanRememberMeVerifierPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition('cache.system')) {
|
||||
$container->removeDefinition('cache.security_token_verifier');
|
||||
}
|
||||
}
|
||||
}
|
64
vendor/symfony/security-bundle/DependencyInjection/Compiler/RegisterCsrfFeaturesPass.php
vendored
Normal file
64
vendor/symfony/security-bundle/DependencyInjection/Compiler/RegisterCsrfFeaturesPass.php
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Security\Http\EventListener\CsrfProtectionListener;
|
||||
use Symfony\Component\Security\Http\EventListener\CsrfTokenClearingLogoutListener;
|
||||
|
||||
/**
|
||||
* @author Christian Flothmann <christian.flothmann@sensiolabs.de>
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class RegisterCsrfFeaturesPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$this->registerCsrfProtectionListener($container);
|
||||
$this->registerLogoutHandler($container);
|
||||
}
|
||||
|
||||
private function registerCsrfProtectionListener(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->has('security.authenticator.manager') || !$container->has('security.csrf.token_manager')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$container->register('security.listener.csrf_protection', CsrfProtectionListener::class)
|
||||
->addArgument(new Reference('security.csrf.token_manager'))
|
||||
->addTag('kernel.event_subscriber')
|
||||
->setPublic(false);
|
||||
}
|
||||
|
||||
protected function registerLogoutHandler(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->has('security.logout_listener') || !$container->has('security.csrf.token_storage')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$csrfTokenStorage = $container->findDefinition('security.csrf.token_storage');
|
||||
$csrfTokenStorageClass = $container->getParameterBag()->resolveValue($csrfTokenStorage->getClass());
|
||||
|
||||
if (!is_subclass_of($csrfTokenStorageClass, 'Symfony\Component\Security\Csrf\TokenStorage\ClearableTokenStorageInterface')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$container->register('security.logout.listener.csrf_token_clearing', CsrfTokenClearingLogoutListener::class)
|
||||
->addArgument(new Reference('security.csrf.token_storage'))
|
||||
->addTag('kernel.event_subscriber')
|
||||
->setPublic(false);
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
trigger_deprecation('symfony/security-bundle', '5.1', 'The "%s" class is deprecated.', RegisterCsrfTokenClearingLogoutHandlerPass::class);
|
||||
|
||||
/**
|
||||
* @deprecated since symfony/security-bundle 5.1
|
||||
*/
|
||||
class RegisterCsrfTokenClearingLogoutHandlerPass extends RegisterCsrfFeaturesPass
|
||||
{
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->has('security.csrf.token_storage')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->registerLogoutHandler($container);
|
||||
}
|
||||
}
|
83
vendor/symfony/security-bundle/DependencyInjection/Compiler/RegisterEntryPointPass.php
vendored
Normal file
83
vendor/symfony/security-bundle/DependencyInjection/Compiler/RegisterEntryPointPass.php
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
|
||||
|
||||
/**
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*/
|
||||
class RegisterEntryPointPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasParameter('security.firewalls')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$firewalls = $container->getParameter('security.firewalls');
|
||||
foreach ($firewalls as $firewallName) {
|
||||
if (!$container->hasDefinition('security.authenticator.manager.'.$firewallName) || !$container->hasParameter('security.'.$firewallName.'._indexed_authenticators')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$entryPoints = [];
|
||||
$indexedAuthenticators = $container->getParameter('security.'.$firewallName.'._indexed_authenticators');
|
||||
// this is a compile-only parameter, removing it cleans up space and avoids unintended usage
|
||||
$container->getParameterBag()->remove('security.'.$firewallName.'._indexed_authenticators');
|
||||
foreach ($indexedAuthenticators as $key => $authenticatorId) {
|
||||
if (!$container->has($authenticatorId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// because this pass runs before ResolveChildDefinitionPass, child definitions didn't inherit the parent class yet
|
||||
$definition = $container->findDefinition($authenticatorId);
|
||||
while (!($authenticatorClass = $definition->getClass()) && $definition instanceof ChildDefinition) {
|
||||
$definition = $container->findDefinition($definition->getParent());
|
||||
}
|
||||
|
||||
if (is_a($authenticatorClass, AuthenticationEntryPointInterface::class, true)) {
|
||||
$entryPoints[$key] = $authenticatorId;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$entryPoints) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$config = $container->getDefinition('security.firewall.map.config.'.$firewallName);
|
||||
$configuredEntryPoint = $config->getArgument(7);
|
||||
|
||||
if (null !== $configuredEntryPoint) {
|
||||
// allow entry points to be configured by authenticator key (e.g. "http_basic")
|
||||
$entryPoint = $entryPoints[$configuredEntryPoint] ?? $configuredEntryPoint;
|
||||
} elseif (1 === \count($entryPoints)) {
|
||||
$entryPoint = array_shift($entryPoints);
|
||||
} else {
|
||||
$entryPointNames = [];
|
||||
foreach ($entryPoints as $key => $serviceId) {
|
||||
$entryPointNames[] = is_numeric($key) ? $serviceId : $key;
|
||||
}
|
||||
|
||||
throw new InvalidConfigurationException(sprintf('Because you have multiple authenticators in firewall "%s", you need to set the "entry_point" key to one of your authenticators ("%s") or a service ID implementing "%s". The "entry_point" determines what should happen (e.g. redirect to "/login") when an anonymous user tries to access a protected page.', $firewallName, implode('", "', $entryPointNames), AuthenticationEntryPointInterface::class));
|
||||
}
|
||||
|
||||
$config->replaceArgument(7, $entryPoint);
|
||||
$container->getDefinition('security.exception_listener.'.$firewallName)->replaceArgument(4, new Reference($entryPoint));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\Security\Core\AuthenticationEvents;
|
||||
use Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent;
|
||||
use Symfony\Component\Security\Http\Event\AuthenticationTokenCreatedEvent;
|
||||
use Symfony\Component\Security\Http\Event\CheckPassportEvent;
|
||||
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
|
||||
use Symfony\Component\Security\Http\Event\LoginFailureEvent;
|
||||
use Symfony\Component\Security\Http\Event\LoginSuccessEvent;
|
||||
use Symfony\Component\Security\Http\Event\LogoutEvent;
|
||||
use Symfony\Component\Security\Http\Event\TokenDeauthenticatedEvent;
|
||||
use Symfony\Component\Security\Http\SecurityEvents;
|
||||
|
||||
/**
|
||||
* Makes sure all event listeners on the global dispatcher are also listening
|
||||
* to events on the firewall-specific dispatchers.
|
||||
*
|
||||
* This compiler pass must be run after RegisterListenersPass of the
|
||||
* EventDispatcher component.
|
||||
*
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class RegisterGlobalSecurityEventListenersPass implements CompilerPassInterface
|
||||
{
|
||||
private const EVENT_BUBBLING_EVENTS = [
|
||||
CheckPassportEvent::class,
|
||||
LoginFailureEvent::class,
|
||||
LoginSuccessEvent::class,
|
||||
LogoutEvent::class,
|
||||
AuthenticationTokenCreatedEvent::class,
|
||||
AuthenticationSuccessEvent::class,
|
||||
InteractiveLoginEvent::class,
|
||||
TokenDeauthenticatedEvent::class,
|
||||
|
||||
// When events are registered by their name
|
||||
AuthenticationEvents::AUTHENTICATION_SUCCESS,
|
||||
SecurityEvents::INTERACTIVE_LOGIN,
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->has('event_dispatcher') || !$container->hasParameter('security.firewalls')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$firewallDispatchers = [];
|
||||
foreach ($container->getParameter('security.firewalls') as $firewallName) {
|
||||
if (!$container->has('security.event_dispatcher.'.$firewallName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$firewallDispatchers[] = $container->findDefinition('security.event_dispatcher.'.$firewallName);
|
||||
}
|
||||
|
||||
$globalDispatcher = $container->findDefinition('event_dispatcher');
|
||||
foreach ($globalDispatcher->getMethodCalls() as $methodCall) {
|
||||
if ('addListener' !== $methodCall[0]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$methodCallArguments = $methodCall[1];
|
||||
if (!\in_array($methodCallArguments[0], self::EVENT_BUBBLING_EVENTS, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($firewallDispatchers as $firewallDispatcher) {
|
||||
$firewallDispatcher->addMethodCall('addListener', $methodCallArguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
39
vendor/symfony/security-bundle/DependencyInjection/Compiler/RegisterLdapLocatorPass.php
vendored
Normal file
39
vendor/symfony/security-bundle/DependencyInjection/Compiler/RegisterLdapLocatorPass.php
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
|
||||
/**
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class RegisterLdapLocatorPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$definition = $container->setDefinition('security.ldap_locator', new Definition(ServiceLocator::class));
|
||||
|
||||
$locators = [];
|
||||
foreach ($container->findTaggedServiceIds('ldap') as $serviceId => $tags) {
|
||||
$locators[$serviceId] = new ServiceClosureArgument(new Reference($serviceId));
|
||||
}
|
||||
|
||||
$definition->addArgument($locators);
|
||||
}
|
||||
}
|
56
vendor/symfony/security-bundle/DependencyInjection/Compiler/RegisterTokenUsageTrackingPass.php
vendored
Normal file
56
vendor/symfony/security-bundle/DependencyInjection/Compiler/RegisterTokenUsageTrackingPass.php
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Monolog\Processor\ProcessorInterface;
|
||||
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
|
||||
/**
|
||||
* Injects the session tracker enabler in "security.context_listener" + binds "security.untracked_token_storage" to ProcessorInterface instances.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class RegisterTokenUsageTrackingPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->has('security.untracked_token_storage')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$processorAutoconfiguration = $container->registerForAutoconfiguration(ProcessorInterface::class);
|
||||
$processorAutoconfiguration->setBindings($processorAutoconfiguration->getBindings() + [
|
||||
TokenStorageInterface::class => new BoundArgument(new Reference('security.untracked_token_storage'), false),
|
||||
]);
|
||||
|
||||
if (!$container->has('session.factory') && !$container->has('session.storage')) {
|
||||
$container->setAlias('security.token_storage', 'security.untracked_token_storage')->setPublic(true);
|
||||
$container->getDefinition('security.untracked_token_storage')->addTag('kernel.reset', ['method' => 'reset']);
|
||||
} elseif ($container->hasDefinition('security.context_listener')) {
|
||||
$tokenStorageClass = $container->getParameterBag()->resolveValue($container->findDefinition('security.token_storage')->getClass());
|
||||
|
||||
if (method_exists($tokenStorageClass, 'enableUsageTracking')) {
|
||||
$container->getDefinition('security.context_listener')
|
||||
->setArgument(6, [new Reference('security.token_storage'), 'enableUsageTracking']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Bundle\SecurityBundle\RememberMe\DecoratedRememberMeHandler;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Replaces the DecoratedRememberMeHandler services with the real definition.
|
||||
*
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class ReplaceDecoratedRememberMeHandlerPass implements CompilerPassInterface
|
||||
{
|
||||
private const HANDLER_TAG = 'security.remember_me_handler';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$handledFirewalls = [];
|
||||
foreach ($container->findTaggedServiceIds(self::HANDLER_TAG) as $definitionId => $rememberMeHandlerTags) {
|
||||
$definition = $container->findDefinition($definitionId);
|
||||
if (DecoratedRememberMeHandler::class !== $definition->getClass()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the actual custom remember me handler definition (passed to the decorator)
|
||||
$realRememberMeHandler = $container->findDefinition((string) $definition->getArgument(0));
|
||||
if (null === $realRememberMeHandler) {
|
||||
throw new \LogicException(sprintf('Invalid service definition for custom remember me handler; no service found with ID "%s".', (string) $definition->getArgument(0)));
|
||||
}
|
||||
|
||||
foreach ($rememberMeHandlerTags as $rememberMeHandlerTag) {
|
||||
// some custom handlers may be used on multiple firewalls in the same application
|
||||
if (\in_array($rememberMeHandlerTag['firewall'], $handledFirewalls, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rememberMeHandler = clone $realRememberMeHandler;
|
||||
$rememberMeHandler->addTag(self::HANDLER_TAG, $rememberMeHandlerTag);
|
||||
$container->setDefinition('security.authenticator.remember_me_handler.'.$rememberMeHandlerTag['firewall'], $rememberMeHandler);
|
||||
|
||||
$handledFirewalls[] = $rememberMeHandlerTag['firewall'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
80
vendor/symfony/security-bundle/DependencyInjection/Compiler/SortFirewallListenersPass.php
vendored
Normal file
80
vendor/symfony/security-bundle/DependencyInjection/Compiler/SortFirewallListenersPass.php
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Security\Http\Firewall\FirewallListenerInterface;
|
||||
|
||||
/**
|
||||
* Sorts firewall listeners based on the execution order provided by FirewallListenerInterface::getPriority().
|
||||
*
|
||||
* @author Christian Scheb <me@christianscheb.de>
|
||||
*/
|
||||
class SortFirewallListenersPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
if (!$container->hasParameter('security.firewalls')) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($container->getParameter('security.firewalls') as $firewallName) {
|
||||
$firewallContextDefinition = $container->getDefinition('security.firewall.map.context.'.$firewallName);
|
||||
$this->sortFirewallContextListeners($firewallContextDefinition, $container);
|
||||
}
|
||||
}
|
||||
|
||||
private function sortFirewallContextListeners(Definition $definition, ContainerBuilder $container): void
|
||||
{
|
||||
/** @var IteratorArgument $listenerIteratorArgument */
|
||||
$listenerIteratorArgument = $definition->getArgument(0);
|
||||
$prioritiesByServiceId = $this->getListenerPriorities($listenerIteratorArgument, $container);
|
||||
|
||||
$listeners = $listenerIteratorArgument->getValues();
|
||||
usort($listeners, function (Reference $a, Reference $b) use ($prioritiesByServiceId) {
|
||||
return $prioritiesByServiceId[(string) $b] <=> $prioritiesByServiceId[(string) $a];
|
||||
});
|
||||
|
||||
$listenerIteratorArgument->setValues(array_values($listeners));
|
||||
}
|
||||
|
||||
private function getListenerPriorities(IteratorArgument $listeners, ContainerBuilder $container): array
|
||||
{
|
||||
$priorities = [];
|
||||
|
||||
foreach ($listeners->getValues() as $reference) {
|
||||
$id = (string) $reference;
|
||||
$def = $container->getDefinition($id);
|
||||
|
||||
// We must assume that the class value has been correctly filled, even if the service is created by a factory
|
||||
$class = $def->getClass();
|
||||
|
||||
if (!$r = $container->getReflectionClass($class)) {
|
||||
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
|
||||
}
|
||||
|
||||
$priority = 0;
|
||||
if ($r->isSubclassOf(FirewallListenerInterface::class)) {
|
||||
$priority = $r->getMethod('getPriority')->invoke(null);
|
||||
}
|
||||
|
||||
$priorities[$id] = $priority;
|
||||
}
|
||||
|
||||
return $priorities;
|
||||
}
|
||||
}
|
521
vendor/symfony/security-bundle/DependencyInjection/MainConfiguration.php
vendored
Normal file
521
vendor/symfony/security-bundle/DependencyInjection/MainConfiguration.php
vendored
Normal file
@ -0,0 +1,521 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AbstractFactory;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AuthenticatorFactoryInterface;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface;
|
||||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
|
||||
use Symfony\Component\Security\Http\Event\LogoutEvent;
|
||||
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy;
|
||||
|
||||
/**
|
||||
* SecurityExtension configuration structure.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class MainConfiguration implements ConfigurationInterface
|
||||
{
|
||||
/** @internal */
|
||||
public const STRATEGY_AFFIRMATIVE = 'affirmative';
|
||||
/** @internal */
|
||||
public const STRATEGY_CONSENSUS = 'consensus';
|
||||
/** @internal */
|
||||
public const STRATEGY_UNANIMOUS = 'unanimous';
|
||||
/** @internal */
|
||||
public const STRATEGY_PRIORITY = 'priority';
|
||||
|
||||
private $factories;
|
||||
private $userProviderFactories;
|
||||
|
||||
/**
|
||||
* @param array<array-key, SecurityFactoryInterface|AuthenticatorFactoryInterface> $factories
|
||||
*/
|
||||
public function __construct(array $factories, array $userProviderFactories)
|
||||
{
|
||||
if (\is_array(current($factories))) {
|
||||
trigger_deprecation('symfony/security-bundle', '5.4', 'Passing an array of arrays as 1st argument to "%s" is deprecated, pass a sorted array of factories instead.', __METHOD__);
|
||||
|
||||
$factories = array_merge(...array_values($factories));
|
||||
}
|
||||
|
||||
$this->factories = $factories;
|
||||
$this->userProviderFactories = $userProviderFactories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the configuration tree builder.
|
||||
*
|
||||
* @return TreeBuilder
|
||||
*/
|
||||
public function getConfigTreeBuilder()
|
||||
{
|
||||
$tb = new TreeBuilder('security');
|
||||
$rootNode = $tb->getRootNode();
|
||||
|
||||
$rootNode
|
||||
->beforeNormalization()
|
||||
->ifTrue(function ($v) {
|
||||
if ($v['encoders'] ?? false) {
|
||||
trigger_deprecation('symfony/security-bundle', '5.3', 'The child node "encoders" at path "security" is deprecated, use "password_hashers" instead.');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return $v['password_hashers'] ?? false;
|
||||
})
|
||||
->then(function ($v) {
|
||||
$v['password_hashers'] = array_merge($v['password_hashers'] ?? [], $v['encoders'] ?? []);
|
||||
$v['encoders'] = $v['password_hashers'];
|
||||
|
||||
return $v;
|
||||
})
|
||||
->end()
|
||||
->children()
|
||||
->scalarNode('access_denied_url')->defaultNull()->example('/foo/error403')->end()
|
||||
->enumNode('session_fixation_strategy')
|
||||
->values([SessionAuthenticationStrategy::NONE, SessionAuthenticationStrategy::MIGRATE, SessionAuthenticationStrategy::INVALIDATE])
|
||||
->defaultValue(SessionAuthenticationStrategy::MIGRATE)
|
||||
->end()
|
||||
->booleanNode('hide_user_not_found')->defaultTrue()->end()
|
||||
->booleanNode('always_authenticate_before_granting')
|
||||
->defaultFalse()
|
||||
->setDeprecated('symfony/security-bundle', '5.4')
|
||||
->end()
|
||||
->booleanNode('erase_credentials')->defaultTrue()->end()
|
||||
->booleanNode('enable_authenticator_manager')->defaultFalse()->info('Enables the new Symfony Security system based on Authenticators, all used authenticators must support this before enabling this.')->end()
|
||||
->arrayNode('access_decision_manager')
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->enumNode('strategy')
|
||||
->values($this->getAccessDecisionStrategies())
|
||||
->end()
|
||||
->scalarNode('service')->end()
|
||||
->scalarNode('strategy_service')->end()
|
||||
->booleanNode('allow_if_all_abstain')->defaultFalse()->end()
|
||||
->booleanNode('allow_if_equal_granted_denied')->defaultTrue()->end()
|
||||
->end()
|
||||
->validate()
|
||||
->ifTrue(function ($v) { return isset($v['strategy'], $v['service']); })
|
||||
->thenInvalid('"strategy" and "service" cannot be used together.')
|
||||
->end()
|
||||
->validate()
|
||||
->ifTrue(function ($v) { return isset($v['strategy'], $v['strategy_service']); })
|
||||
->thenInvalid('"strategy" and "strategy_service" cannot be used together.')
|
||||
->end()
|
||||
->validate()
|
||||
->ifTrue(function ($v) { return isset($v['service'], $v['strategy_service']); })
|
||||
->thenInvalid('"service" and "strategy_service" cannot be used together.')
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
|
||||
$this->addEncodersSection($rootNode);
|
||||
$this->addPasswordHashersSection($rootNode);
|
||||
$this->addProvidersSection($rootNode);
|
||||
$this->addFirewallsSection($rootNode, $this->factories);
|
||||
$this->addAccessControlSection($rootNode);
|
||||
$this->addRoleHierarchySection($rootNode);
|
||||
|
||||
return $tb;
|
||||
}
|
||||
|
||||
private function addRoleHierarchySection(ArrayNodeDefinition $rootNode)
|
||||
{
|
||||
$rootNode
|
||||
->fixXmlConfig('role', 'role_hierarchy')
|
||||
->children()
|
||||
->arrayNode('role_hierarchy')
|
||||
->useAttributeAsKey('id')
|
||||
->prototype('array')
|
||||
->performNoDeepMerging()
|
||||
->beforeNormalization()->ifString()->then(function ($v) { return ['value' => $v]; })->end()
|
||||
->beforeNormalization()
|
||||
->ifTrue(function ($v) { return \is_array($v) && isset($v['value']); })
|
||||
->then(function ($v) { return preg_split('/\s*,\s*/', $v['value']); })
|
||||
->end()
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
|
||||
private function addAccessControlSection(ArrayNodeDefinition $rootNode)
|
||||
{
|
||||
$rootNode
|
||||
->fixXmlConfig('rule', 'access_control')
|
||||
->children()
|
||||
->arrayNode('access_control')
|
||||
->cannotBeOverwritten()
|
||||
->prototype('array')
|
||||
->fixXmlConfig('ip')
|
||||
->fixXmlConfig('method')
|
||||
->children()
|
||||
->scalarNode('requires_channel')->defaultNull()->end()
|
||||
->scalarNode('path')
|
||||
->defaultNull()
|
||||
->info('use the urldecoded format')
|
||||
->example('^/path to resource/')
|
||||
->end()
|
||||
->scalarNode('host')->defaultNull()->end()
|
||||
->integerNode('port')->defaultNull()->end()
|
||||
->arrayNode('ips')
|
||||
->beforeNormalization()->ifString()->then(function ($v) { return [$v]; })->end()
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->arrayNode('methods')
|
||||
->beforeNormalization()->ifString()->then(function ($v) { return preg_split('/\s*,\s*/', $v); })->end()
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->scalarNode('allow_if')->defaultNull()->end()
|
||||
->end()
|
||||
->fixXmlConfig('role')
|
||||
->children()
|
||||
->arrayNode('roles')
|
||||
->beforeNormalization()->ifString()->then(function ($v) { return preg_split('/\s*,\s*/', $v); })->end()
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<array-key, SecurityFactoryInterface|AuthenticatorFactoryInterface> $factories
|
||||
*/
|
||||
private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $factories)
|
||||
{
|
||||
$firewallNodeBuilder = $rootNode
|
||||
->fixXmlConfig('firewall')
|
||||
->children()
|
||||
->arrayNode('firewalls')
|
||||
->isRequired()
|
||||
->requiresAtLeastOneElement()
|
||||
->disallowNewKeysInSubsequentConfigs()
|
||||
->useAttributeAsKey('name')
|
||||
->prototype('array')
|
||||
->fixXmlConfig('required_badge')
|
||||
->children()
|
||||
;
|
||||
|
||||
$firewallNodeBuilder
|
||||
->scalarNode('pattern')->end()
|
||||
->scalarNode('host')->end()
|
||||
->arrayNode('methods')
|
||||
->beforeNormalization()->ifString()->then(function ($v) { return preg_split('/\s*,\s*/', $v); })->end()
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->booleanNode('security')->defaultTrue()->end()
|
||||
->scalarNode('user_checker')
|
||||
->defaultValue('security.user_checker')
|
||||
->treatNullLike('security.user_checker')
|
||||
->info('The UserChecker to use when authenticating users in this firewall.')
|
||||
->end()
|
||||
->scalarNode('request_matcher')->end()
|
||||
->scalarNode('access_denied_url')->end()
|
||||
->scalarNode('access_denied_handler')->end()
|
||||
->scalarNode('entry_point')
|
||||
->info(sprintf('An enabled authenticator name or a service id that implements "%s"', AuthenticationEntryPointInterface::class))
|
||||
->end()
|
||||
->scalarNode('provider')->end()
|
||||
->booleanNode('stateless')->defaultFalse()->end()
|
||||
->booleanNode('lazy')->defaultFalse()->end()
|
||||
->scalarNode('context')->cannotBeEmpty()->end()
|
||||
->arrayNode('logout')
|
||||
->treatTrueLike([])
|
||||
->canBeUnset()
|
||||
->children()
|
||||
->scalarNode('csrf_parameter')->defaultValue('_csrf_token')->end()
|
||||
->scalarNode('csrf_token_generator')->cannotBeEmpty()->end()
|
||||
->scalarNode('csrf_token_id')->defaultValue('logout')->end()
|
||||
->scalarNode('path')->defaultValue('/logout')->end()
|
||||
->scalarNode('target')->defaultValue('/')->end()
|
||||
->scalarNode('success_handler')->setDeprecated('symfony/security-bundle', '5.1', sprintf('The "%%node%%" at path "%%path%%" is deprecated, register a listener on the "%s" event instead.', LogoutEvent::class))->end()
|
||||
->booleanNode('invalidate_session')->defaultTrue()->end()
|
||||
->end()
|
||||
->fixXmlConfig('delete_cookie')
|
||||
->children()
|
||||
->arrayNode('delete_cookies')
|
||||
->normalizeKeys(false)
|
||||
->beforeNormalization()
|
||||
->ifTrue(function ($v) { return \is_array($v) && \is_int(key($v)); })
|
||||
->then(function ($v) { return array_map(function ($v) { return ['name' => $v]; }, $v); })
|
||||
->end()
|
||||
->useAttributeAsKey('name')
|
||||
->prototype('array')
|
||||
->children()
|
||||
->scalarNode('path')->defaultNull()->end()
|
||||
->scalarNode('domain')->defaultNull()->end()
|
||||
->scalarNode('secure')->defaultFalse()->end()
|
||||
->scalarNode('samesite')->defaultNull()->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->fixXmlConfig('handler')
|
||||
->children()
|
||||
->arrayNode('handlers')
|
||||
->prototype('scalar')->setDeprecated('symfony/security-bundle', '5.1', sprintf('The "%%node%%" at path "%%path%%" is deprecated, register a listener on the "%s" event instead.', LogoutEvent::class))->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('switch_user')
|
||||
->canBeUnset()
|
||||
->children()
|
||||
->scalarNode('provider')->end()
|
||||
->scalarNode('parameter')->defaultValue('_switch_user')->end()
|
||||
->scalarNode('role')->defaultValue('ROLE_ALLOWED_TO_SWITCH')->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('required_badges')
|
||||
->info('A list of badges that must be present on the authenticated passport.')
|
||||
->validate()
|
||||
->always()
|
||||
->then(function ($requiredBadges) {
|
||||
return array_map(function ($requiredBadge) {
|
||||
if (class_exists($requiredBadge)) {
|
||||
return $requiredBadge;
|
||||
}
|
||||
|
||||
if (false === strpos($requiredBadge, '\\')) {
|
||||
$fqcn = 'Symfony\Component\Security\Http\Authenticator\Passport\Badge\\'.$requiredBadge;
|
||||
if (class_exists($fqcn)) {
|
||||
return $fqcn;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidConfigurationException(sprintf('Undefined security Badge class "%s" set in "security.firewall.required_badges".', $requiredBadge));
|
||||
}, $requiredBadges);
|
||||
})
|
||||
->end()
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
;
|
||||
|
||||
$abstractFactoryKeys = [];
|
||||
foreach ($factories as $factory) {
|
||||
$name = str_replace('-', '_', $factory->getKey());
|
||||
$factoryNode = $firewallNodeBuilder->arrayNode($name)
|
||||
->canBeUnset()
|
||||
;
|
||||
|
||||
if ($factory instanceof AbstractFactory) {
|
||||
$abstractFactoryKeys[] = $name;
|
||||
}
|
||||
|
||||
$factory->addConfiguration($factoryNode);
|
||||
}
|
||||
|
||||
// check for unreachable check paths
|
||||
$firewallNodeBuilder
|
||||
->end()
|
||||
->validate()
|
||||
->ifTrue(function ($v) {
|
||||
return true === $v['security'] && isset($v['pattern']) && !isset($v['request_matcher']);
|
||||
})
|
||||
->then(function ($firewall) use ($abstractFactoryKeys) {
|
||||
foreach ($abstractFactoryKeys as $k) {
|
||||
if (!isset($firewall[$k]['check_path'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str_contains($firewall[$k]['check_path'], '/') && !preg_match('#'.$firewall['pattern'].'#', $firewall[$k]['check_path'])) {
|
||||
throw new \LogicException(sprintf('The check_path "%s" for login method "%s" is not matched by the firewall pattern "%s".', $firewall[$k]['check_path'], $k, $firewall['pattern']));
|
||||
}
|
||||
}
|
||||
|
||||
return $firewall;
|
||||
})
|
||||
->end()
|
||||
;
|
||||
}
|
||||
|
||||
private function addProvidersSection(ArrayNodeDefinition $rootNode)
|
||||
{
|
||||
$providerNodeBuilder = $rootNode
|
||||
->fixXmlConfig('provider')
|
||||
->children()
|
||||
->arrayNode('providers')
|
||||
->example([
|
||||
'my_memory_provider' => [
|
||||
'memory' => [
|
||||
'users' => [
|
||||
'foo' => ['password' => 'foo', 'roles' => 'ROLE_USER'],
|
||||
'bar' => ['password' => 'bar', 'roles' => '[ROLE_USER, ROLE_ADMIN]'],
|
||||
],
|
||||
],
|
||||
],
|
||||
'my_entity_provider' => ['entity' => ['class' => 'SecurityBundle:User', 'property' => 'username']],
|
||||
])
|
||||
->requiresAtLeastOneElement()
|
||||
->useAttributeAsKey('name')
|
||||
->prototype('array')
|
||||
;
|
||||
|
||||
$providerNodeBuilder
|
||||
->children()
|
||||
->scalarNode('id')->end()
|
||||
->arrayNode('chain')
|
||||
->fixXmlConfig('provider')
|
||||
->children()
|
||||
->arrayNode('providers')
|
||||
->beforeNormalization()
|
||||
->ifString()
|
||||
->then(function ($v) { return preg_split('/\s*,\s*/', $v); })
|
||||
->end()
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
|
||||
foreach ($this->userProviderFactories as $factory) {
|
||||
$name = str_replace('-', '_', $factory->getKey());
|
||||
$factoryNode = $providerNodeBuilder->children()->arrayNode($name)->canBeUnset();
|
||||
|
||||
$factory->addConfiguration($factoryNode);
|
||||
}
|
||||
|
||||
$providerNodeBuilder
|
||||
->validate()
|
||||
->ifTrue(function ($v) { return \count($v) > 1; })
|
||||
->thenInvalid('You cannot set multiple provider types for the same provider')
|
||||
->end()
|
||||
->validate()
|
||||
->ifTrue(function ($v) { return 0 === \count($v); })
|
||||
->thenInvalid('You must set a provider definition for the provider.')
|
||||
->end()
|
||||
;
|
||||
}
|
||||
|
||||
private function addEncodersSection(ArrayNodeDefinition $rootNode)
|
||||
{
|
||||
$rootNode
|
||||
->fixXmlConfig('encoder')
|
||||
->children()
|
||||
->arrayNode('encoders')
|
||||
->example([
|
||||
'App\Entity\User1' => 'auto',
|
||||
'App\Entity\User2' => [
|
||||
'algorithm' => 'auto',
|
||||
'time_cost' => 8,
|
||||
'cost' => 13,
|
||||
],
|
||||
])
|
||||
->requiresAtLeastOneElement()
|
||||
->useAttributeAsKey('class')
|
||||
->prototype('array')
|
||||
->canBeUnset()
|
||||
->performNoDeepMerging()
|
||||
->beforeNormalization()->ifString()->then(function ($v) { return ['algorithm' => $v]; })->end()
|
||||
->children()
|
||||
->scalarNode('algorithm')
|
||||
->cannotBeEmpty()
|
||||
->validate()
|
||||
->ifTrue(function ($v) { return !\is_string($v); })
|
||||
->thenInvalid('You must provide a string value.')
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('migrate_from')
|
||||
->prototype('scalar')->end()
|
||||
->beforeNormalization()->castToArray()->end()
|
||||
->end()
|
||||
->scalarNode('hash_algorithm')->info('Name of hashing algorithm for PBKDF2 (i.e. sha256, sha512, etc..) See hash_algos() for a list of supported algorithms.')->defaultValue('sha512')->end()
|
||||
->scalarNode('key_length')->defaultValue(40)->end()
|
||||
->booleanNode('ignore_case')->defaultFalse()->end()
|
||||
->booleanNode('encode_as_base64')->defaultTrue()->end()
|
||||
->scalarNode('iterations')->defaultValue(5000)->end()
|
||||
->integerNode('cost')
|
||||
->min(4)
|
||||
->max(31)
|
||||
->defaultNull()
|
||||
->end()
|
||||
->scalarNode('memory_cost')->defaultNull()->end()
|
||||
->scalarNode('time_cost')->defaultNull()->end()
|
||||
->scalarNode('id')->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
|
||||
private function addPasswordHashersSection(ArrayNodeDefinition $rootNode)
|
||||
{
|
||||
$rootNode
|
||||
->fixXmlConfig('password_hasher')
|
||||
->children()
|
||||
->arrayNode('password_hashers')
|
||||
->example([
|
||||
'App\Entity\User1' => 'auto',
|
||||
'App\Entity\User2' => [
|
||||
'algorithm' => 'auto',
|
||||
'time_cost' => 8,
|
||||
'cost' => 13,
|
||||
],
|
||||
])
|
||||
->requiresAtLeastOneElement()
|
||||
->useAttributeAsKey('class')
|
||||
->prototype('array')
|
||||
->canBeUnset()
|
||||
->performNoDeepMerging()
|
||||
->beforeNormalization()->ifString()->then(function ($v) { return ['algorithm' => $v]; })->end()
|
||||
->children()
|
||||
->scalarNode('algorithm')
|
||||
->cannotBeEmpty()
|
||||
->validate()
|
||||
->ifTrue(function ($v) { return !\is_string($v); })
|
||||
->thenInvalid('You must provide a string value.')
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('migrate_from')
|
||||
->prototype('scalar')->end()
|
||||
->beforeNormalization()->castToArray()->end()
|
||||
->end()
|
||||
->scalarNode('hash_algorithm')->info('Name of hashing algorithm for PBKDF2 (i.e. sha256, sha512, etc..) See hash_algos() for a list of supported algorithms.')->defaultValue('sha512')->end()
|
||||
->scalarNode('key_length')->defaultValue(40)->end()
|
||||
->booleanNode('ignore_case')->defaultFalse()->end()
|
||||
->booleanNode('encode_as_base64')->defaultTrue()->end()
|
||||
->scalarNode('iterations')->defaultValue(5000)->end()
|
||||
->integerNode('cost')
|
||||
->min(4)
|
||||
->max(31)
|
||||
->defaultNull()
|
||||
->end()
|
||||
->scalarNode('memory_cost')->defaultNull()->end()
|
||||
->scalarNode('time_cost')->defaultNull()->end()
|
||||
->scalarNode('id')->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end();
|
||||
}
|
||||
|
||||
private function getAccessDecisionStrategies(): array
|
||||
{
|
||||
return [
|
||||
self::STRATEGY_AFFIRMATIVE,
|
||||
self::STRATEGY_CONSENSUS,
|
||||
self::STRATEGY_UNANIMOUS,
|
||||
self::STRATEGY_PRIORITY,
|
||||
];
|
||||
}
|
||||
}
|
205
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/AbstractFactory.php
vendored
Normal file
205
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/AbstractFactory.php
vendored
Normal file
@ -0,0 +1,205 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* AbstractFactory is the base class for all classes inheriting from
|
||||
* AbstractAuthenticationListener.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Lukas Kahwe Smith <smith@pooteeweet.org>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
abstract class AbstractFactory implements SecurityFactoryInterface
|
||||
{
|
||||
protected $options = [
|
||||
'check_path' => '/login_check',
|
||||
'use_forward' => false,
|
||||
'require_previous_session' => false,
|
||||
'login_path' => '/login',
|
||||
];
|
||||
|
||||
protected $defaultSuccessHandlerOptions = [
|
||||
'always_use_default_target_path' => false,
|
||||
'default_target_path' => '/',
|
||||
'login_path' => '/login',
|
||||
'target_path_parameter' => '_target_path',
|
||||
'use_referer' => false,
|
||||
];
|
||||
|
||||
protected $defaultFailureHandlerOptions = [
|
||||
'failure_path' => null,
|
||||
'failure_forward' => false,
|
||||
'login_path' => '/login',
|
||||
'failure_path_parameter' => '_failure_path',
|
||||
];
|
||||
|
||||
public function create(ContainerBuilder $container, string $id, array $config, string $userProviderId, ?string $defaultEntryPointId)
|
||||
{
|
||||
// authentication provider
|
||||
$authProviderId = $this->createAuthProvider($container, $id, $config, $userProviderId);
|
||||
|
||||
// authentication listener
|
||||
$listenerId = $this->createListener($container, $id, $config, $userProviderId);
|
||||
|
||||
// add remember-me aware tag if requested
|
||||
if ($this->isRememberMeAware($config)) {
|
||||
$container
|
||||
->getDefinition($listenerId)
|
||||
->addTag('security.remember_me_aware', ['id' => $id, 'provider' => $userProviderId])
|
||||
;
|
||||
}
|
||||
|
||||
// create entry point if applicable (optional)
|
||||
$entryPointId = $this->createEntryPoint($container, $id, $config, $defaultEntryPointId);
|
||||
|
||||
return [$authProviderId, $listenerId, $entryPointId];
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
$builder = $node->children();
|
||||
|
||||
$builder
|
||||
->scalarNode('provider')->end()
|
||||
->booleanNode('remember_me')->defaultTrue()->end()
|
||||
->scalarNode('success_handler')->end()
|
||||
->scalarNode('failure_handler')->end()
|
||||
;
|
||||
|
||||
foreach (array_merge($this->options, $this->defaultSuccessHandlerOptions, $this->defaultFailureHandlerOptions) as $name => $default) {
|
||||
if (\is_bool($default)) {
|
||||
$builder->booleanNode($name)->defaultValue($default);
|
||||
} else {
|
||||
$builder->scalarNode($name)->defaultValue($default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final public function addOption(string $name, $default = null)
|
||||
{
|
||||
$this->options[$name] = $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses must return the id of a service which implements the
|
||||
* AuthenticationProviderInterface.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function createAuthProvider(ContainerBuilder $container, string $id, array $config, string $userProviderId);
|
||||
|
||||
/**
|
||||
* Subclasses must return the id of the abstract listener template.
|
||||
*
|
||||
* Listener definitions should inherit from the AbstractAuthenticationListener
|
||||
* like this:
|
||||
*
|
||||
* <service id="my.listener.id"
|
||||
* class="My\Concrete\Classname"
|
||||
* parent="security.authentication.listener.abstract"
|
||||
* abstract="true" />
|
||||
*
|
||||
* In the above case, this method would return "my.listener.id".
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getListenerId();
|
||||
|
||||
/**
|
||||
* Subclasses may create an entry point of their as they see fit. The
|
||||
* default implementation does not change the default entry point.
|
||||
*
|
||||
* @return string|null the entry point id
|
||||
*/
|
||||
protected function createEntryPoint(ContainerBuilder $container, string $id, array $config, ?string $defaultEntryPointId)
|
||||
{
|
||||
return $defaultEntryPointId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may disable remember-me features for the listener, by
|
||||
* always returning false from this method.
|
||||
*
|
||||
* @return bool Whether a possibly configured RememberMeServices should be set for this listener
|
||||
*/
|
||||
protected function isRememberMeAware(array $config)
|
||||
{
|
||||
return $config['remember_me'];
|
||||
}
|
||||
|
||||
protected function createListener(ContainerBuilder $container, string $id, array $config, string $userProvider)
|
||||
{
|
||||
$listenerId = $this->getListenerId();
|
||||
$listener = new ChildDefinition($listenerId);
|
||||
$listener->replaceArgument(4, $id);
|
||||
$listener->replaceArgument(5, new Reference($this->createAuthenticationSuccessHandler($container, $id, $config)));
|
||||
$listener->replaceArgument(6, new Reference($this->createAuthenticationFailureHandler($container, $id, $config)));
|
||||
$listener->replaceArgument(7, array_intersect_key($config, $this->options));
|
||||
|
||||
$listenerId .= '.'.$id;
|
||||
$container->setDefinition($listenerId, $listener);
|
||||
|
||||
return $listenerId;
|
||||
}
|
||||
|
||||
protected function createAuthenticationSuccessHandler(ContainerBuilder $container, string $id, array $config)
|
||||
{
|
||||
$successHandlerId = $this->getSuccessHandlerId($id);
|
||||
$options = array_intersect_key($config, $this->defaultSuccessHandlerOptions);
|
||||
|
||||
if (isset($config['success_handler'])) {
|
||||
$successHandler = $container->setDefinition($successHandlerId, new ChildDefinition('security.authentication.custom_success_handler'));
|
||||
$successHandler->replaceArgument(0, new Reference($config['success_handler']));
|
||||
$successHandler->replaceArgument(1, $options);
|
||||
$successHandler->replaceArgument(2, $id);
|
||||
} else {
|
||||
$successHandler = $container->setDefinition($successHandlerId, new ChildDefinition('security.authentication.success_handler'));
|
||||
$successHandler->addMethodCall('setOptions', [$options]);
|
||||
$successHandler->addMethodCall('setFirewallName', [$id]);
|
||||
}
|
||||
|
||||
return $successHandlerId;
|
||||
}
|
||||
|
||||
protected function createAuthenticationFailureHandler(ContainerBuilder $container, string $id, array $config)
|
||||
{
|
||||
$id = $this->getFailureHandlerId($id);
|
||||
$options = array_intersect_key($config, $this->defaultFailureHandlerOptions);
|
||||
|
||||
if (isset($config['failure_handler'])) {
|
||||
$failureHandler = $container->setDefinition($id, new ChildDefinition('security.authentication.custom_failure_handler'));
|
||||
$failureHandler->replaceArgument(0, new Reference($config['failure_handler']));
|
||||
$failureHandler->replaceArgument(1, $options);
|
||||
} else {
|
||||
$failureHandler = $container->setDefinition($id, new ChildDefinition('security.authentication.failure_handler'));
|
||||
$failureHandler->addMethodCall('setOptions', [$options]);
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
protected function getSuccessHandlerId(string $id)
|
||||
{
|
||||
return 'security.authentication.success_handler.'.$id.'.'.str_replace('-', '_', $this->getKey());
|
||||
}
|
||||
|
||||
protected function getFailureHandlerId(string $id)
|
||||
{
|
||||
return 'security.authentication.failure_handler.'.$id.'.'.str_replace('-', '_', $this->getKey());
|
||||
}
|
||||
}
|
81
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/AnonymousFactory.php
vendored
Normal file
81
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/AnonymousFactory.php
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Parameter;
|
||||
|
||||
/**
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*
|
||||
* @deprecated since Symfony 5.3, use the new authenticator system instead
|
||||
*/
|
||||
class AnonymousFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface
|
||||
{
|
||||
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
|
||||
{
|
||||
if (null === $config['secret']) {
|
||||
$config['secret'] = new Parameter('container.build_hash');
|
||||
}
|
||||
|
||||
$listenerId = 'security.authentication.listener.anonymous.'.$id;
|
||||
$container
|
||||
->setDefinition($listenerId, new ChildDefinition('security.authentication.listener.anonymous'))
|
||||
->replaceArgument(1, $config['secret'])
|
||||
;
|
||||
|
||||
$providerId = 'security.authentication.provider.anonymous.'.$id;
|
||||
$container
|
||||
->setDefinition($providerId, new ChildDefinition('security.authentication.provider.anonymous'))
|
||||
->replaceArgument(0, $config['secret'])
|
||||
;
|
||||
|
||||
return [$providerId, $listenerId, $defaultEntryPoint];
|
||||
}
|
||||
|
||||
public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId): string
|
||||
{
|
||||
throw new InvalidConfigurationException(sprintf('The authenticator manager no longer has "anonymous" security. Please remove this option under the "%s" firewall'.($config['lazy'] ? ' and add "lazy: true"' : '').'.', $firewallName));
|
||||
}
|
||||
|
||||
public function getPriority()
|
||||
{
|
||||
return -60;
|
||||
}
|
||||
|
||||
public function getPosition()
|
||||
{
|
||||
return 'anonymous';
|
||||
}
|
||||
|
||||
public function getKey()
|
||||
{
|
||||
return 'anonymous';
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $builder)
|
||||
{
|
||||
$builder
|
||||
->beforeNormalization()
|
||||
->ifTrue(function ($v) { return 'lazy' === $v; })
|
||||
->then(function ($v) { return ['lazy' => true]; })
|
||||
->end()
|
||||
->children()
|
||||
->booleanNode('lazy')->defaultFalse()->setDeprecated('symfony/security-bundle', '5.1', 'Using "anonymous: lazy" to make the firewall lazy is deprecated, use "anonymous: true" and "lazy: true" instead.')->end()
|
||||
->scalarNode('secret')->defaultNull()->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* @method int getPriority() defines the position at which the authenticator is called
|
||||
*
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*/
|
||||
interface AuthenticatorFactoryInterface
|
||||
{
|
||||
/**
|
||||
* Creates the authenticator service(s) for the provided configuration.
|
||||
*
|
||||
* @return string|string[] The authenticator service ID(s) to be used by the firewall
|
||||
*/
|
||||
public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId);
|
||||
|
||||
/**
|
||||
* Defines the configuration key used to reference the authenticator
|
||||
* in the firewall configuration.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getKey();
|
||||
|
||||
public function addConfiguration(NodeDefinition $builder);
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class CustomAuthenticatorFactory implements AuthenticatorFactoryInterface, SecurityFactoryInterface
|
||||
{
|
||||
public function create(ContainerBuilder $container, string $id, array $config, string $userProvider, ?string $defaultEntryPoint): array
|
||||
{
|
||||
throw new \LogicException('Custom authenticators are not supported when "security.enable_authenticator_manager" is not set to true.');
|
||||
}
|
||||
|
||||
public function getPriority(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getPosition(): string
|
||||
{
|
||||
return 'pre_auth';
|
||||
}
|
||||
|
||||
public function getKey(): string
|
||||
{
|
||||
return 'custom_authenticators';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ArrayNodeDefinition $builder
|
||||
*/
|
||||
public function addConfiguration(NodeDefinition $builder)
|
||||
{
|
||||
$builder
|
||||
->info('An array of service ids for all of your "authenticators"')
|
||||
->requiresAtLeastOneElement()
|
||||
->prototype('scalar')->end();
|
||||
|
||||
// get the parent array node builder ("firewalls") from inside the children builder
|
||||
$factoryRootNode = $builder->end()->end();
|
||||
$factoryRootNode
|
||||
->fixXmlConfig('custom_authenticator')
|
||||
->validate()
|
||||
->ifTrue(function ($v) { return isset($v['custom_authenticators']) && empty($v['custom_authenticators']); })
|
||||
->then(function ($v) {
|
||||
unset($v['custom_authenticators']);
|
||||
|
||||
return $v;
|
||||
})
|
||||
->end()
|
||||
;
|
||||
}
|
||||
|
||||
public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId): array
|
||||
{
|
||||
return $config;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Can be implemented by a security factory to add a listener to the firewall.
|
||||
*
|
||||
* @author Christian Scheb <me@christianscheb.de>
|
||||
*/
|
||||
interface FirewallListenerFactoryInterface
|
||||
{
|
||||
/**
|
||||
* Creates the firewall listener services for the provided configuration.
|
||||
*
|
||||
* @return string[] The listener service IDs to be used by the firewall
|
||||
*/
|
||||
public function createListeners(ContainerBuilder $container, string $firewallName, array $config): array;
|
||||
}
|
137
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/FormLoginFactory.php
vendored
Normal file
137
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/FormLoginFactory.php
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* FormLoginFactory creates services for form login authentication.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class FormLoginFactory extends AbstractFactory implements AuthenticatorFactoryInterface
|
||||
{
|
||||
public const PRIORITY = -30;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->addOption('username_parameter', '_username');
|
||||
$this->addOption('password_parameter', '_password');
|
||||
$this->addOption('csrf_parameter', '_csrf_token');
|
||||
$this->addOption('csrf_token_id', 'authenticate');
|
||||
$this->addOption('enable_csrf', false);
|
||||
$this->addOption('post_only', true);
|
||||
$this->addOption('form_only', false);
|
||||
}
|
||||
|
||||
public function getPriority(): int
|
||||
{
|
||||
return self::PRIORITY;
|
||||
}
|
||||
|
||||
public function getPosition(): string
|
||||
{
|
||||
return 'form';
|
||||
}
|
||||
|
||||
public function getKey(): string
|
||||
{
|
||||
return 'form-login';
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
parent::addConfiguration($node);
|
||||
|
||||
$node
|
||||
->children()
|
||||
->scalarNode('csrf_token_generator')->cannotBeEmpty()->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
|
||||
protected function getListenerId(): string
|
||||
{
|
||||
return 'security.authentication.listener.form';
|
||||
}
|
||||
|
||||
protected function createAuthProvider(ContainerBuilder $container, string $id, array $config, string $userProviderId): string
|
||||
{
|
||||
if ($config['enable_csrf'] ?? false) {
|
||||
throw new InvalidConfigurationException('The "enable_csrf" option of "form_login" is only available when "security.enable_authenticator_manager" is set to "true", use "csrf_token_generator" instead.');
|
||||
}
|
||||
|
||||
$provider = 'security.authentication.provider.dao.'.$id;
|
||||
$container
|
||||
->setDefinition($provider, new ChildDefinition('security.authentication.provider.dao'))
|
||||
->replaceArgument(0, new Reference($userProviderId))
|
||||
->replaceArgument(1, new Reference('security.user_checker.'.$id))
|
||||
->replaceArgument(2, $id)
|
||||
;
|
||||
|
||||
return $provider;
|
||||
}
|
||||
|
||||
protected function createListener(ContainerBuilder $container, string $id, array $config, string $userProvider)
|
||||
{
|
||||
$listenerId = parent::createListener($container, $id, $config, $userProvider);
|
||||
|
||||
$container
|
||||
->getDefinition($listenerId)
|
||||
->addArgument(isset($config['csrf_token_generator']) ? new Reference($config['csrf_token_generator']) : null)
|
||||
;
|
||||
|
||||
return $listenerId;
|
||||
}
|
||||
|
||||
protected function createEntryPoint(ContainerBuilder $container, string $id, array $config, ?string $defaultEntryPointId): ?string
|
||||
{
|
||||
$entryPointId = 'security.authentication.form_entry_point.'.$id;
|
||||
$container
|
||||
->setDefinition($entryPointId, new ChildDefinition('security.authentication.form_entry_point'))
|
||||
->addArgument(new Reference('security.http_utils'))
|
||||
->addArgument($config['login_path'])
|
||||
->addArgument($config['use_forward'])
|
||||
;
|
||||
|
||||
return $entryPointId;
|
||||
}
|
||||
|
||||
public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId): string
|
||||
{
|
||||
if (isset($config['csrf_token_generator'])) {
|
||||
throw new InvalidConfigurationException('The "csrf_token_generator" option of "form_login" is only available when "security.enable_authenticator_manager" is set to "false", use "enable_csrf" instead.');
|
||||
}
|
||||
|
||||
$authenticatorId = 'security.authenticator.form_login.'.$firewallName;
|
||||
$options = array_intersect_key($config, $this->options);
|
||||
$authenticator = $container
|
||||
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.form_login'))
|
||||
->replaceArgument(1, new Reference($userProviderId))
|
||||
->replaceArgument(2, new Reference($this->createAuthenticationSuccessHandler($container, $firewallName, $config)))
|
||||
->replaceArgument(3, new Reference($this->createAuthenticationFailureHandler($container, $firewallName, $config)))
|
||||
->replaceArgument(4, $options);
|
||||
|
||||
if ($options['use_forward'] ?? false) {
|
||||
$authenticator->addMethodCall('setHttpKernel', [new Reference('http_kernel')]);
|
||||
}
|
||||
|
||||
return $authenticatorId;
|
||||
}
|
||||
}
|
70
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/FormLoginLdapFactory.php
vendored
Normal file
70
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/FormLoginLdapFactory.php
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Security\Core\Exception\LogicException;
|
||||
|
||||
/**
|
||||
* FormLoginLdapFactory creates services for form login ldap authentication.
|
||||
*
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class FormLoginLdapFactory extends FormLoginFactory
|
||||
{
|
||||
use LdapFactoryTrait;
|
||||
|
||||
protected function createAuthProvider(ContainerBuilder $container, string $id, array $config, string $userProviderId): string
|
||||
{
|
||||
$provider = 'security.authentication.provider.ldap_bind.'.$id;
|
||||
$definition = $container
|
||||
->setDefinition($provider, new ChildDefinition('security.authentication.provider.ldap_bind'))
|
||||
->replaceArgument(0, new Reference($userProviderId))
|
||||
->replaceArgument(1, new Reference('security.user_checker.'.$id))
|
||||
->replaceArgument(2, $id)
|
||||
->replaceArgument(3, new Reference($config['service']))
|
||||
->replaceArgument(4, $config['dn_string'])
|
||||
->replaceArgument(6, $config['search_dn'])
|
||||
->replaceArgument(7, $config['search_password'])
|
||||
;
|
||||
|
||||
if (!empty($config['query_string'])) {
|
||||
if ('' === $config['search_dn'] || '' === $config['search_password']) {
|
||||
throw new LogicException('Using the "query_string" config without using a "search_dn" and a "search_password" is not supported.');
|
||||
}
|
||||
$definition->addMethodCall('setQueryString', [$config['query_string']]);
|
||||
}
|
||||
|
||||
return $provider;
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
parent::addConfiguration($node);
|
||||
|
||||
$node
|
||||
->children()
|
||||
->scalarNode('service')->defaultValue('ldap')->end()
|
||||
->scalarNode('dn_string')->defaultValue('{username}')->end()
|
||||
->scalarNode('query_string')->end()
|
||||
->scalarNode('search_dn')->defaultValue('')->end()
|
||||
->scalarNode('search_password')->defaultValue('')->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
}
|
151
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/GuardAuthenticationFactory.php
vendored
Normal file
151
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/GuardAuthenticationFactory.php
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Security\Guard\Authenticator\GuardBridgeAuthenticator;
|
||||
|
||||
/**
|
||||
* Configures the "guard" authentication provider key under a firewall.
|
||||
*
|
||||
* @author Ryan Weaver <ryan@knpuniversity.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class GuardAuthenticationFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface
|
||||
{
|
||||
public function getPosition(): string
|
||||
{
|
||||
return 'pre_auth';
|
||||
}
|
||||
|
||||
public function getPriority(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getKey(): string
|
||||
{
|
||||
return 'guard';
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
$node
|
||||
->fixXmlConfig('authenticator')
|
||||
->children()
|
||||
->scalarNode('provider')
|
||||
->info('A key from the "providers" section of your security config, in case your user provider is different than the firewall')
|
||||
->end()
|
||||
->scalarNode('entry_point')
|
||||
->info('A service id (of one of your authenticators) whose start() method should be called when an anonymous user hits a page that requires authentication')
|
||||
->defaultValue(null)
|
||||
->end()
|
||||
->arrayNode('authenticators')
|
||||
->info('An array of service ids for all of your "authenticators"')
|
||||
->requiresAtLeastOneElement()
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
|
||||
public function create(ContainerBuilder $container, string $id, array $config, string $userProvider, ?string $defaultEntryPoint): array
|
||||
{
|
||||
$authenticatorIds = $config['authenticators'];
|
||||
$authenticatorReferences = [];
|
||||
foreach ($authenticatorIds as $authenticatorId) {
|
||||
$authenticatorReferences[] = new Reference($authenticatorId);
|
||||
}
|
||||
|
||||
$authenticators = new IteratorArgument($authenticatorReferences);
|
||||
|
||||
// configure the GuardAuthenticationFactory to have the dynamic constructor arguments
|
||||
$providerId = 'security.authentication.provider.guard.'.$id;
|
||||
$container
|
||||
->setDefinition($providerId, new ChildDefinition('security.authentication.provider.guard'))
|
||||
->replaceArgument(0, $authenticators)
|
||||
->replaceArgument(1, new Reference($userProvider))
|
||||
->replaceArgument(2, $id)
|
||||
->replaceArgument(3, new Reference('security.user_checker.'.$id))
|
||||
;
|
||||
|
||||
// listener
|
||||
$listenerId = 'security.authentication.listener.guard.'.$id;
|
||||
$listener = $container->setDefinition($listenerId, new ChildDefinition('security.authentication.listener.guard'));
|
||||
$listener->replaceArgument(2, $id);
|
||||
$listener->replaceArgument(3, $authenticators);
|
||||
|
||||
// determine the entryPointId to use
|
||||
$entryPointId = $this->determineEntryPoint($defaultEntryPoint, $config);
|
||||
|
||||
// this is always injected - then the listener decides if it should be used
|
||||
$container
|
||||
->getDefinition($listenerId)
|
||||
->addTag('security.remember_me_aware', ['id' => $id, 'provider' => $userProvider]);
|
||||
|
||||
return [$providerId, $listenerId, $entryPointId];
|
||||
}
|
||||
|
||||
public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId)
|
||||
{
|
||||
$userProvider = new Reference($userProviderId);
|
||||
$authenticatorIds = [];
|
||||
|
||||
if (isset($config['entry_point'])) {
|
||||
throw new InvalidConfigurationException('The "security.firewall.'.$firewallName.'.guard.entry_point" option has no effect in the new authenticator system, configure "security.firewall.'.$firewallName.'.entry_point" instead.');
|
||||
}
|
||||
|
||||
$guardAuthenticatorIds = $config['authenticators'];
|
||||
foreach ($guardAuthenticatorIds as $i => $guardAuthenticatorId) {
|
||||
$container->setDefinition($authenticatorIds[] = 'security.authenticator.guard.'.$firewallName.'.'.$i, new Definition(GuardBridgeAuthenticator::class))
|
||||
->setArguments([
|
||||
new Reference($guardAuthenticatorId),
|
||||
$userProvider,
|
||||
]);
|
||||
}
|
||||
|
||||
return $authenticatorIds;
|
||||
}
|
||||
|
||||
private function determineEntryPoint(?string $defaultEntryPointId, array $config): string
|
||||
{
|
||||
if ($defaultEntryPointId) {
|
||||
// explode if they've configured the entry_point, but there is already one
|
||||
if ($config['entry_point']) {
|
||||
throw new \LogicException(sprintf('The guard authentication provider cannot use the "%s" entry_point because another entry point is already configured by another provider! Either remove the other provider or move the entry_point configuration as a root key under your firewall (i.e. at the same level as "guard").', $config['entry_point']));
|
||||
}
|
||||
|
||||
return $defaultEntryPointId;
|
||||
}
|
||||
|
||||
if ($config['entry_point']) {
|
||||
// if it's configured explicitly, use it!
|
||||
return $config['entry_point'];
|
||||
}
|
||||
|
||||
$authenticatorIds = $config['authenticators'];
|
||||
if (1 == \count($authenticatorIds)) {
|
||||
// if there is only one authenticator, use that as the entry point
|
||||
return array_shift($authenticatorIds);
|
||||
}
|
||||
|
||||
// we have multiple entry points - we must ask them to configure one
|
||||
throw new \LogicException(sprintf('Because you have multiple guard authenticators, you need to set the "guard.entry_point" key to one of your authenticators (%s).', implode(', ', $authenticatorIds)));
|
||||
}
|
||||
}
|
95
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/HttpBasicFactory.php
vendored
Normal file
95
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/HttpBasicFactory.php
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* HttpBasicFactory creates services for HTTP basic authentication.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class HttpBasicFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface
|
||||
{
|
||||
public const PRIORITY = -50;
|
||||
|
||||
public function create(ContainerBuilder $container, string $id, array $config, string $userProvider, ?string $defaultEntryPoint): array
|
||||
{
|
||||
$provider = 'security.authentication.provider.dao.'.$id;
|
||||
$container
|
||||
->setDefinition($provider, new ChildDefinition('security.authentication.provider.dao'))
|
||||
->replaceArgument(0, new Reference($userProvider))
|
||||
->replaceArgument(1, new Reference('security.user_checker.'.$id))
|
||||
->replaceArgument(2, $id)
|
||||
;
|
||||
|
||||
// entry point
|
||||
$entryPointId = $defaultEntryPoint;
|
||||
if (null === $entryPointId) {
|
||||
$entryPointId = 'security.authentication.basic_entry_point.'.$id;
|
||||
$container
|
||||
->setDefinition($entryPointId, new ChildDefinition('security.authentication.basic_entry_point'))
|
||||
->addArgument($config['realm'])
|
||||
;
|
||||
}
|
||||
|
||||
// listener
|
||||
$listenerId = 'security.authentication.listener.basic.'.$id;
|
||||
$listener = $container->setDefinition($listenerId, new ChildDefinition('security.authentication.listener.basic'));
|
||||
$listener->replaceArgument(2, $id);
|
||||
$listener->replaceArgument(3, new Reference($entryPointId));
|
||||
$listener->addMethodCall('setSessionAuthenticationStrategy', [new Reference('security.authentication.session_strategy.'.$id)]);
|
||||
|
||||
return [$provider, $listenerId, $entryPointId];
|
||||
}
|
||||
|
||||
public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId): string
|
||||
{
|
||||
$authenticatorId = 'security.authenticator.http_basic.'.$firewallName;
|
||||
$container
|
||||
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.http_basic'))
|
||||
->replaceArgument(0, $config['realm'])
|
||||
->replaceArgument(1, new Reference($userProviderId));
|
||||
|
||||
return $authenticatorId;
|
||||
}
|
||||
|
||||
public function getPriority(): int
|
||||
{
|
||||
return self::PRIORITY;
|
||||
}
|
||||
|
||||
public function getPosition(): string
|
||||
{
|
||||
return 'http';
|
||||
}
|
||||
|
||||
public function getKey(): string
|
||||
{
|
||||
return 'http-basic';
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
$node
|
||||
->children()
|
||||
->scalarNode('provider')->end()
|
||||
->scalarNode('realm')->defaultValue('Secured Area')->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
}
|
87
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/HttpBasicLdapFactory.php
vendored
Normal file
87
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/HttpBasicLdapFactory.php
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Security\Core\Exception\LogicException;
|
||||
|
||||
/**
|
||||
* HttpBasicFactory creates services for HTTP basic authentication.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class HttpBasicLdapFactory extends HttpBasicFactory
|
||||
{
|
||||
use LdapFactoryTrait;
|
||||
|
||||
public function create(ContainerBuilder $container, string $id, array $config, string $userProvider, ?string $defaultEntryPoint): array
|
||||
{
|
||||
$provider = 'security.authentication.provider.ldap_bind.'.$id;
|
||||
$definition = $container
|
||||
->setDefinition($provider, new ChildDefinition('security.authentication.provider.ldap_bind'))
|
||||
->replaceArgument(0, new Reference($userProvider))
|
||||
->replaceArgument(1, new Reference('security.user_checker.'.$id))
|
||||
->replaceArgument(2, $id)
|
||||
->replaceArgument(3, new Reference($config['service']))
|
||||
->replaceArgument(4, $config['dn_string'])
|
||||
->replaceArgument(6, $config['search_dn'])
|
||||
->replaceArgument(7, $config['search_password'])
|
||||
;
|
||||
|
||||
// entry point
|
||||
$entryPointId = $defaultEntryPoint;
|
||||
|
||||
if (null === $entryPointId) {
|
||||
$entryPointId = 'security.authentication.basic_entry_point.'.$id;
|
||||
$container
|
||||
->setDefinition($entryPointId, new ChildDefinition('security.authentication.basic_entry_point'))
|
||||
->addArgument($config['realm']);
|
||||
}
|
||||
|
||||
if (!empty($config['query_string'])) {
|
||||
if ('' === $config['search_dn'] || '' === $config['search_password']) {
|
||||
throw new LogicException('Using the "query_string" config without using a "search_dn" and a "search_password" is not supported.');
|
||||
}
|
||||
$definition->addMethodCall('setQueryString', [$config['query_string']]);
|
||||
}
|
||||
|
||||
// listener
|
||||
$listenerId = 'security.authentication.listener.basic.'.$id;
|
||||
$listener = $container->setDefinition($listenerId, new ChildDefinition('security.authentication.listener.basic'));
|
||||
$listener->replaceArgument(2, $id);
|
||||
$listener->replaceArgument(3, new Reference($entryPointId));
|
||||
|
||||
return [$provider, $listenerId, $entryPointId];
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
parent::addConfiguration($node);
|
||||
|
||||
$node
|
||||
->children()
|
||||
->scalarNode('service')->defaultValue('ldap')->end()
|
||||
->scalarNode('dn_string')->defaultValue('{username}')->end()
|
||||
->scalarNode('query_string')->end()
|
||||
->scalarNode('search_dn')->defaultValue('')->end()
|
||||
->scalarNode('search_password')->defaultValue('')->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
}
|
122
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/JsonLoginFactory.php
vendored
Normal file
122
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/JsonLoginFactory.php
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* JsonLoginFactory creates services for JSON login authentication.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class JsonLoginFactory extends AbstractFactory implements AuthenticatorFactoryInterface
|
||||
{
|
||||
public const PRIORITY = -40;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->addOption('username_path', 'username');
|
||||
$this->addOption('password_path', 'password');
|
||||
$this->defaultFailureHandlerOptions = [];
|
||||
$this->defaultSuccessHandlerOptions = [];
|
||||
}
|
||||
|
||||
public function getPriority(): int
|
||||
{
|
||||
return self::PRIORITY;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPosition(): string
|
||||
{
|
||||
return 'form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getKey(): string
|
||||
{
|
||||
return 'json-login';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createAuthProvider(ContainerBuilder $container, string $id, array $config, string $userProviderId): string
|
||||
{
|
||||
$provider = 'security.authentication.provider.dao.'.$id;
|
||||
$container
|
||||
->setDefinition($provider, new ChildDefinition('security.authentication.provider.dao'))
|
||||
->replaceArgument(0, new Reference($userProviderId))
|
||||
->replaceArgument(1, new Reference('security.user_checker.'.$id))
|
||||
->replaceArgument(2, $id)
|
||||
;
|
||||
|
||||
return $provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getListenerId(): string
|
||||
{
|
||||
return 'security.authentication.listener.json';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function isRememberMeAware(array $config): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createListener(ContainerBuilder $container, string $id, array $config, string $userProvider)
|
||||
{
|
||||
$listenerId = $this->getListenerId();
|
||||
$listener = new ChildDefinition($listenerId);
|
||||
$listener->replaceArgument(3, $id);
|
||||
$listener->replaceArgument(4, isset($config['success_handler']) ? new Reference($this->createAuthenticationSuccessHandler($container, $id, $config)) : null);
|
||||
$listener->replaceArgument(5, isset($config['failure_handler']) ? new Reference($this->createAuthenticationFailureHandler($container, $id, $config)) : null);
|
||||
$listener->replaceArgument(6, array_intersect_key($config, $this->options));
|
||||
$listener->addMethodCall('setSessionAuthenticationStrategy', [new Reference('security.authentication.session_strategy.'.$id)]);
|
||||
|
||||
$listenerId .= '.'.$id;
|
||||
$container->setDefinition($listenerId, $listener);
|
||||
|
||||
return $listenerId;
|
||||
}
|
||||
|
||||
public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId)
|
||||
{
|
||||
$authenticatorId = 'security.authenticator.json_login.'.$firewallName;
|
||||
$options = array_intersect_key($config, $this->options);
|
||||
$container
|
||||
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.json_login'))
|
||||
->replaceArgument(1, new Reference($userProviderId))
|
||||
->replaceArgument(2, isset($config['success_handler']) ? new Reference($this->createAuthenticationSuccessHandler($container, $firewallName, $config)) : null)
|
||||
->replaceArgument(3, isset($config['failure_handler']) ? new Reference($this->createAuthenticationFailureHandler($container, $firewallName, $config)) : null)
|
||||
->replaceArgument(4, $options);
|
||||
|
||||
return $authenticatorId;
|
||||
}
|
||||
}
|
67
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/JsonLoginLdapFactory.php
vendored
Normal file
67
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/JsonLoginLdapFactory.php
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Security\Core\Exception\LogicException;
|
||||
|
||||
/**
|
||||
* JsonLoginLdapFactory creates services for json login ldap authentication.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class JsonLoginLdapFactory extends JsonLoginFactory
|
||||
{
|
||||
use LdapFactoryTrait;
|
||||
|
||||
protected function createAuthProvider(ContainerBuilder $container, string $id, array $config, string $userProviderId): string
|
||||
{
|
||||
$provider = 'security.authentication.provider.ldap_bind.'.$id;
|
||||
$definition = $container
|
||||
->setDefinition($provider, new ChildDefinition('security.authentication.provider.ldap_bind'))
|
||||
->replaceArgument(0, new Reference($userProviderId))
|
||||
->replaceArgument(1, new Reference('security.user_checker.'.$id))
|
||||
->replaceArgument(2, $id)
|
||||
->replaceArgument(3, new Reference($config['service']))
|
||||
->replaceArgument(4, $config['dn_string'])
|
||||
->replaceArgument(6, $config['search_dn'])
|
||||
->replaceArgument(7, $config['search_password'])
|
||||
;
|
||||
|
||||
if (!empty($config['query_string'])) {
|
||||
if ('' === $config['search_dn'] || '' === $config['search_password']) {
|
||||
throw new LogicException('Using the "query_string" config without using a "search_dn" and a "search_password" is not supported.');
|
||||
}
|
||||
$definition->addMethodCall('setQueryString', [$config['query_string']]);
|
||||
}
|
||||
|
||||
return $provider;
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
parent::addConfiguration($node);
|
||||
|
||||
$node
|
||||
->children()
|
||||
->scalarNode('service')->defaultValue('ldap')->end()
|
||||
->scalarNode('dn_string')->defaultValue('{username}')->end()
|
||||
->scalarNode('query_string')->end()
|
||||
->scalarNode('search_dn')->defaultValue('')->end()
|
||||
->scalarNode('search_password')->defaultValue('')->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
}
|
69
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/LdapFactoryTrait.php
vendored
Normal file
69
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/LdapFactoryTrait.php
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Ldap\Security\CheckLdapCredentialsListener;
|
||||
use Symfony\Component\Ldap\Security\LdapAuthenticator;
|
||||
|
||||
/**
|
||||
* A trait decorating the authenticator with LDAP functionality.
|
||||
*
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
trait LdapFactoryTrait
|
||||
{
|
||||
public function getKey(): string
|
||||
{
|
||||
return parent::getKey().'-ldap';
|
||||
}
|
||||
|
||||
public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId): string
|
||||
{
|
||||
$key = str_replace('-', '_', $this->getKey());
|
||||
if (!class_exists(LdapAuthenticator::class)) {
|
||||
throw new \LogicException(sprintf('The "%s" authenticator requires the "symfony/ldap" package version "5.1" or higher.', $key));
|
||||
}
|
||||
|
||||
$authenticatorId = parent::createAuthenticator($container, $firewallName, $config, $userProviderId);
|
||||
|
||||
$container->setDefinition('security.listener.'.$key.'.'.$firewallName, new Definition(CheckLdapCredentialsListener::class))
|
||||
->addTag('kernel.event_subscriber', ['dispatcher' => 'security.event_dispatcher.'.$firewallName])
|
||||
->addArgument(new Reference('security.ldap_locator'))
|
||||
;
|
||||
|
||||
$ldapAuthenticatorId = 'security.authenticator.'.$key.'.'.$firewallName;
|
||||
$definition = $container->setDefinition($ldapAuthenticatorId, new Definition(LdapAuthenticator::class))
|
||||
->setArguments([
|
||||
new Reference($authenticatorId),
|
||||
$config['service'],
|
||||
$config['dn_string'],
|
||||
$config['search_dn'],
|
||||
$config['search_password'],
|
||||
]);
|
||||
|
||||
if (!empty($config['query_string'])) {
|
||||
if ('' === $config['search_dn'] || '' === $config['search_password']) {
|
||||
throw new InvalidConfigurationException('Using the "query_string" config without using a "search_dn" and a "search_password" is not supported.');
|
||||
}
|
||||
|
||||
$definition->addArgument($config['query_string']);
|
||||
}
|
||||
|
||||
return $ldapAuthenticatorId;
|
||||
}
|
||||
}
|
181
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/LoginLinkFactory.php
vendored
Normal file
181
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/LoginLinkFactory.php
vendored
Normal file
@ -0,0 +1,181 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
|
||||
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
|
||||
use Symfony\Component\Security\Http\LoginLink\LoginLinkHandler;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class LoginLinkFactory extends AbstractFactory implements AuthenticatorFactoryInterface
|
||||
{
|
||||
public const PRIORITY = -20;
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
/** @var NodeBuilder $builder */
|
||||
$builder = $node->fixXmlConfig('signature_property', 'signature_properties')->children();
|
||||
|
||||
$builder
|
||||
->scalarNode('check_route')
|
||||
->isRequired()
|
||||
->info('Route that will validate the login link - e.g. "app_login_link_verify".')
|
||||
->end()
|
||||
->scalarNode('check_post_only')
|
||||
->defaultFalse()
|
||||
->info('If true, only HTTP POST requests to "check_route" will be handled by the authenticator.')
|
||||
->end()
|
||||
->arrayNode('signature_properties')
|
||||
->isRequired()
|
||||
->prototype('scalar')->end()
|
||||
->requiresAtLeastOneElement()
|
||||
->info('An array of properties on your User that are used to sign the link. If any of these change, all existing links will become invalid.')
|
||||
->example(['email', 'password'])
|
||||
->end()
|
||||
->integerNode('lifetime')
|
||||
->defaultValue(600)
|
||||
->info('The lifetime of the login link in seconds.')
|
||||
->end()
|
||||
->integerNode('max_uses')
|
||||
->defaultNull()
|
||||
->info('Max number of times a login link can be used - null means unlimited within lifetime.')
|
||||
->end()
|
||||
->scalarNode('used_link_cache')
|
||||
->info('Cache service id used to expired links of max_uses is set.')
|
||||
->end()
|
||||
->scalarNode('success_handler')
|
||||
->info(sprintf('A service id that implements %s.', AuthenticationSuccessHandlerInterface::class))
|
||||
->end()
|
||||
->scalarNode('failure_handler')
|
||||
->info(sprintf('A service id that implements %s.', AuthenticationFailureHandlerInterface::class))
|
||||
->end()
|
||||
->scalarNode('provider')
|
||||
->info('The user provider to load users from.')
|
||||
->end()
|
||||
;
|
||||
|
||||
foreach (array_merge($this->defaultSuccessHandlerOptions, $this->defaultFailureHandlerOptions) as $name => $default) {
|
||||
if (\is_bool($default)) {
|
||||
$builder->booleanNode($name)->defaultValue($default);
|
||||
} else {
|
||||
$builder->scalarNode($name)->defaultValue($default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getKey(): string
|
||||
{
|
||||
return 'login-link';
|
||||
}
|
||||
|
||||
public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId): string
|
||||
{
|
||||
if (!class_exists(LoginLinkHandler::class)) {
|
||||
throw new \LogicException('Login login link requires symfony/security-http:^5.2.');
|
||||
}
|
||||
|
||||
if (!$container->hasDefinition('security.authenticator.login_link')) {
|
||||
$loader = new PhpFileLoader($container, new FileLocator(\dirname(__DIR__).'/../../Resources/config'));
|
||||
$loader->load('security_authenticator_login_link.php');
|
||||
}
|
||||
|
||||
if (null !== $config['max_uses'] && !isset($config['used_link_cache'])) {
|
||||
$config['used_link_cache'] = 'security.authenticator.cache.expired_links';
|
||||
$defaultCacheDefinition = $container->getDefinition($config['used_link_cache']);
|
||||
if (!$defaultCacheDefinition->hasTag('cache.pool')) {
|
||||
$defaultCacheDefinition->addTag('cache.pool');
|
||||
}
|
||||
}
|
||||
|
||||
$expiredStorageId = null;
|
||||
if (isset($config['used_link_cache'])) {
|
||||
$expiredStorageId = 'security.authenticator.expired_login_link_storage.'.$firewallName;
|
||||
$container
|
||||
->setDefinition($expiredStorageId, new ChildDefinition('security.authenticator.expired_login_link_storage'))
|
||||
->replaceArgument(0, new Reference($config['used_link_cache']))
|
||||
->replaceArgument(1, $config['lifetime']);
|
||||
}
|
||||
|
||||
$signatureHasherId = 'security.authenticator.login_link_signature_hasher.'.$firewallName;
|
||||
$container
|
||||
->setDefinition($signatureHasherId, new ChildDefinition('security.authenticator.abstract_login_link_signature_hasher'))
|
||||
->replaceArgument(1, $config['signature_properties'])
|
||||
->replaceArgument(3, $expiredStorageId ? new Reference($expiredStorageId) : null)
|
||||
->replaceArgument(4, $config['max_uses'] ?? null)
|
||||
;
|
||||
|
||||
$linkerId = 'security.authenticator.login_link_handler.'.$firewallName;
|
||||
$linkerOptions = [
|
||||
'route_name' => $config['check_route'],
|
||||
'lifetime' => $config['lifetime'],
|
||||
];
|
||||
$container
|
||||
->setDefinition($linkerId, new ChildDefinition('security.authenticator.abstract_login_link_handler'))
|
||||
->replaceArgument(1, new Reference($userProviderId))
|
||||
->replaceArgument(2, new Reference($signatureHasherId))
|
||||
->replaceArgument(3, $linkerOptions)
|
||||
->addTag('security.authenticator.login_linker', ['firewall' => $firewallName])
|
||||
;
|
||||
|
||||
$authenticatorId = 'security.authenticator.login_link.'.$firewallName;
|
||||
$container
|
||||
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.login_link'))
|
||||
->replaceArgument(0, new Reference($linkerId))
|
||||
->replaceArgument(2, new Reference($this->createAuthenticationSuccessHandler($container, $firewallName, $config)))
|
||||
->replaceArgument(3, new Reference($this->createAuthenticationFailureHandler($container, $firewallName, $config)))
|
||||
->replaceArgument(4, [
|
||||
'check_route' => $config['check_route'],
|
||||
'check_post_only' => $config['check_post_only'],
|
||||
]);
|
||||
|
||||
return $authenticatorId;
|
||||
}
|
||||
|
||||
public function getPriority(): int
|
||||
{
|
||||
return self::PRIORITY;
|
||||
}
|
||||
|
||||
public function getPosition(): string
|
||||
{
|
||||
return 'form';
|
||||
}
|
||||
|
||||
protected function createAuthProvider(ContainerBuilder $container, string $id, array $config, string $userProviderId): string
|
||||
{
|
||||
throw new \Exception('The old authentication system is not supported with login_link.');
|
||||
}
|
||||
|
||||
protected function getListenerId(): string
|
||||
{
|
||||
throw new \Exception('The old authentication system is not supported with login_link.');
|
||||
}
|
||||
|
||||
protected function createListener(ContainerBuilder $container, string $id, array $config, string $userProvider)
|
||||
{
|
||||
throw new \Exception('The old authentication system is not supported with login_link.');
|
||||
}
|
||||
|
||||
protected function createEntryPoint(ContainerBuilder $container, string $id, array $config, ?string $defaultEntryPointId): ?string
|
||||
{
|
||||
throw new \Exception('The old authentication system is not supported with login_link.');
|
||||
}
|
||||
}
|
107
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php
vendored
Normal file
107
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/LoginThrottlingFactory.php
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkExtension;
|
||||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\HttpFoundation\RateLimiter\RequestRateLimiterInterface;
|
||||
use Symfony\Component\RateLimiter\RateLimiterFactory;
|
||||
use Symfony\Component\Security\Http\EventListener\LoginThrottlingListener;
|
||||
use Symfony\Component\Security\Http\RateLimiter\DefaultLoginRateLimiter;
|
||||
|
||||
/**
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class LoginThrottlingFactory implements AuthenticatorFactoryInterface, SecurityFactoryInterface
|
||||
{
|
||||
public function create(ContainerBuilder $container, string $id, array $config, string $userProvider, ?string $defaultEntryPoint): array
|
||||
{
|
||||
throw new \LogicException('Login throttling is not supported when "security.enable_authenticator_manager" is not set to true.');
|
||||
}
|
||||
|
||||
public function getPriority(): int
|
||||
{
|
||||
// this factory doesn't register any authenticators, this priority doesn't matter
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getPosition(): string
|
||||
{
|
||||
// this factory doesn't register any authenticators, this position doesn't matter
|
||||
return 'pre_auth';
|
||||
}
|
||||
|
||||
public function getKey(): string
|
||||
{
|
||||
return 'login_throttling';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ArrayNodeDefinition $builder
|
||||
*/
|
||||
public function addConfiguration(NodeDefinition $builder)
|
||||
{
|
||||
$builder
|
||||
->children()
|
||||
->scalarNode('limiter')->info(sprintf('A service id implementing "%s".', RequestRateLimiterInterface::class))->end()
|
||||
->integerNode('max_attempts')->defaultValue(5)->end()
|
||||
->scalarNode('interval')->defaultValue('1 minute')->end()
|
||||
->scalarNode('lock_factory')->info('The service ID of the lock factory used by the login rate limiter (or null to disable locking)')->defaultNull()->end()
|
||||
->end();
|
||||
}
|
||||
|
||||
public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId): array
|
||||
{
|
||||
if (!class_exists(LoginThrottlingListener::class)) {
|
||||
throw new \LogicException('Login throttling requires symfony/security-http:^5.2.');
|
||||
}
|
||||
|
||||
if (!class_exists(RateLimiterFactory::class)) {
|
||||
throw new \LogicException('Login throttling requires the Rate Limiter component. Try running "composer require symfony/rate-limiter".');
|
||||
}
|
||||
|
||||
if (!isset($config['limiter'])) {
|
||||
if (!class_exists(FrameworkExtension::class) || !method_exists(FrameworkExtension::class, 'registerRateLimiter')) {
|
||||
throw new \LogicException('You must either configure a rate limiter for "security.firewalls.'.$firewallName.'.login_throttling" or install symfony/framework-bundle:^5.2.');
|
||||
}
|
||||
|
||||
$limiterOptions = [
|
||||
'policy' => 'fixed_window',
|
||||
'limit' => $config['max_attempts'],
|
||||
'interval' => $config['interval'],
|
||||
'lock_factory' => $config['lock_factory'],
|
||||
];
|
||||
FrameworkExtension::registerRateLimiter($container, $localId = '_login_local_'.$firewallName, $limiterOptions);
|
||||
|
||||
$limiterOptions['limit'] = 5 * $config['max_attempts'];
|
||||
FrameworkExtension::registerRateLimiter($container, $globalId = '_login_global_'.$firewallName, $limiterOptions);
|
||||
|
||||
$container->register($config['limiter'] = 'security.login_throttling.'.$firewallName.'.limiter', DefaultLoginRateLimiter::class)
|
||||
->addArgument(new Reference('limiter.'.$globalId))
|
||||
->addArgument(new Reference('limiter.'.$localId))
|
||||
;
|
||||
}
|
||||
|
||||
$container
|
||||
->setDefinition('security.listener.login_throttling.'.$firewallName, new ChildDefinition('security.listener.login_throttling'))
|
||||
->replaceArgument(1, new Reference($config['limiter']))
|
||||
->addTag('kernel.event_subscriber', ['dispatcher' => 'security.event_dispatcher.'.$firewallName]);
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
374
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/RememberMeFactory.php
vendored
Normal file
374
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/RememberMeFactory.php
vendored
Normal file
@ -0,0 +1,374 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Bridge\Doctrine\Security\RememberMe\DoctrineTokenProvider;
|
||||
use Symfony\Bundle\SecurityBundle\RememberMe\DecoratedRememberMeHandler;
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\HttpFoundation\Cookie;
|
||||
use Symfony\Component\Security\Core\Authentication\RememberMe\CacheTokenVerifier;
|
||||
use Symfony\Component\Security\Http\EventListener\RememberMeLogoutListener;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class RememberMeFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface, PrependExtensionInterface
|
||||
{
|
||||
public const PRIORITY = -50;
|
||||
|
||||
protected $options = [
|
||||
'name' => 'REMEMBERME',
|
||||
'lifetime' => 31536000,
|
||||
'path' => '/',
|
||||
'domain' => null,
|
||||
'secure' => false,
|
||||
'httponly' => true,
|
||||
'samesite' => null,
|
||||
'always_remember_me' => false,
|
||||
'remember_me_parameter' => '_remember_me',
|
||||
];
|
||||
|
||||
public function create(ContainerBuilder $container, string $id, array $config, ?string $userProvider, ?string $defaultEntryPoint): array
|
||||
{
|
||||
// authentication provider
|
||||
$authProviderId = 'security.authentication.provider.rememberme.'.$id;
|
||||
$container
|
||||
->setDefinition($authProviderId, new ChildDefinition('security.authentication.provider.rememberme'))
|
||||
->replaceArgument(0, new Reference('security.user_checker.'.$id))
|
||||
->addArgument($config['secret'])
|
||||
->addArgument($id)
|
||||
;
|
||||
|
||||
// remember me services
|
||||
$templateId = $this->generateRememberMeServicesTemplateId($config, $id);
|
||||
$rememberMeServicesId = $templateId.'.'.$id;
|
||||
|
||||
// attach to remember-me aware listeners
|
||||
$userProviders = [];
|
||||
foreach ($container->findTaggedServiceIds('security.remember_me_aware') as $serviceId => $attributes) {
|
||||
foreach ($attributes as $attribute) {
|
||||
if (!isset($attribute['id']) || $attribute['id'] !== $id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($attribute['provider'])) {
|
||||
throw new \RuntimeException('Each "security.remember_me_aware" tag must have a provider attribute.');
|
||||
}
|
||||
|
||||
// context listeners don't need a provider
|
||||
if ('none' !== $attribute['provider']) {
|
||||
$userProviders[] = new Reference($attribute['provider']);
|
||||
}
|
||||
|
||||
$container
|
||||
->getDefinition($serviceId)
|
||||
->addMethodCall('setRememberMeServices', [new Reference($rememberMeServicesId)])
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
$this->createRememberMeServices($container, $id, $templateId, $userProviders, $config);
|
||||
|
||||
// remember-me listener
|
||||
$listenerId = 'security.authentication.listener.rememberme.'.$id;
|
||||
$listener = $container->setDefinition($listenerId, new ChildDefinition('security.authentication.listener.rememberme'));
|
||||
$listener->replaceArgument(1, new Reference($rememberMeServicesId));
|
||||
$listener->replaceArgument(5, $config['catch_exceptions']);
|
||||
|
||||
// remember-me logout listener
|
||||
$container->setDefinition('security.logout.listener.remember_me.'.$id, new Definition(RememberMeLogoutListener::class))
|
||||
->addArgument(new Reference($rememberMeServicesId))
|
||||
->addTag('kernel.event_subscriber', ['dispatcher' => 'security.event_dispatcher.'.$id]);
|
||||
|
||||
return [$authProviderId, $listenerId, $defaultEntryPoint];
|
||||
}
|
||||
|
||||
public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId): string
|
||||
{
|
||||
if (!$container->hasDefinition('security.authenticator.remember_me')) {
|
||||
$loader = new PhpFileLoader($container, new FileLocator(\dirname(__DIR__).'/../../Resources/config'));
|
||||
$loader->load('security_authenticator_remember_me.php');
|
||||
}
|
||||
|
||||
if ('auto' === $config['secure']) {
|
||||
$config['secure'] = null;
|
||||
}
|
||||
|
||||
// create remember me handler (which manage the remember-me cookies)
|
||||
$rememberMeHandlerId = 'security.authenticator.remember_me_handler.'.$firewallName;
|
||||
if (isset($config['service']) && isset($config['token_provider'])) {
|
||||
throw new InvalidConfigurationException(sprintf('You cannot use both "service" and "token_provider" in "security.firewalls.%s.remember_me".', $firewallName));
|
||||
}
|
||||
|
||||
if (isset($config['service'])) {
|
||||
$container->register($rememberMeHandlerId, DecoratedRememberMeHandler::class)
|
||||
->addArgument(new Reference($config['service']))
|
||||
->addTag('security.remember_me_handler', ['firewall' => $firewallName]);
|
||||
} elseif (isset($config['token_provider'])) {
|
||||
$tokenProviderId = $this->createTokenProvider($container, $firewallName, $config['token_provider']);
|
||||
$tokenVerifier = $this->createTokenVerifier($container, $firewallName, $config['token_verifier'] ?? null);
|
||||
$container->setDefinition($rememberMeHandlerId, new ChildDefinition('security.authenticator.persistent_remember_me_handler'))
|
||||
->replaceArgument(0, new Reference($tokenProviderId))
|
||||
->replaceArgument(1, $config['secret'])
|
||||
->replaceArgument(2, new Reference($userProviderId))
|
||||
->replaceArgument(4, $config)
|
||||
->replaceArgument(6, $tokenVerifier)
|
||||
->addTag('security.remember_me_handler', ['firewall' => $firewallName]);
|
||||
} else {
|
||||
$signatureHasherId = 'security.authenticator.remember_me_signature_hasher.'.$firewallName;
|
||||
$container->setDefinition($signatureHasherId, new ChildDefinition('security.authenticator.remember_me_signature_hasher'))
|
||||
->replaceArgument(1, $config['signature_properties'])
|
||||
->replaceArgument(2, $config['secret'])
|
||||
;
|
||||
|
||||
$container->setDefinition($rememberMeHandlerId, new ChildDefinition('security.authenticator.signature_remember_me_handler'))
|
||||
->replaceArgument(0, new Reference($signatureHasherId))
|
||||
->replaceArgument(1, new Reference($userProviderId))
|
||||
->replaceArgument(3, $config)
|
||||
->addTag('security.remember_me_handler', ['firewall' => $firewallName]);
|
||||
}
|
||||
|
||||
// create check remember me conditions listener (which checks if a remember-me cookie is supported and requested)
|
||||
$rememberMeConditionsListenerId = 'security.listener.check_remember_me_conditions.'.$firewallName;
|
||||
$container->setDefinition($rememberMeConditionsListenerId, new ChildDefinition('security.listener.check_remember_me_conditions'))
|
||||
->replaceArgument(0, array_intersect_key($config, ['always_remember_me' => true, 'remember_me_parameter' => true]))
|
||||
->addTag('kernel.event_subscriber', ['dispatcher' => 'security.event_dispatcher.'.$firewallName])
|
||||
;
|
||||
|
||||
// create remember me listener (which executes the remember me services for other authenticators and logout)
|
||||
$rememberMeListenerId = 'security.listener.remember_me.'.$firewallName;
|
||||
$container->setDefinition($rememberMeListenerId, new ChildDefinition('security.listener.remember_me'))
|
||||
->replaceArgument(0, new Reference($rememberMeHandlerId))
|
||||
->addTag('kernel.event_subscriber', ['dispatcher' => 'security.event_dispatcher.'.$firewallName])
|
||||
;
|
||||
|
||||
// create remember me authenticator (which re-authenticates the user based on the remember-me cookie)
|
||||
$authenticatorId = 'security.authenticator.remember_me.'.$firewallName;
|
||||
$container
|
||||
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.remember_me'))
|
||||
->replaceArgument(0, new Reference($rememberMeHandlerId))
|
||||
->replaceArgument(3, $config['name'] ?? $this->options['name'])
|
||||
;
|
||||
|
||||
foreach ($container->findTaggedServiceIds('security.remember_me_aware') as $serviceId => $attributes) {
|
||||
// register ContextListener
|
||||
if ('security.context_listener' === substr($serviceId, 0, 25)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new \LogicException(sprintf('Symfony Authenticator Security dropped support for the "security.remember_me_aware" tag, service "%s" will no longer work as expected.', $serviceId));
|
||||
}
|
||||
|
||||
return $authenticatorId;
|
||||
}
|
||||
|
||||
public function getPosition(): string
|
||||
{
|
||||
return 'remember_me';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPriority(): int
|
||||
{
|
||||
return self::PRIORITY;
|
||||
}
|
||||
|
||||
public function getKey(): string
|
||||
{
|
||||
return 'remember-me';
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
$builder = $node
|
||||
->fixXmlConfig('user_provider')
|
||||
->children()
|
||||
;
|
||||
|
||||
$builder
|
||||
->scalarNode('secret')
|
||||
->cannotBeEmpty()
|
||||
->defaultValue('%kernel.secret%')
|
||||
->end()
|
||||
->scalarNode('service')->end()
|
||||
->arrayNode('user_providers')
|
||||
->beforeNormalization()
|
||||
->ifString()->then(function ($v) { return [$v]; })
|
||||
->end()
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->booleanNode('catch_exceptions')->defaultTrue()->end()
|
||||
->arrayNode('signature_properties')
|
||||
->prototype('scalar')->end()
|
||||
->requiresAtLeastOneElement()
|
||||
->info('An array of properties on your User that are used to sign the remember-me cookie. If any of these change, all existing cookies will become invalid.')
|
||||
->example(['email', 'password'])
|
||||
->defaultValue(['password'])
|
||||
->end()
|
||||
->arrayNode('token_provider')
|
||||
->beforeNormalization()
|
||||
->ifString()->then(function ($v) { return ['service' => $v]; })
|
||||
->end()
|
||||
->children()
|
||||
->scalarNode('service')->info('The service ID of a custom rememberme token provider.')->end()
|
||||
->arrayNode('doctrine')
|
||||
->canBeEnabled()
|
||||
->children()
|
||||
->scalarNode('connection')->defaultNull()->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->scalarNode('token_verifier')
|
||||
->info('The service ID of a custom rememberme token verifier.')
|
||||
->end();
|
||||
|
||||
foreach ($this->options as $name => $value) {
|
||||
if ('secure' === $name) {
|
||||
$builder->enumNode($name)->values([true, false, 'auto'])->defaultValue('auto' === $value ? null : $value);
|
||||
} elseif ('samesite' === $name) {
|
||||
$builder->enumNode($name)->values([null, Cookie::SAMESITE_LAX, Cookie::SAMESITE_STRICT, Cookie::SAMESITE_NONE])->defaultValue($value);
|
||||
} elseif (\is_bool($value)) {
|
||||
$builder->booleanNode($name)->defaultValue($value);
|
||||
} elseif (\is_int($value)) {
|
||||
$builder->integerNode($name)->defaultValue($value);
|
||||
} else {
|
||||
$builder->scalarNode($name)->defaultValue($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function generateRememberMeServicesTemplateId(array $config, string $id): string
|
||||
{
|
||||
if (isset($config['service'])) {
|
||||
return $config['service'];
|
||||
}
|
||||
|
||||
if (isset($config['token_provider'])) {
|
||||
return 'security.authentication.rememberme.services.persistent';
|
||||
}
|
||||
|
||||
return 'security.authentication.rememberme.services.simplehash';
|
||||
}
|
||||
|
||||
private function createRememberMeServices(ContainerBuilder $container, string $id, string $templateId, array $userProviders, array $config): void
|
||||
{
|
||||
$rememberMeServicesId = $templateId.'.'.$id;
|
||||
|
||||
$rememberMeServices = $container->setDefinition($rememberMeServicesId, new ChildDefinition($templateId));
|
||||
$rememberMeServices->replaceArgument(1, $config['secret']);
|
||||
$rememberMeServices->replaceArgument(2, $id);
|
||||
|
||||
if (isset($config['token_provider'])) {
|
||||
$tokenProviderId = $this->createTokenProvider($container, $id, $config['token_provider']);
|
||||
$rememberMeServices->addMethodCall('setTokenProvider', [new Reference($tokenProviderId)]);
|
||||
}
|
||||
|
||||
// remember-me options
|
||||
$mergedOptions = array_intersect_key($config, $this->options);
|
||||
if ('auto' === $mergedOptions['secure']) {
|
||||
$mergedOptions['secure'] = null;
|
||||
}
|
||||
|
||||
$rememberMeServices->replaceArgument(3, $mergedOptions);
|
||||
|
||||
if ($config['user_providers']) {
|
||||
$userProviders = [];
|
||||
foreach ($config['user_providers'] as $providerName) {
|
||||
$userProviders[] = new Reference('security.user.provider.concrete.'.$providerName);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 === \count($userProviders)) {
|
||||
throw new \RuntimeException('You must configure at least one remember-me aware listener (such as form-login) for each firewall that has remember-me enabled.');
|
||||
}
|
||||
|
||||
$rememberMeServices->replaceArgument(0, new IteratorArgument(array_unique($userProviders)));
|
||||
}
|
||||
|
||||
private function createTokenProvider(ContainerBuilder $container, string $firewallName, array $config): string
|
||||
{
|
||||
$tokenProviderId = $config['service'] ?? false;
|
||||
if ($config['doctrine']['enabled'] ?? false) {
|
||||
if (!class_exists(DoctrineTokenProvider::class)) {
|
||||
throw new InvalidConfigurationException('Cannot use the "doctrine" token provider for "remember_me" because the Doctrine Bridge is not installed. Try running "composer require symfony/doctrine-bridge".');
|
||||
}
|
||||
|
||||
if (null === $config['doctrine']['connection']) {
|
||||
$connectionId = 'database_connection';
|
||||
} else {
|
||||
$connectionId = 'doctrine.dbal.'.$config['doctrine']['connection'].'_connection';
|
||||
}
|
||||
|
||||
$tokenProviderId = 'security.remember_me.doctrine_token_provider.'.$firewallName;
|
||||
$container->register($tokenProviderId, DoctrineTokenProvider::class)
|
||||
->addArgument(new Reference($connectionId));
|
||||
}
|
||||
|
||||
if (!$tokenProviderId) {
|
||||
throw new InvalidConfigurationException(sprintf('No token provider was set for firewall "%s". Either configure a service ID or set "remember_me.token_provider.doctrine" to true.', $firewallName));
|
||||
}
|
||||
|
||||
return $tokenProviderId;
|
||||
}
|
||||
|
||||
private function createTokenVerifier(ContainerBuilder $container, string $firewallName, ?string $serviceId): Reference
|
||||
{
|
||||
if ($serviceId) {
|
||||
return new Reference($serviceId);
|
||||
}
|
||||
|
||||
$tokenVerifierId = 'security.remember_me.token_verifier.'.$firewallName;
|
||||
|
||||
$container->register($tokenVerifierId, CacheTokenVerifier::class)
|
||||
->addArgument(new Reference('cache.security_token_verifier', ContainerInterface::NULL_ON_INVALID_REFERENCE))
|
||||
->addArgument(60)
|
||||
->addArgument('rememberme-'.$firewallName.'-stale-');
|
||||
|
||||
return new Reference($tokenVerifierId, ContainerInterface::NULL_ON_INVALID_REFERENCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepend(ContainerBuilder $container)
|
||||
{
|
||||
$rememberMeSecureDefault = false;
|
||||
$rememberMeSameSiteDefault = null;
|
||||
|
||||
if (!isset($container->getExtensions()['framework'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($container->getExtensionConfig('framework') as $config) {
|
||||
if (isset($config['session']) && \is_array($config['session'])) {
|
||||
$rememberMeSecureDefault = $config['session']['cookie_secure'] ?? $rememberMeSecureDefault;
|
||||
$rememberMeSameSiteDefault = \array_key_exists('cookie_samesite', $config['session']) ? $config['session']['cookie_samesite'] : $rememberMeSameSiteDefault;
|
||||
}
|
||||
}
|
||||
|
||||
$this->options['secure'] = $rememberMeSecureDefault;
|
||||
$this->options['samesite'] = $rememberMeSameSiteDefault;
|
||||
}
|
||||
}
|
87
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/RemoteUserFactory.php
vendored
Normal file
87
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/RemoteUserFactory.php
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* RemoteUserFactory creates services for REMOTE_USER based authentication.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Maxime Douailin <maxime.douailin@gmail.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class RemoteUserFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface
|
||||
{
|
||||
public const PRIORITY = -10;
|
||||
|
||||
public function create(ContainerBuilder $container, string $id, array $config, string $userProvider, ?string $defaultEntryPoint): array
|
||||
{
|
||||
$providerId = 'security.authentication.provider.pre_authenticated.'.$id;
|
||||
$container
|
||||
->setDefinition($providerId, new ChildDefinition('security.authentication.provider.pre_authenticated'))
|
||||
->replaceArgument(0, new Reference($userProvider))
|
||||
->replaceArgument(1, new Reference('security.user_checker.'.$id))
|
||||
->addArgument($id)
|
||||
;
|
||||
|
||||
$listenerId = 'security.authentication.listener.remote_user.'.$id;
|
||||
$listener = $container->setDefinition($listenerId, new ChildDefinition('security.authentication.listener.remote_user'));
|
||||
$listener->replaceArgument(2, $id);
|
||||
$listener->replaceArgument(3, $config['user']);
|
||||
$listener->addMethodCall('setSessionAuthenticationStrategy', [new Reference('security.authentication.session_strategy.'.$id)]);
|
||||
|
||||
return [$providerId, $listenerId, $defaultEntryPoint];
|
||||
}
|
||||
|
||||
public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId)
|
||||
{
|
||||
$authenticatorId = 'security.authenticator.remote_user.'.$firewallName;
|
||||
$container
|
||||
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.remote_user'))
|
||||
->replaceArgument(0, new Reference($userProviderId))
|
||||
->replaceArgument(2, $firewallName)
|
||||
->replaceArgument(3, $config['user'])
|
||||
;
|
||||
|
||||
return $authenticatorId;
|
||||
}
|
||||
|
||||
public function getPriority(): int
|
||||
{
|
||||
return self::PRIORITY;
|
||||
}
|
||||
|
||||
public function getPosition(): string
|
||||
{
|
||||
return 'pre_auth';
|
||||
}
|
||||
|
||||
public function getKey(): string
|
||||
{
|
||||
return 'remote-user';
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
$node
|
||||
->children()
|
||||
->scalarNode('provider')->end()
|
||||
->scalarNode('user')->defaultValue('REMOTE_USER')->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
}
|
53
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/SecurityFactoryInterface.php
vendored
Normal file
53
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/SecurityFactoryInterface.php
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* SecurityFactoryInterface is the interface for all security authentication listener.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @deprecated since Symfony 5.3, use AuthenticatorFactoryInterface instead.
|
||||
*/
|
||||
interface SecurityFactoryInterface
|
||||
{
|
||||
/**
|
||||
* Configures the container services required to use the authentication listener.
|
||||
*
|
||||
* @return array containing three values:
|
||||
* - the provider id
|
||||
* - the listener id
|
||||
* - the entry point id
|
||||
*/
|
||||
public function create(ContainerBuilder $container, string $id, array $config, string $userProviderId, ?string $defaultEntryPointId);
|
||||
|
||||
/**
|
||||
* Defines the position at which the provider is called.
|
||||
* Possible values: pre_auth, form, http, and remember_me.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPosition();
|
||||
|
||||
/**
|
||||
* Defines the configuration key used to reference the provider
|
||||
* in the firewall configuration.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getKey();
|
||||
|
||||
public function addConfiguration(NodeDefinition $builder);
|
||||
}
|
90
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/X509Factory.php
vendored
Normal file
90
vendor/symfony/security-bundle/DependencyInjection/Security/Factory/X509Factory.php
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* X509Factory creates services for X509 certificate authentication.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class X509Factory implements SecurityFactoryInterface, AuthenticatorFactoryInterface
|
||||
{
|
||||
public const PRIORITY = -10;
|
||||
|
||||
public function create(ContainerBuilder $container, string $id, array $config, string $userProvider, ?string $defaultEntryPoint): array
|
||||
{
|
||||
$providerId = 'security.authentication.provider.pre_authenticated.'.$id;
|
||||
$container
|
||||
->setDefinition($providerId, new ChildDefinition('security.authentication.provider.pre_authenticated'))
|
||||
->replaceArgument(0, new Reference($userProvider))
|
||||
->replaceArgument(1, new Reference('security.user_checker.'.$id))
|
||||
->addArgument($id)
|
||||
;
|
||||
|
||||
// listener
|
||||
$listenerId = 'security.authentication.listener.x509.'.$id;
|
||||
$listener = $container->setDefinition($listenerId, new ChildDefinition('security.authentication.listener.x509'));
|
||||
$listener->replaceArgument(2, $id);
|
||||
$listener->replaceArgument(3, $config['user']);
|
||||
$listener->replaceArgument(4, $config['credentials']);
|
||||
$listener->addMethodCall('setSessionAuthenticationStrategy', [new Reference('security.authentication.session_strategy.'.$id)]);
|
||||
|
||||
return [$providerId, $listenerId, $defaultEntryPoint];
|
||||
}
|
||||
|
||||
public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId)
|
||||
{
|
||||
$authenticatorId = 'security.authenticator.x509.'.$firewallName;
|
||||
$container
|
||||
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.x509'))
|
||||
->replaceArgument(0, new Reference($userProviderId))
|
||||
->replaceArgument(2, $firewallName)
|
||||
->replaceArgument(3, $config['user'])
|
||||
->replaceArgument(4, $config['credentials'])
|
||||
;
|
||||
|
||||
return $authenticatorId;
|
||||
}
|
||||
|
||||
public function getPriority(): int
|
||||
{
|
||||
return self::PRIORITY;
|
||||
}
|
||||
|
||||
public function getPosition(): string
|
||||
{
|
||||
return 'pre_auth';
|
||||
}
|
||||
|
||||
public function getKey(): string
|
||||
{
|
||||
return 'x509';
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
$node
|
||||
->children()
|
||||
->scalarNode('provider')->end()
|
||||
->scalarNode('user')->defaultValue('SSL_CLIENT_S_DN_Email')->end()
|
||||
->scalarNode('credentials')->defaultValue('SSL_CLIENT_S_DN')->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
}
|
88
vendor/symfony/security-bundle/DependencyInjection/Security/UserProvider/InMemoryFactory.php
vendored
Normal file
88
vendor/symfony/security-bundle/DependencyInjection/Security/UserProvider/InMemoryFactory.php
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Parameter;
|
||||
|
||||
/**
|
||||
* InMemoryFactory creates services for the memory provider.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
*/
|
||||
class InMemoryFactory implements UserProviderFactoryInterface
|
||||
{
|
||||
public function create(ContainerBuilder $container, string $id, array $config)
|
||||
{
|
||||
$definition = $container->setDefinition($id, new ChildDefinition('security.user.provider.in_memory'));
|
||||
$defaultPassword = new Parameter('container.build_id');
|
||||
$users = [];
|
||||
|
||||
foreach ($config['users'] as $username => $user) {
|
||||
$users[$username] = ['password' => null !== $user['password'] ? (string) $user['password'] : $defaultPassword, 'roles' => $user['roles']];
|
||||
}
|
||||
|
||||
$definition->addArgument($users);
|
||||
}
|
||||
|
||||
public function getKey()
|
||||
{
|
||||
return 'memory';
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
$node
|
||||
->fixXmlConfig('user')
|
||||
->children()
|
||||
->arrayNode('users')
|
||||
->useAttributeAsKey('identifier')
|
||||
->normalizeKeys(false)
|
||||
->beforeNormalization()
|
||||
->always()
|
||||
->then(function ($v) {
|
||||
$deprecation = false;
|
||||
foreach ($v as $i => $child) {
|
||||
if (!isset($child['name'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$deprecation = true;
|
||||
|
||||
$v[$i]['identifier'] = $child['name'];
|
||||
unset($v[$i]['name']);
|
||||
}
|
||||
|
||||
if ($deprecation) {
|
||||
trigger_deprecation('symfony/security-bundle', '5.3', 'The "in_memory.user.name" option is deprecated, use "identifier" instead.');
|
||||
}
|
||||
|
||||
return $v;
|
||||
})
|
||||
->end()
|
||||
->prototype('array')
|
||||
->children()
|
||||
->scalarNode('password')->defaultNull()->end()
|
||||
->arrayNode('roles')
|
||||
->beforeNormalization()->ifString()->then(function ($v) { return preg_split('/\s*,\s*/', $v); })->end()
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
}
|
72
vendor/symfony/security-bundle/DependencyInjection/Security/UserProvider/LdapFactory.php
vendored
Normal file
72
vendor/symfony/security-bundle/DependencyInjection/Security/UserProvider/LdapFactory.php
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* LdapFactory creates services for Ldap user provider.
|
||||
*
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
* @author Charles Sarrazin <charles@sarraz.in>
|
||||
*/
|
||||
class LdapFactory implements UserProviderFactoryInterface
|
||||
{
|
||||
public function create(ContainerBuilder $container, string $id, array $config)
|
||||
{
|
||||
$container
|
||||
->setDefinition($id, new ChildDefinition('security.user.provider.ldap'))
|
||||
->replaceArgument(0, new Reference($config['service']))
|
||||
->replaceArgument(1, $config['base_dn'])
|
||||
->replaceArgument(2, $config['search_dn'])
|
||||
->replaceArgument(3, $config['search_password'])
|
||||
->replaceArgument(4, $config['default_roles'])
|
||||
->replaceArgument(5, $config['uid_key'])
|
||||
->replaceArgument(6, $config['filter'])
|
||||
->replaceArgument(7, $config['password_attribute'])
|
||||
->replaceArgument(8, $config['extra_fields'])
|
||||
;
|
||||
}
|
||||
|
||||
public function getKey()
|
||||
{
|
||||
return 'ldap';
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
$node
|
||||
->fixXmlConfig('extra_field')
|
||||
->fixXmlConfig('default_role')
|
||||
->children()
|
||||
->scalarNode('service')->isRequired()->cannotBeEmpty()->defaultValue('ldap')->end()
|
||||
->scalarNode('base_dn')->isRequired()->cannotBeEmpty()->end()
|
||||
->scalarNode('search_dn')->defaultNull()->end()
|
||||
->scalarNode('search_password')->defaultNull()->end()
|
||||
->arrayNode('extra_fields')
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->arrayNode('default_roles')
|
||||
->beforeNormalization()->ifString()->then(function ($v) { return preg_split('/\s*,\s*/', $v); })->end()
|
||||
->requiresAtLeastOneElement()
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->scalarNode('uid_key')->defaultValue('sAMAccountName')->end()
|
||||
->scalarNode('filter')->defaultValue('({uid_key}={username})')->end()
|
||||
->scalarNode('password_attribute')->defaultNull()->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* UserProviderFactoryInterface is the interface for all user provider factories.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
*/
|
||||
interface UserProviderFactoryInterface
|
||||
{
|
||||
public function create(ContainerBuilder $container, string $id, array $config);
|
||||
|
||||
public function getKey();
|
||||
|
||||
public function addConfiguration(NodeDefinition $builder);
|
||||
}
|
1210
vendor/symfony/security-bundle/DependencyInjection/SecurityExtension.php
vendored
Normal file
1210
vendor/symfony/security-bundle/DependencyInjection/SecurityExtension.php
vendored
Normal file
@ -0,0 +1,1210 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection;
|
||||
|
||||
use Composer\InstalledVersions;
|
||||
use Symfony\Bridge\Twig\Extension\LogoutUrlExtension;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AuthenticatorFactoryInterface;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\FirewallListenerFactoryInterface;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\UserProviderFactoryInterface;
|
||||
use Symfony\Bundle\SecurityBundle\Security\LegacyLogoutHandlerListener;
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
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;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Component\PasswordHasher\Hasher\NativePasswordHasher;
|
||||
use Symfony\Component\PasswordHasher\Hasher\Pbkdf2PasswordHasher;
|
||||
use Symfony\Component\PasswordHasher\Hasher\PlaintextPasswordHasher;
|
||||
use Symfony\Component\PasswordHasher\Hasher\SodiumPasswordHasher;
|
||||
use Symfony\Component\Security\Core\Authorization\Strategy\AffirmativeStrategy;
|
||||
use Symfony\Component\Security\Core\Authorization\Strategy\ConsensusStrategy;
|
||||
use Symfony\Component\Security\Core\Authorization\Strategy\PriorityStrategy;
|
||||
use Symfony\Component\Security\Core\Authorization\Strategy\UnanimousStrategy;
|
||||
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
|
||||
use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder;
|
||||
use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder;
|
||||
use Symfony\Component\Security\Core\User\ChainUserProvider;
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Http\Authenticator\Debug\TraceableAuthenticatorManagerListener;
|
||||
use Symfony\Component\Security\Http\Event\CheckPassportEvent;
|
||||
|
||||
/**
|
||||
* SecurityExtension.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class SecurityExtension extends Extension implements PrependExtensionInterface
|
||||
{
|
||||
private $requestMatchers = [];
|
||||
private $expressions = [];
|
||||
private $contextListeners = [];
|
||||
/** @var list<array{int, AuthenticatorFactoryInterface|SecurityFactoryInterface}> */
|
||||
private $factories = [];
|
||||
/** @var list<AuthenticatorFactoryInterface|SecurityFactoryInterface> */
|
||||
private $sortedFactories = [];
|
||||
private $userProviderFactories = [];
|
||||
private $statelessFirewallKeys = [];
|
||||
|
||||
private $authenticatorManagerEnabled = false;
|
||||
|
||||
public function prepend(ContainerBuilder $container)
|
||||
{
|
||||
foreach ($this->getSortedFactories() as $factory) {
|
||||
if ($factory instanceof PrependExtensionInterface) {
|
||||
$factory->prepend($container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function load(array $configs, ContainerBuilder $container)
|
||||
{
|
||||
if (!class_exists(InstalledVersions::class)) {
|
||||
trigger_deprecation('symfony/security-bundle', '5.4', 'Configuring Symfony without the Composer Runtime API is deprecated. Consider upgrading to Composer 2.1 or later.');
|
||||
}
|
||||
|
||||
if (!array_filter($configs)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$mainConfig = $this->getConfiguration($configs, $container);
|
||||
|
||||
$config = $this->processConfiguration($mainConfig, $configs);
|
||||
|
||||
// load services
|
||||
$loader = new PhpFileLoader($container, new FileLocator(\dirname(__DIR__).'/Resources/config'));
|
||||
|
||||
$loader->load('security.php');
|
||||
$loader->load('password_hasher.php');
|
||||
$loader->load('security_listeners.php');
|
||||
$loader->load('security_rememberme.php');
|
||||
|
||||
if ($this->authenticatorManagerEnabled = $config['enable_authenticator_manager']) {
|
||||
if ($config['always_authenticate_before_granting']) {
|
||||
throw new InvalidConfigurationException('The security option "always_authenticate_before_granting" cannot be used when "enable_authenticator_manager" is set to true. If you rely on this behavior, set it to false.');
|
||||
}
|
||||
|
||||
$loader->load('security_authenticator.php');
|
||||
|
||||
// The authenticator system no longer has anonymous tokens. This makes sure AccessListener
|
||||
// and AuthorizationChecker do not throw AuthenticationCredentialsNotFoundException when no
|
||||
// token is available in the token storage.
|
||||
$container->getDefinition('security.access_listener')->setArgument(3, false);
|
||||
$container->getDefinition('security.authorization_checker')->setArgument(3, false);
|
||||
$container->getDefinition('security.authorization_checker')->setArgument(4, false);
|
||||
} else {
|
||||
trigger_deprecation('symfony/security-bundle', '5.3', 'Not setting the "security.enable_authenticator_manager" config option to true is deprecated.');
|
||||
|
||||
if ($config['always_authenticate_before_granting']) {
|
||||
$authorizationChecker = $container->getDefinition('security.authorization_checker');
|
||||
$authorizationCheckerArgs = $authorizationChecker->getArguments();
|
||||
array_splice($authorizationCheckerArgs, 1, 0, [new Reference('security.authentication.manager')]);
|
||||
$authorizationChecker->setArguments($authorizationCheckerArgs);
|
||||
}
|
||||
|
||||
$loader->load('security_legacy.php');
|
||||
}
|
||||
|
||||
if ($container::willBeAvailable('symfony/twig-bridge', LogoutUrlExtension::class, ['symfony/security-bundle'], true)) {
|
||||
$loader->load('templating_twig.php');
|
||||
}
|
||||
|
||||
$loader->load('collectors.php');
|
||||
$loader->load('guard.php');
|
||||
|
||||
$container->getDefinition('data_collector.security')->addArgument($this->authenticatorManagerEnabled);
|
||||
|
||||
if ($container->hasParameter('kernel.debug') && $container->getParameter('kernel.debug')) {
|
||||
$loader->load('security_debug.php');
|
||||
}
|
||||
|
||||
if (!$container::willBeAvailable('symfony/expression-language', ExpressionLanguage::class, ['symfony/security-bundle'], true)) {
|
||||
$container->removeDefinition('security.expression_language');
|
||||
$container->removeDefinition('security.access.expression_voter');
|
||||
}
|
||||
|
||||
// set some global scalars
|
||||
$container->setParameter('security.access.denied_url', $config['access_denied_url']);
|
||||
$container->setParameter('security.authentication.manager.erase_credentials', $config['erase_credentials']);
|
||||
$container->setParameter('security.authentication.session_strategy.strategy', $config['session_fixation_strategy']);
|
||||
|
||||
if (isset($config['access_decision_manager']['service'])) {
|
||||
$container->setAlias('security.access.decision_manager', $config['access_decision_manager']['service']);
|
||||
} elseif (isset($config['access_decision_manager']['strategy_service'])) {
|
||||
$container
|
||||
->getDefinition('security.access.decision_manager')
|
||||
->addArgument(new Reference($config['access_decision_manager']['strategy_service']));
|
||||
} else {
|
||||
$container
|
||||
->getDefinition('security.access.decision_manager')
|
||||
->addArgument($this->createStrategyDefinition(
|
||||
$config['access_decision_manager']['strategy'] ?? MainConfiguration::STRATEGY_AFFIRMATIVE,
|
||||
$config['access_decision_manager']['allow_if_all_abstain'],
|
||||
$config['access_decision_manager']['allow_if_equal_granted_denied']
|
||||
));
|
||||
}
|
||||
|
||||
$container->setParameter('security.access.always_authenticate_before_granting', $config['always_authenticate_before_granting']);
|
||||
$container->setParameter('security.authentication.hide_user_not_found', $config['hide_user_not_found']);
|
||||
|
||||
if (class_exists(Application::class)) {
|
||||
$loader->load('debug_console.php');
|
||||
$debugCommand = $container->getDefinition('security.command.debug_firewall');
|
||||
$debugCommand->replaceArgument(4, $this->authenticatorManagerEnabled);
|
||||
}
|
||||
|
||||
$this->createFirewalls($config, $container);
|
||||
$this->createAuthorization($config, $container);
|
||||
$this->createRoleHierarchy($config, $container);
|
||||
|
||||
$container->getDefinition('security.authentication.guard_handler')
|
||||
->replaceArgument(2, $this->statelessFirewallKeys);
|
||||
|
||||
// @deprecated since Symfony 5.3
|
||||
if ($config['encoders']) {
|
||||
$this->createEncoders($config['encoders'], $container);
|
||||
}
|
||||
|
||||
if ($config['password_hashers']) {
|
||||
$this->createHashers($config['password_hashers'], $container);
|
||||
}
|
||||
|
||||
if (class_exists(Application::class)) {
|
||||
$loader->load('console.php');
|
||||
|
||||
// @deprecated since Symfony 5.3
|
||||
$container->getDefinition('security.command.user_password_encoder')->replaceArgument(1, array_keys($config['encoders']));
|
||||
|
||||
$container->getDefinition('security.command.user_password_hash')->replaceArgument(1, array_keys($config['password_hashers']));
|
||||
}
|
||||
|
||||
$container->registerForAutoconfiguration(VoterInterface::class)
|
||||
->addTag('security.voter');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException if the $strategy is invalid
|
||||
*/
|
||||
private function createStrategyDefinition(string $strategy, bool $allowIfAllAbstainDecisions, bool $allowIfEqualGrantedDeniedDecisions): Definition
|
||||
{
|
||||
switch ($strategy) {
|
||||
case MainConfiguration::STRATEGY_AFFIRMATIVE:
|
||||
return new Definition(AffirmativeStrategy::class, [$allowIfAllAbstainDecisions]);
|
||||
case MainConfiguration::STRATEGY_CONSENSUS:
|
||||
return new Definition(ConsensusStrategy::class, [$allowIfAllAbstainDecisions, $allowIfEqualGrantedDeniedDecisions]);
|
||||
case MainConfiguration::STRATEGY_UNANIMOUS:
|
||||
return new Definition(UnanimousStrategy::class, [$allowIfAllAbstainDecisions]);
|
||||
case MainConfiguration::STRATEGY_PRIORITY:
|
||||
return new Definition(PriorityStrategy::class, [$allowIfAllAbstainDecisions]);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf('The strategy "%s" is not supported.', $strategy));
|
||||
}
|
||||
|
||||
private function createRoleHierarchy(array $config, ContainerBuilder $container)
|
||||
{
|
||||
if (!isset($config['role_hierarchy']) || 0 === \count($config['role_hierarchy'])) {
|
||||
$container->removeDefinition('security.access.role_hierarchy_voter');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$container->setParameter('security.role_hierarchy.roles', $config['role_hierarchy']);
|
||||
$container->removeDefinition('security.access.simple_role_voter');
|
||||
}
|
||||
|
||||
private function createAuthorization(array $config, ContainerBuilder $container)
|
||||
{
|
||||
foreach ($config['access_control'] as $access) {
|
||||
$matcher = $this->createRequestMatcher(
|
||||
$container,
|
||||
$access['path'],
|
||||
$access['host'],
|
||||
$access['port'],
|
||||
$access['methods'],
|
||||
$access['ips']
|
||||
);
|
||||
|
||||
$attributes = $access['roles'];
|
||||
if ($access['allow_if']) {
|
||||
$attributes[] = $this->createExpression($container, $access['allow_if']);
|
||||
}
|
||||
|
||||
$emptyAccess = 0 === \count(array_filter($access));
|
||||
|
||||
if ($emptyAccess) {
|
||||
throw new InvalidConfigurationException('One or more access control items are empty. Did you accidentally add lines only containing a "-" under "security.access_control"?');
|
||||
}
|
||||
|
||||
$container->getDefinition('security.access_map')
|
||||
->addMethodCall('add', [$matcher, $attributes, $access['requires_channel']]);
|
||||
}
|
||||
|
||||
// allow cache warm-up for expressions
|
||||
if (\count($this->expressions)) {
|
||||
$container->getDefinition('security.cache_warmer.expression')
|
||||
->replaceArgument(0, new IteratorArgument(array_values($this->expressions)));
|
||||
} else {
|
||||
$container->removeDefinition('security.cache_warmer.expression');
|
||||
}
|
||||
}
|
||||
|
||||
private function createFirewalls(array $config, ContainerBuilder $container)
|
||||
{
|
||||
if (!isset($config['firewalls'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$firewalls = $config['firewalls'];
|
||||
$providerIds = $this->createUserProviders($config, $container);
|
||||
|
||||
$container->setParameter('security.firewalls', array_keys($firewalls));
|
||||
|
||||
// make the ContextListener aware of the configured user providers
|
||||
$contextListenerDefinition = $container->getDefinition('security.context_listener');
|
||||
$arguments = $contextListenerDefinition->getArguments();
|
||||
$userProviders = [];
|
||||
foreach ($providerIds as $userProviderId) {
|
||||
$userProviders[] = new Reference($userProviderId);
|
||||
}
|
||||
$arguments[1] = $userProviderIteratorsArgument = new IteratorArgument($userProviders);
|
||||
$contextListenerDefinition->setArguments($arguments);
|
||||
$nbUserProviders = \count($userProviders);
|
||||
|
||||
if ($nbUserProviders > 1) {
|
||||
$container->setDefinition('security.user_providers', new Definition(ChainUserProvider::class, [$userProviderIteratorsArgument]))
|
||||
->setPublic(false);
|
||||
} elseif (0 === $nbUserProviders) {
|
||||
$container->removeDefinition('security.listener.user_provider');
|
||||
} else {
|
||||
$container->setAlias('security.user_providers', new Alias(current($providerIds)))->setPublic(false);
|
||||
}
|
||||
|
||||
if (1 === \count($providerIds)) {
|
||||
$container->setAlias(UserProviderInterface::class, current($providerIds));
|
||||
}
|
||||
|
||||
$customUserChecker = false;
|
||||
|
||||
// load firewall map
|
||||
$mapDef = $container->getDefinition('security.firewall.map');
|
||||
$map = $authenticationProviders = $contextRefs = [];
|
||||
foreach ($firewalls as $name => $firewall) {
|
||||
if (isset($firewall['user_checker']) && 'security.user_checker' !== $firewall['user_checker']) {
|
||||
$customUserChecker = true;
|
||||
}
|
||||
|
||||
$configId = 'security.firewall.map.config.'.$name;
|
||||
|
||||
[$matcher, $listeners, $exceptionListener, $logoutListener] = $this->createFirewall($container, $name, $firewall, $authenticationProviders, $providerIds, $configId);
|
||||
|
||||
$contextId = 'security.firewall.map.context.'.$name;
|
||||
$isLazy = !$firewall['stateless'] && (!empty($firewall['anonymous']['lazy']) || $firewall['lazy']);
|
||||
$context = new ChildDefinition($isLazy ? 'security.firewall.lazy_context' : 'security.firewall.context');
|
||||
$context = $container->setDefinition($contextId, $context);
|
||||
$context
|
||||
->replaceArgument(0, new IteratorArgument($listeners))
|
||||
->replaceArgument(1, $exceptionListener)
|
||||
->replaceArgument(2, $logoutListener)
|
||||
->replaceArgument(3, new Reference($configId))
|
||||
;
|
||||
|
||||
$contextRefs[$contextId] = new Reference($contextId);
|
||||
$map[$contextId] = $matcher;
|
||||
}
|
||||
|
||||
$container->setAlias('security.firewall.context_locator', (string) ServiceLocatorTagPass::register($container, $contextRefs));
|
||||
|
||||
$mapDef->replaceArgument(0, new Reference('security.firewall.context_locator'));
|
||||
$mapDef->replaceArgument(1, new IteratorArgument($map));
|
||||
|
||||
if (!$this->authenticatorManagerEnabled) {
|
||||
// add authentication providers to authentication manager
|
||||
$authenticationProviders = array_map(function ($id) {
|
||||
return new Reference($id);
|
||||
}, array_values(array_unique($authenticationProviders)));
|
||||
|
||||
$container
|
||||
->getDefinition('security.authentication.manager')
|
||||
->replaceArgument(0, new IteratorArgument($authenticationProviders));
|
||||
}
|
||||
|
||||
// register an autowire alias for the UserCheckerInterface if no custom user checker service is configured
|
||||
if (!$customUserChecker) {
|
||||
$container->setAlias('Symfony\Component\Security\Core\User\UserCheckerInterface', new Alias('security.user_checker', false));
|
||||
}
|
||||
}
|
||||
|
||||
private function createFirewall(ContainerBuilder $container, string $id, array $firewall, array &$authenticationProviders, array $providerIds, string $configId)
|
||||
{
|
||||
$config = $container->setDefinition($configId, new ChildDefinition('security.firewall.config'));
|
||||
$config->replaceArgument(0, $id);
|
||||
$config->replaceArgument(1, $firewall['user_checker']);
|
||||
|
||||
// Matcher
|
||||
$matcher = null;
|
||||
if (isset($firewall['request_matcher'])) {
|
||||
$matcher = new Reference($firewall['request_matcher']);
|
||||
} elseif (isset($firewall['pattern']) || isset($firewall['host'])) {
|
||||
$pattern = $firewall['pattern'] ?? null;
|
||||
$host = $firewall['host'] ?? null;
|
||||
$methods = $firewall['methods'] ?? [];
|
||||
$matcher = $this->createRequestMatcher($container, $pattern, $host, null, $methods);
|
||||
}
|
||||
|
||||
$config->replaceArgument(2, $matcher ? (string) $matcher : null);
|
||||
$config->replaceArgument(3, $firewall['security']);
|
||||
|
||||
// Security disabled?
|
||||
if (false === $firewall['security']) {
|
||||
return [$matcher, [], null, null];
|
||||
}
|
||||
|
||||
$config->replaceArgument(4, $firewall['stateless']);
|
||||
|
||||
$firewallEventDispatcherId = 'security.event_dispatcher.'.$id;
|
||||
|
||||
// Provider id (must be configured explicitly per firewall/authenticator if more than one provider is set)
|
||||
$defaultProvider = null;
|
||||
if (isset($firewall['provider'])) {
|
||||
if (!isset($providerIds[$normalizedName = str_replace('-', '_', $firewall['provider'])])) {
|
||||
throw new InvalidConfigurationException(sprintf('Invalid firewall "%s": user provider "%s" not found.', $id, $firewall['provider']));
|
||||
}
|
||||
$defaultProvider = $providerIds[$normalizedName];
|
||||
|
||||
if ($this->authenticatorManagerEnabled) {
|
||||
$container->setDefinition('security.listener.'.$id.'.user_provider', new ChildDefinition('security.listener.user_provider.abstract'))
|
||||
->addTag('kernel.event_listener', ['dispatcher' => $firewallEventDispatcherId, 'event' => CheckPassportEvent::class, 'priority' => 2048, 'method' => 'checkPassport'])
|
||||
->replaceArgument(0, new Reference($defaultProvider));
|
||||
}
|
||||
} elseif (1 === \count($providerIds)) {
|
||||
$defaultProvider = reset($providerIds);
|
||||
}
|
||||
|
||||
$config->replaceArgument(5, $defaultProvider);
|
||||
|
||||
// Register Firewall-specific event dispatcher
|
||||
$container->register($firewallEventDispatcherId, EventDispatcher::class)
|
||||
->addTag('event_dispatcher.dispatcher', ['name' => $firewallEventDispatcherId]);
|
||||
|
||||
// Register listeners
|
||||
$listeners = [];
|
||||
$listenerKeys = [];
|
||||
|
||||
// Channel listener
|
||||
$listeners[] = new Reference('security.channel_listener');
|
||||
|
||||
$contextKey = null;
|
||||
$contextListenerId = null;
|
||||
// Context serializer listener
|
||||
if (false === $firewall['stateless']) {
|
||||
$contextKey = $firewall['context'] ?? $id;
|
||||
$listeners[] = new Reference($contextListenerId = $this->createContextListener($container, $contextKey, $this->authenticatorManagerEnabled ? $firewallEventDispatcherId : null));
|
||||
$sessionStrategyId = 'security.authentication.session_strategy';
|
||||
|
||||
if ($this->authenticatorManagerEnabled) {
|
||||
$container
|
||||
->setDefinition('security.listener.session.'.$id, new ChildDefinition('security.listener.session'))
|
||||
->addTag('kernel.event_subscriber', ['dispatcher' => $firewallEventDispatcherId]);
|
||||
}
|
||||
} else {
|
||||
$this->statelessFirewallKeys[] = $id;
|
||||
$sessionStrategyId = 'security.authentication.session_strategy_noop';
|
||||
}
|
||||
$container->setAlias(new Alias('security.authentication.session_strategy.'.$id, false), $sessionStrategyId);
|
||||
|
||||
$config->replaceArgument(6, $contextKey);
|
||||
|
||||
// Logout listener
|
||||
$logoutListenerId = null;
|
||||
if (isset($firewall['logout'])) {
|
||||
$logoutListenerId = 'security.logout_listener.'.$id;
|
||||
$logoutListener = $container->setDefinition($logoutListenerId, new ChildDefinition('security.logout_listener'));
|
||||
$logoutListener->replaceArgument(2, new Reference($firewallEventDispatcherId));
|
||||
$logoutListener->replaceArgument(3, [
|
||||
'csrf_parameter' => $firewall['logout']['csrf_parameter'],
|
||||
'csrf_token_id' => $firewall['logout']['csrf_token_id'],
|
||||
'logout_path' => $firewall['logout']['path'],
|
||||
]);
|
||||
|
||||
// add default logout listener
|
||||
if (isset($firewall['logout']['success_handler'])) {
|
||||
// deprecated, to be removed in Symfony 6.0
|
||||
$logoutSuccessHandlerId = $firewall['logout']['success_handler'];
|
||||
$container->register('security.logout.listener.legacy_success_listener.'.$id, LegacyLogoutHandlerListener::class)
|
||||
->setArguments([new Reference($logoutSuccessHandlerId)])
|
||||
->addTag('kernel.event_subscriber', ['dispatcher' => $firewallEventDispatcherId]);
|
||||
} else {
|
||||
$logoutSuccessListenerId = 'security.logout.listener.default.'.$id;
|
||||
$container->setDefinition($logoutSuccessListenerId, new ChildDefinition('security.logout.listener.default'))
|
||||
->replaceArgument(1, $firewall['logout']['target'])
|
||||
->addTag('kernel.event_subscriber', ['dispatcher' => $firewallEventDispatcherId]);
|
||||
}
|
||||
|
||||
// add CSRF provider
|
||||
if (isset($firewall['logout']['csrf_token_generator'])) {
|
||||
$logoutListener->addArgument(new Reference($firewall['logout']['csrf_token_generator']));
|
||||
}
|
||||
|
||||
// add session logout listener
|
||||
if (true === $firewall['logout']['invalidate_session'] && false === $firewall['stateless']) {
|
||||
$container->setDefinition('security.logout.listener.session.'.$id, new ChildDefinition('security.logout.listener.session'))
|
||||
->addTag('kernel.event_subscriber', ['dispatcher' => $firewallEventDispatcherId]);
|
||||
}
|
||||
|
||||
// add cookie logout listener
|
||||
if (\count($firewall['logout']['delete_cookies']) > 0) {
|
||||
$container->setDefinition('security.logout.listener.cookie_clearing.'.$id, new ChildDefinition('security.logout.listener.cookie_clearing'))
|
||||
->addArgument($firewall['logout']['delete_cookies'])
|
||||
->addTag('kernel.event_subscriber', ['dispatcher' => $firewallEventDispatcherId]);
|
||||
}
|
||||
|
||||
// add custom listeners (deprecated)
|
||||
foreach ($firewall['logout']['handlers'] as $i => $handlerId) {
|
||||
$container->register('security.logout.listener.legacy_handler.'.$i, LegacyLogoutHandlerListener::class)
|
||||
->addArgument(new Reference($handlerId))
|
||||
->addTag('kernel.event_subscriber', ['dispatcher' => $firewallEventDispatcherId]);
|
||||
}
|
||||
|
||||
// register with LogoutUrlGenerator
|
||||
$container
|
||||
->getDefinition('security.logout_url_generator')
|
||||
->addMethodCall('registerListener', [
|
||||
$id,
|
||||
$firewall['logout']['path'],
|
||||
$firewall['logout']['csrf_token_id'],
|
||||
$firewall['logout']['csrf_parameter'],
|
||||
isset($firewall['logout']['csrf_token_generator']) ? new Reference($firewall['logout']['csrf_token_generator']) : null,
|
||||
false === $firewall['stateless'] && isset($firewall['context']) ? $firewall['context'] : null,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
// Determine default entry point
|
||||
$configuredEntryPoint = $firewall['entry_point'] ?? null;
|
||||
|
||||
// Authentication listeners
|
||||
$firewallAuthenticationProviders = [];
|
||||
[$authListeners, $defaultEntryPoint] = $this->createAuthenticationListeners($container, $id, $firewall, $firewallAuthenticationProviders, $defaultProvider, $providerIds, $configuredEntryPoint, $contextListenerId);
|
||||
|
||||
if (!$this->authenticatorManagerEnabled) {
|
||||
$authenticationProviders = array_merge($authenticationProviders, $firewallAuthenticationProviders);
|
||||
} else {
|
||||
// $configuredEntryPoint is resolved into a service ID and stored in $defaultEntryPoint
|
||||
$configuredEntryPoint = $defaultEntryPoint;
|
||||
|
||||
// authenticator manager
|
||||
$authenticators = array_map(function ($id) {
|
||||
return new Reference($id);
|
||||
}, $firewallAuthenticationProviders);
|
||||
$container
|
||||
->setDefinition($managerId = 'security.authenticator.manager.'.$id, new ChildDefinition('security.authenticator.manager'))
|
||||
->replaceArgument(0, $authenticators)
|
||||
->replaceArgument(2, new Reference($firewallEventDispatcherId))
|
||||
->replaceArgument(3, $id)
|
||||
->replaceArgument(7, $firewall['required_badges'] ?? [])
|
||||
->addTag('monolog.logger', ['channel' => 'security'])
|
||||
;
|
||||
|
||||
$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, new ChildDefinition('security.firewall.authenticator'))
|
||||
->replaceArgument(0, new Reference($managerId))
|
||||
;
|
||||
|
||||
if ($container->hasDefinition('debug.security.firewall') && $this->authenticatorManagerEnabled) {
|
||||
$container
|
||||
->register('debug.security.firewall.authenticator.'.$id, TraceableAuthenticatorManagerListener::class)
|
||||
->setDecoratedService('security.firewall.authenticator.'.$id)
|
||||
->setArguments([new Reference('debug.security.firewall.authenticator.'.$id.'.inner')])
|
||||
;
|
||||
}
|
||||
|
||||
// user checker listener
|
||||
$container
|
||||
->setDefinition('security.listener.user_checker.'.$id, new ChildDefinition('security.listener.user_checker'))
|
||||
->replaceArgument(0, new Reference('security.user_checker.'.$id))
|
||||
->addTag('kernel.event_subscriber', ['dispatcher' => $firewallEventDispatcherId]);
|
||||
|
||||
$listeners[] = new Reference('security.firewall.authenticator.'.$id);
|
||||
|
||||
// Add authenticators to the debug:firewall command
|
||||
if ($container->hasDefinition('security.command.debug_firewall')) {
|
||||
$debugCommand = $container->getDefinition('security.command.debug_firewall');
|
||||
$debugCommand->replaceArgument(3, array_merge($debugCommand->getArgument(3), [$id => $authenticators]));
|
||||
}
|
||||
}
|
||||
|
||||
$config->replaceArgument(7, $configuredEntryPoint ?: $defaultEntryPoint);
|
||||
|
||||
$listeners = array_merge($listeners, $authListeners);
|
||||
|
||||
// Switch user listener
|
||||
if (isset($firewall['switch_user'])) {
|
||||
$listenerKeys[] = 'switch_user';
|
||||
$listeners[] = new Reference($this->createSwitchUserListener($container, $id, $firewall['switch_user'], $defaultProvider, $firewall['stateless']));
|
||||
}
|
||||
|
||||
// Access listener
|
||||
$listeners[] = new Reference('security.access_listener');
|
||||
|
||||
// Exception listener
|
||||
$exceptionListener = new Reference($this->createExceptionListener($container, $firewall, $id, $configuredEntryPoint ?: $defaultEntryPoint, $firewall['stateless']));
|
||||
|
||||
$config->replaceArgument(8, $firewall['access_denied_handler'] ?? null);
|
||||
$config->replaceArgument(9, $firewall['access_denied_url'] ?? null);
|
||||
|
||||
$container->setAlias('security.user_checker.'.$id, new Alias($firewall['user_checker'], false));
|
||||
|
||||
foreach ($this->getSortedFactories() as $factory) {
|
||||
$key = str_replace('-', '_', $factory->getKey());
|
||||
if ('custom_authenticators' !== $key && \array_key_exists($key, $firewall)) {
|
||||
$listenerKeys[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
if ($firewall['custom_authenticators'] ?? false) {
|
||||
foreach ($firewall['custom_authenticators'] as $customAuthenticatorId) {
|
||||
$listenerKeys[] = $customAuthenticatorId;
|
||||
}
|
||||
}
|
||||
|
||||
$config->replaceArgument(10, $listenerKeys);
|
||||
$config->replaceArgument(11, $firewall['switch_user'] ?? null);
|
||||
|
||||
return [$matcher, $listeners, $exceptionListener, null !== $logoutListenerId ? new Reference($logoutListenerId) : null];
|
||||
}
|
||||
|
||||
private function createContextListener(ContainerBuilder $container, string $contextKey, ?string $firewallEventDispatcherId)
|
||||
{
|
||||
if (isset($this->contextListeners[$contextKey])) {
|
||||
return $this->contextListeners[$contextKey];
|
||||
}
|
||||
|
||||
$listenerId = 'security.context_listener.'.\count($this->contextListeners);
|
||||
$listener = $container->setDefinition($listenerId, new ChildDefinition('security.context_listener'));
|
||||
$listener->replaceArgument(2, $contextKey);
|
||||
if (null !== $firewallEventDispatcherId) {
|
||||
$listener->replaceArgument(4, new Reference($firewallEventDispatcherId));
|
||||
$listener->addTag('kernel.event_listener', ['event' => KernelEvents::RESPONSE, 'method' => 'onKernelResponse']);
|
||||
}
|
||||
|
||||
return $this->contextListeners[$contextKey] = $listenerId;
|
||||
}
|
||||
|
||||
private function createAuthenticationListeners(ContainerBuilder $container, string $id, array $firewall, array &$authenticationProviders, ?string $defaultProvider, array $providerIds, ?string $defaultEntryPoint, string $contextListenerId = null)
|
||||
{
|
||||
$listeners = [];
|
||||
$hasListeners = false;
|
||||
$entryPoints = [];
|
||||
|
||||
foreach ($this->getSortedFactories() as $factory) {
|
||||
$key = str_replace('-', '_', $factory->getKey());
|
||||
|
||||
if (isset($firewall[$key])) {
|
||||
$userProvider = $this->getUserProvider($container, $id, $firewall, $key, $defaultProvider, $providerIds, $contextListenerId);
|
||||
|
||||
if ($this->authenticatorManagerEnabled) {
|
||||
if (!$factory instanceof AuthenticatorFactoryInterface) {
|
||||
throw new InvalidConfigurationException(sprintf('Cannot configure AuthenticatorManager as "%s" authentication does not support it, set "security.enable_authenticator_manager" to `false`.', $key));
|
||||
}
|
||||
|
||||
$authenticators = $factory->createAuthenticator($container, $id, $firewall[$key], $userProvider);
|
||||
if (\is_array($authenticators)) {
|
||||
foreach ($authenticators as $authenticator) {
|
||||
$authenticationProviders[] = $authenticator;
|
||||
$entryPoints[] = $authenticator;
|
||||
}
|
||||
} else {
|
||||
$authenticationProviders[] = $authenticators;
|
||||
$entryPoints[$key] = $authenticators;
|
||||
}
|
||||
} else {
|
||||
[$provider, $listenerId, $defaultEntryPoint] = $factory->create($container, $id, $firewall[$key], $userProvider, $defaultEntryPoint);
|
||||
|
||||
$listeners[] = new Reference($listenerId);
|
||||
$authenticationProviders[] = $provider;
|
||||
}
|
||||
|
||||
if ($factory instanceof FirewallListenerFactoryInterface) {
|
||||
$firewallListenerIds = $factory->createListeners($container, $id, $firewall[$key]);
|
||||
foreach ($firewallListenerIds as $firewallListenerId) {
|
||||
$listeners[] = new Reference($firewallListenerId);
|
||||
}
|
||||
}
|
||||
|
||||
$hasListeners = true;
|
||||
}
|
||||
}
|
||||
|
||||
// the actual entry point is configured by the RegisterEntryPointPass
|
||||
$container->setParameter('security.'.$id.'._indexed_authenticators', $entryPoints);
|
||||
|
||||
if (false === $hasListeners && !$this->authenticatorManagerEnabled) {
|
||||
throw new InvalidConfigurationException(sprintf('No authentication listener registered for firewall "%s".', $id));
|
||||
}
|
||||
|
||||
return [$listeners, $defaultEntryPoint];
|
||||
}
|
||||
|
||||
private function getUserProvider(ContainerBuilder $container, string $id, array $firewall, string $factoryKey, ?string $defaultProvider, array $providerIds, ?string $contextListenerId): string
|
||||
{
|
||||
if (isset($firewall[$factoryKey]['provider'])) {
|
||||
if (!isset($providerIds[$normalizedName = str_replace('-', '_', $firewall[$factoryKey]['provider'])])) {
|
||||
throw new InvalidConfigurationException(sprintf('Invalid firewall "%s": user provider "%s" not found.', $id, $firewall[$factoryKey]['provider']));
|
||||
}
|
||||
|
||||
return $providerIds[$normalizedName];
|
||||
}
|
||||
|
||||
if ('remember_me' === $factoryKey && $contextListenerId) {
|
||||
$container->getDefinition($contextListenerId)->addTag('security.remember_me_aware', ['id' => $id, 'provider' => 'none']);
|
||||
}
|
||||
|
||||
if ($defaultProvider) {
|
||||
return $defaultProvider;
|
||||
}
|
||||
|
||||
if (!$providerIds) {
|
||||
$userProvider = sprintf('security.user.provider.missing.%s', $factoryKey);
|
||||
$container->setDefinition(
|
||||
$userProvider,
|
||||
(new ChildDefinition('security.user.provider.missing'))->replaceArgument(0, $id)
|
||||
);
|
||||
|
||||
return $userProvider;
|
||||
}
|
||||
|
||||
if ('remember_me' === $factoryKey || 'anonymous' === $factoryKey || 'custom_authenticators' === $factoryKey) {
|
||||
if ('custom_authenticators' === $factoryKey) {
|
||||
trigger_deprecation('symfony/security-bundle', '5.4', 'Not configuring explicitly the provider for the "%s" firewall is deprecated because it\'s ambiguous as there is more than one registered provider. Set the "provider" key to one of the configured providers, even if your custom authenticators don\'t use it.', $id);
|
||||
}
|
||||
|
||||
return 'security.user_providers';
|
||||
}
|
||||
|
||||
throw new InvalidConfigurationException(sprintf('Not configuring explicitly the provider for the "%s" %s on "%s" firewall is ambiguous as there is more than one registered provider.', $factoryKey, $this->authenticatorManagerEnabled ? 'authenticator' : 'listener', $id));
|
||||
}
|
||||
|
||||
private function createEncoders(array $encoders, ContainerBuilder $container)
|
||||
{
|
||||
$encoderMap = [];
|
||||
foreach ($encoders as $class => $encoder) {
|
||||
if (class_exists($class) && !is_a($class, PasswordAuthenticatedUserInterface::class, true)) {
|
||||
trigger_deprecation('symfony/security-bundle', '5.3', 'Configuring an encoder for a user class that does not implement "%s" is deprecated, class "%s" should implement it.', PasswordAuthenticatedUserInterface::class, $class);
|
||||
}
|
||||
$encoderMap[$class] = $this->createEncoder($encoder);
|
||||
}
|
||||
|
||||
$container
|
||||
->getDefinition('security.encoder_factory.generic')
|
||||
->setArguments([$encoderMap])
|
||||
;
|
||||
}
|
||||
|
||||
private function createEncoder(array $config)
|
||||
{
|
||||
// a custom encoder service
|
||||
if (isset($config['id'])) {
|
||||
return new Reference($config['id']);
|
||||
}
|
||||
|
||||
if ($config['migrate_from'] ?? false) {
|
||||
return $config;
|
||||
}
|
||||
|
||||
// plaintext encoder
|
||||
if ('plaintext' === $config['algorithm']) {
|
||||
$arguments = [$config['ignore_case']];
|
||||
|
||||
return [
|
||||
'class' => 'Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder',
|
||||
'arguments' => $arguments,
|
||||
];
|
||||
}
|
||||
|
||||
// pbkdf2 encoder
|
||||
if ('pbkdf2' === $config['algorithm']) {
|
||||
return [
|
||||
'class' => 'Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder',
|
||||
'arguments' => [
|
||||
$config['hash_algorithm'],
|
||||
$config['encode_as_base64'],
|
||||
$config['iterations'],
|
||||
$config['key_length'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// bcrypt encoder
|
||||
if ('bcrypt' === $config['algorithm']) {
|
||||
$config['algorithm'] = 'native';
|
||||
$config['native_algorithm'] = \PASSWORD_BCRYPT;
|
||||
|
||||
return $this->createEncoder($config);
|
||||
}
|
||||
|
||||
// Argon2i encoder
|
||||
if ('argon2i' === $config['algorithm']) {
|
||||
if (SodiumPasswordHasher::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) {
|
||||
$config['algorithm'] = 'sodium';
|
||||
} elseif (\defined('PASSWORD_ARGON2I')) {
|
||||
$config['algorithm'] = 'native';
|
||||
$config['native_algorithm'] = \PASSWORD_ARGON2I;
|
||||
} else {
|
||||
throw new InvalidConfigurationException(sprintf('Algorithm "argon2i" is not available. Use "%s" instead.', \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13') ? 'argon2id", "auto' : 'auto'));
|
||||
}
|
||||
|
||||
return $this->createEncoder($config);
|
||||
}
|
||||
|
||||
if ('argon2id' === $config['algorithm']) {
|
||||
if (($hasSodium = SodiumPasswordHasher::isSupported()) && \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) {
|
||||
$config['algorithm'] = 'sodium';
|
||||
} elseif (\defined('PASSWORD_ARGON2ID')) {
|
||||
$config['algorithm'] = 'native';
|
||||
$config['native_algorithm'] = \PASSWORD_ARGON2ID;
|
||||
} else {
|
||||
throw new InvalidConfigurationException(sprintf('Algorithm "argon2id" is not available. Either use "%s", upgrade to PHP 7.3+ or use libsodium 1.0.15+ instead.', \defined('PASSWORD_ARGON2I') || $hasSodium ? 'argon2i", "auto' : 'auto'));
|
||||
}
|
||||
|
||||
return $this->createEncoder($config);
|
||||
}
|
||||
|
||||
if ('native' === $config['algorithm']) {
|
||||
return [
|
||||
'class' => NativePasswordEncoder::class,
|
||||
'arguments' => [
|
||||
$config['time_cost'],
|
||||
(($config['memory_cost'] ?? 0) << 10) ?: null,
|
||||
$config['cost'],
|
||||
] + (isset($config['native_algorithm']) ? [3 => $config['native_algorithm']] : []),
|
||||
];
|
||||
}
|
||||
|
||||
if ('sodium' === $config['algorithm']) {
|
||||
if (!SodiumPasswordHasher::isSupported()) {
|
||||
throw new InvalidConfigurationException('Libsodium is not available. Install the sodium extension or use "auto" instead.');
|
||||
}
|
||||
|
||||
return [
|
||||
'class' => SodiumPasswordEncoder::class,
|
||||
'arguments' => [
|
||||
$config['time_cost'],
|
||||
(($config['memory_cost'] ?? 0) << 10) ?: null,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// run-time configured encoder
|
||||
return $config;
|
||||
}
|
||||
|
||||
private function createHashers(array $hashers, ContainerBuilder $container)
|
||||
{
|
||||
$hasherMap = [];
|
||||
foreach ($hashers as $class => $hasher) {
|
||||
// @deprecated since Symfony 5.3, remove the check in 6.0
|
||||
if (class_exists($class) && !is_a($class, PasswordAuthenticatedUserInterface::class, true)) {
|
||||
trigger_deprecation('symfony/security-bundle', '5.3', 'Configuring a password hasher for a user class that does not implement "%s" is deprecated, class "%s" should implement it.', PasswordAuthenticatedUserInterface::class, $class);
|
||||
}
|
||||
$hasherMap[$class] = $this->createHasher($hasher);
|
||||
}
|
||||
|
||||
$container
|
||||
->getDefinition('security.password_hasher_factory')
|
||||
->setArguments([$hasherMap])
|
||||
;
|
||||
}
|
||||
|
||||
private function createHasher(array $config)
|
||||
{
|
||||
// a custom hasher service
|
||||
if (isset($config['id'])) {
|
||||
return new Reference($config['id']);
|
||||
}
|
||||
|
||||
if ($config['migrate_from'] ?? false) {
|
||||
return $config;
|
||||
}
|
||||
|
||||
// plaintext hasher
|
||||
if ('plaintext' === $config['algorithm']) {
|
||||
$arguments = [$config['ignore_case']];
|
||||
|
||||
return [
|
||||
'class' => PlaintextPasswordHasher::class,
|
||||
'arguments' => $arguments,
|
||||
];
|
||||
}
|
||||
|
||||
// pbkdf2 hasher
|
||||
if ('pbkdf2' === $config['algorithm']) {
|
||||
return [
|
||||
'class' => Pbkdf2PasswordHasher::class,
|
||||
'arguments' => [
|
||||
$config['hash_algorithm'],
|
||||
$config['encode_as_base64'],
|
||||
$config['iterations'],
|
||||
$config['key_length'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// bcrypt hasher
|
||||
if ('bcrypt' === $config['algorithm']) {
|
||||
$config['algorithm'] = 'native';
|
||||
$config['native_algorithm'] = \PASSWORD_BCRYPT;
|
||||
|
||||
return $this->createHasher($config);
|
||||
}
|
||||
|
||||
// Argon2i hasher
|
||||
if ('argon2i' === $config['algorithm']) {
|
||||
if (SodiumPasswordHasher::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) {
|
||||
$config['algorithm'] = 'sodium';
|
||||
} elseif (\defined('PASSWORD_ARGON2I')) {
|
||||
$config['algorithm'] = 'native';
|
||||
$config['native_algorithm'] = \PASSWORD_ARGON2I;
|
||||
} else {
|
||||
throw new InvalidConfigurationException(sprintf('Algorithm "argon2i" is not available. Either use "%s" or upgrade to PHP 7.2+ instead.', \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13') ? 'argon2id", "auto' : 'auto'));
|
||||
}
|
||||
|
||||
return $this->createHasher($config);
|
||||
}
|
||||
|
||||
if ('argon2id' === $config['algorithm']) {
|
||||
if (($hasSodium = SodiumPasswordHasher::isSupported()) && \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) {
|
||||
$config['algorithm'] = 'sodium';
|
||||
} elseif (\defined('PASSWORD_ARGON2ID')) {
|
||||
$config['algorithm'] = 'native';
|
||||
$config['native_algorithm'] = \PASSWORD_ARGON2ID;
|
||||
} else {
|
||||
throw new InvalidConfigurationException(sprintf('Algorithm "argon2id" is not available. Either use "%s", upgrade to PHP 7.3+ or use libsodium 1.0.15+ instead.', \defined('PASSWORD_ARGON2I') || $hasSodium ? 'argon2i", "auto' : 'auto'));
|
||||
}
|
||||
|
||||
return $this->createHasher($config);
|
||||
}
|
||||
|
||||
if ('native' === $config['algorithm']) {
|
||||
return [
|
||||
'class' => NativePasswordHasher::class,
|
||||
'arguments' => [
|
||||
$config['time_cost'],
|
||||
(($config['memory_cost'] ?? 0) << 10) ?: null,
|
||||
$config['cost'],
|
||||
] + (isset($config['native_algorithm']) ? [3 => $config['native_algorithm']] : []),
|
||||
];
|
||||
}
|
||||
|
||||
if ('sodium' === $config['algorithm']) {
|
||||
if (!SodiumPasswordHasher::isSupported()) {
|
||||
throw new InvalidConfigurationException('Libsodium is not available. Install the sodium extension or use "auto" instead.');
|
||||
}
|
||||
|
||||
return [
|
||||
'class' => SodiumPasswordHasher::class,
|
||||
'arguments' => [
|
||||
$config['time_cost'],
|
||||
(($config['memory_cost'] ?? 0) << 10) ?: null,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// run-time configured hasher
|
||||
return $config;
|
||||
}
|
||||
|
||||
// Parses user providers and returns an array of their ids
|
||||
private function createUserProviders(array $config, ContainerBuilder $container): array
|
||||
{
|
||||
$providerIds = [];
|
||||
foreach ($config['providers'] as $name => $provider) {
|
||||
$id = $this->createUserDaoProvider($name, $provider, $container);
|
||||
$providerIds[str_replace('-', '_', $name)] = $id;
|
||||
}
|
||||
|
||||
return $providerIds;
|
||||
}
|
||||
|
||||
// Parses a <provider> tag and returns the id for the related user provider service
|
||||
private function createUserDaoProvider(string $name, array $provider, ContainerBuilder $container): string
|
||||
{
|
||||
$name = $this->getUserProviderId($name);
|
||||
|
||||
// Doctrine Entity and In-memory DAO provider are managed by factories
|
||||
foreach ($this->userProviderFactories as $factory) {
|
||||
$key = str_replace('-', '_', $factory->getKey());
|
||||
|
||||
if (!empty($provider[$key])) {
|
||||
$factory->create($container, $name, $provider[$key]);
|
||||
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
|
||||
// Existing DAO service provider
|
||||
if (isset($provider['id'])) {
|
||||
$container->setAlias($name, new Alias($provider['id'], false));
|
||||
|
||||
return $provider['id'];
|
||||
}
|
||||
|
||||
// Chain provider
|
||||
if (isset($provider['chain'])) {
|
||||
$providers = [];
|
||||
foreach ($provider['chain']['providers'] as $providerName) {
|
||||
$providers[] = new Reference($this->getUserProviderId($providerName));
|
||||
}
|
||||
|
||||
$container
|
||||
->setDefinition($name, new ChildDefinition('security.user.provider.chain'))
|
||||
->addArgument(new IteratorArgument($providers));
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
throw new InvalidConfigurationException(sprintf('Unable to create definition for "%s" user provider.', $name));
|
||||
}
|
||||
|
||||
private function getUserProviderId(string $name): string
|
||||
{
|
||||
return 'security.user.provider.concrete.'.strtolower($name);
|
||||
}
|
||||
|
||||
private function createExceptionListener(ContainerBuilder $container, array $config, string $id, ?string $defaultEntryPoint, bool $stateless): string
|
||||
{
|
||||
$exceptionListenerId = 'security.exception_listener.'.$id;
|
||||
$listener = $container->setDefinition($exceptionListenerId, new ChildDefinition('security.exception_listener'));
|
||||
$listener->replaceArgument(3, $id);
|
||||
$listener->replaceArgument(4, null === $defaultEntryPoint ? null : new Reference($defaultEntryPoint));
|
||||
$listener->replaceArgument(8, $stateless);
|
||||
|
||||
// access denied handler setup
|
||||
if (isset($config['access_denied_handler'])) {
|
||||
$listener->replaceArgument(6, new Reference($config['access_denied_handler']));
|
||||
} elseif (isset($config['access_denied_url'])) {
|
||||
$listener->replaceArgument(5, $config['access_denied_url']);
|
||||
}
|
||||
|
||||
return $exceptionListenerId;
|
||||
}
|
||||
|
||||
private function createSwitchUserListener(ContainerBuilder $container, string $id, array $config, ?string $defaultProvider, bool $stateless): string
|
||||
{
|
||||
$userProvider = isset($config['provider']) ? $this->getUserProviderId($config['provider']) : $defaultProvider;
|
||||
|
||||
if (!$userProvider) {
|
||||
throw new InvalidConfigurationException(sprintf('Not configuring explicitly the provider for the "switch_user" listener on "%s" firewall is ambiguous as there is more than one registered provider.', $id));
|
||||
}
|
||||
|
||||
$switchUserListenerId = 'security.authentication.switchuser_listener.'.$id;
|
||||
$listener = $container->setDefinition($switchUserListenerId, new ChildDefinition('security.authentication.switchuser_listener'));
|
||||
$listener->replaceArgument(1, new Reference($userProvider));
|
||||
$listener->replaceArgument(2, new Reference('security.user_checker.'.$id));
|
||||
$listener->replaceArgument(3, $id);
|
||||
$listener->replaceArgument(6, $config['parameter']);
|
||||
$listener->replaceArgument(7, $config['role']);
|
||||
$listener->replaceArgument(9, $stateless);
|
||||
|
||||
return $switchUserListenerId;
|
||||
}
|
||||
|
||||
private function createExpression(ContainerBuilder $container, string $expression): Reference
|
||||
{
|
||||
if (isset($this->expressions[$id = '.security.expression.'.ContainerBuilder::hash($expression)])) {
|
||||
return $this->expressions[$id];
|
||||
}
|
||||
|
||||
if (!$container::willBeAvailable('symfony/expression-language', ExpressionLanguage::class, ['symfony/security-bundle'], true)) {
|
||||
throw new \RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed. Try running "composer require symfony/expression-language".');
|
||||
}
|
||||
|
||||
$container
|
||||
->register($id, 'Symfony\Component\ExpressionLanguage\Expression')
|
||||
->setPublic(false)
|
||||
->addArgument($expression)
|
||||
;
|
||||
|
||||
return $this->expressions[$id] = new Reference($id);
|
||||
}
|
||||
|
||||
private function createRequestMatcher(ContainerBuilder $container, string $path = null, string $host = null, int $port = null, array $methods = [], array $ips = null, array $attributes = []): Reference
|
||||
{
|
||||
if ($methods) {
|
||||
$methods = array_map('strtoupper', $methods);
|
||||
}
|
||||
|
||||
if (null !== $ips) {
|
||||
foreach ($ips as $ip) {
|
||||
$container->resolveEnvPlaceholders($ip, null, $usedEnvs);
|
||||
|
||||
if (!$usedEnvs && !$this->isValidIps($ip)) {
|
||||
throw new \LogicException(sprintf('The given value "%s" in the "security.access_control" config option is not a valid IP address.', $ip));
|
||||
}
|
||||
|
||||
$usedEnvs = null;
|
||||
}
|
||||
}
|
||||
|
||||
$id = '.security.request_matcher.'.ContainerBuilder::hash([$path, $host, $port, $methods, $ips, $attributes]);
|
||||
|
||||
if (isset($this->requestMatchers[$id])) {
|
||||
return $this->requestMatchers[$id];
|
||||
}
|
||||
|
||||
// only add arguments that are necessary
|
||||
$arguments = [$path, $host, $methods, $ips, $attributes, null, $port];
|
||||
while (\count($arguments) > 0 && !end($arguments)) {
|
||||
array_pop($arguments);
|
||||
}
|
||||
|
||||
$container
|
||||
->register($id, 'Symfony\Component\HttpFoundation\RequestMatcher')
|
||||
->setPublic(false)
|
||||
->setArguments($arguments)
|
||||
;
|
||||
|
||||
return $this->requestMatchers[$id] = new Reference($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since Symfony 5.4, use "addAuthenticatorFactory()" instead
|
||||
*/
|
||||
public function addSecurityListenerFactory(SecurityFactoryInterface $factory)
|
||||
{
|
||||
trigger_deprecation('symfony/security-bundle', '5.4', 'Method "%s()" is deprecated, use "addAuthenticatorFactory()" instead.', __METHOD__);
|
||||
|
||||
$this->factories[] = [[
|
||||
'pre_auth' => -10,
|
||||
'form' => -30,
|
||||
'http' => -40,
|
||||
'remember_me' => -50,
|
||||
'anonymous' => -60,
|
||||
][$factory->getPosition()], $factory];
|
||||
$this->sortedFactories = [];
|
||||
}
|
||||
|
||||
public function addAuthenticatorFactory(AuthenticatorFactoryInterface $factory)
|
||||
{
|
||||
$this->factories[] = [method_exists($factory, 'getPriority') ? $factory->getPriority() : 0, $factory];
|
||||
$this->sortedFactories = [];
|
||||
}
|
||||
|
||||
public function addUserProviderFactory(UserProviderFactoryInterface $factory)
|
||||
{
|
||||
$this->userProviderFactories[] = $factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getXsdValidationBasePath()
|
||||
{
|
||||
return __DIR__.'/../Resources/config/schema';
|
||||
}
|
||||
|
||||
public function getNamespace()
|
||||
{
|
||||
return 'http://symfony.com/schema/dic/security';
|
||||
}
|
||||
|
||||
public function getConfiguration(array $config, ContainerBuilder $container)
|
||||
{
|
||||
// first assemble the factories
|
||||
return new MainConfiguration($this->getSortedFactories(), $this->userProviderFactories);
|
||||
}
|
||||
|
||||
private function isValidIps($ips): bool
|
||||
{
|
||||
$ipsList = array_reduce((array) $ips, static function (array $ips, string $ip) {
|
||||
return array_merge($ips, preg_split('/\s*,\s*/', $ip));
|
||||
}, []);
|
||||
|
||||
if (!$ipsList) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($ipsList as $cidr) {
|
||||
if (!$this->isValidIp($cidr)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function isValidIp(string $cidr): bool
|
||||
{
|
||||
$cidrParts = explode('/', $cidr);
|
||||
|
||||
if (1 === \count($cidrParts)) {
|
||||
return false !== filter_var($cidrParts[0], \FILTER_VALIDATE_IP);
|
||||
}
|
||||
|
||||
$ip = $cidrParts[0];
|
||||
$netmask = $cidrParts[1];
|
||||
|
||||
if (!ctype_digit($netmask)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) {
|
||||
return $netmask <= 32;
|
||||
}
|
||||
|
||||
if (filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) {
|
||||
return $netmask <= 128;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, SecurityFactoryInterface|AuthenticatorFactoryInterface>
|
||||
*/
|
||||
private function getSortedFactories(): array
|
||||
{
|
||||
if (!$this->sortedFactories) {
|
||||
$factories = [];
|
||||
foreach ($this->factories as $i => $factory) {
|
||||
$factories[] = array_merge($factory, [$i]);
|
||||
}
|
||||
|
||||
usort($factories, function ($a, $b) {
|
||||
return $b[0] <=> $a[0] ?: $a[2] <=> $b[2];
|
||||
});
|
||||
|
||||
$this->sortedFactories = array_column($factories, 1);
|
||||
}
|
||||
|
||||
return $this->sortedFactories;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user