This commit is contained in:
Xes
2025-08-14 22:41:49 +02:00
parent 2de81ccc46
commit 8ce45119b6
39774 changed files with 4309466 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
<?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;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
use Symfony\Component\DependencyInjection\Exception\LogicException;
/**
* 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"');
}
$adm = $container->getDefinition($container->hasDefinition('debug.security.access.decision_manager') ? 'debug.security.access.decision_manager' : 'security.access.decision_manager');
$adm->addMethodCall('setVoters', array($voters));
}
}

View 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\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/**
* 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'], '.')));
$domainRegexp = (empty($sessionOptions['cookie_secure']) ? 'https?://' : 'https://').$domainRegexp;
$container->findDefinition('security.http_utils')->addArgument(sprintf('{^%s$}i', $domainRegexp));
}
}

View File

@@ -0,0 +1,420 @@
<?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\Component\Security\Core\Authorization\AccessDecisionManager;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy;
/**
* This class contains the configuration information.
*
* This information is for the following tags:
*
* * security.config
* * security.acl
*
* This information is solely responsible for how the different configuration
* sections are normalized, and merged.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class MainConfiguration implements ConfigurationInterface
{
private $factories;
private $userProviderFactories;
/**
* Constructor.
*
* @param array $factories
* @param array $userProviderFactories
*/
public function __construct(array $factories, array $userProviderFactories)
{
$this->factories = $factories;
$this->userProviderFactories = $userProviderFactories;
}
/**
* Generates the configuration tree builder.
*
* @return TreeBuilder The tree builder
*/
public function getConfigTreeBuilder()
{
$tb = new TreeBuilder();
$rootNode = $tb->root('security');
$rootNode
->children()
->scalarNode('access_denied_url')->defaultNull()->example('/foo/error403')->end()
->enumNode('session_fixation_strategy')
->values(array(SessionAuthenticationStrategy::NONE, SessionAuthenticationStrategy::MIGRATE, SessionAuthenticationStrategy::INVALIDATE))
->defaultValue(SessionAuthenticationStrategy::MIGRATE)
->end()
->booleanNode('hide_user_not_found')->defaultTrue()->end()
->booleanNode('always_authenticate_before_granting')->defaultFalse()->end()
->booleanNode('erase_credentials')->defaultTrue()->end()
->arrayNode('access_decision_manager')
->addDefaultsIfNotSet()
->children()
->enumNode('strategy')
->values(array(AccessDecisionManager::STRATEGY_AFFIRMATIVE, AccessDecisionManager::STRATEGY_CONSENSUS, AccessDecisionManager::STRATEGY_UNANIMOUS))
->defaultValue(AccessDecisionManager::STRATEGY_AFFIRMATIVE)
->end()
->booleanNode('allow_if_all_abstain')->defaultFalse()->end()
->booleanNode('allow_if_equal_granted_denied')->defaultTrue()->end()
->end()
->end()
->end()
;
$this->addAclSection($rootNode);
$this->addEncodersSection($rootNode);
$this->addProvidersSection($rootNode);
$this->addFirewallsSection($rootNode, $this->factories);
$this->addAccessControlSection($rootNode);
$this->addRoleHierarchySection($rootNode);
return $tb;
}
private function addAclSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('acl')
->children()
->scalarNode('connection')
->defaultNull()
->info('any name configured in doctrine.dbal section')
->end()
->arrayNode('cache')
->addDefaultsIfNotSet()
->children()
->scalarNode('id')->end()
->scalarNode('prefix')->defaultValue('sf2_acl_')->end()
->end()
->end()
->scalarNode('provider')->end()
->arrayNode('tables')
->addDefaultsIfNotSet()
->children()
->scalarNode('class')->defaultValue('acl_classes')->end()
->scalarNode('entry')->defaultValue('acl_entries')->end()
->scalarNode('object_identity')->defaultValue('acl_object_identities')->end()
->scalarNode('object_identity_ancestors')->defaultValue('acl_object_identity_ancestors')->end()
->scalarNode('security_identity')->defaultValue('acl_security_identities')->end()
->end()
->end()
->arrayNode('voter')
->addDefaultsIfNotSet()
->children()
->booleanNode('allow_if_object_identity_unavailable')->defaultTrue()->end()
->end()
->end()
->end()
->end()
->end()
;
}
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 array('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()
->arrayNode('ips')
->beforeNormalization()->ifString()->then(function ($v) { return array($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()
;
}
private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $factories)
{
$firewallNodeBuilder = $rootNode
->fixXmlConfig('firewall')
->children()
->arrayNode('firewalls')
->isRequired()
->requiresAtLeastOneElement()
->disallowNewKeysInSubsequentConfigs()
->useAttributeAsKey('name')
->prototype('array')
->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')->end()
->scalarNode('provider')->end()
->booleanNode('stateless')->defaultFalse()->end()
->scalarNode('context')->cannotBeEmpty()->end()
->arrayNode('logout')
->treatTrueLike(array())
->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')->end()
->booleanNode('invalidate_session')->defaultTrue()->end()
->end()
->fixXmlConfig('delete_cookie')
->children()
->arrayNode('delete_cookies')
->beforeNormalization()
->ifTrue(function ($v) { return is_array($v) && is_int(key($v)); })
->then(function ($v) { return array_map(function ($v) { return array('name' => $v); }, $v); })
->end()
->useAttributeAsKey('name')
->prototype('array')
->children()
->scalarNode('path')->defaultNull()->end()
->scalarNode('domain')->defaultNull()->end()
->end()
->end()
->end()
->end()
->fixXmlConfig('handler')
->children()
->arrayNode('handlers')
->prototype('scalar')->end()
->end()
->end()
->end()
->arrayNode('anonymous')
->canBeUnset()
->children()
->scalarNode('secret')->defaultValue(uniqid('', true))->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()
;
$abstractFactoryKeys = array();
foreach ($factories as $factoriesAtPosition) {
foreach ($factoriesAtPosition 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 (false !== strpos($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(array(
'my_memory_provider' => array(
'memory' => array(
'users' => array(
'foo' => array('password' => 'foo', 'roles' => 'ROLE_USER'),
'bar' => array('password' => 'bar', 'roles' => '[ROLE_USER, ROLE_ADMIN]'),
),
),
),
'my_entity_provider' => array('entity' => array('class' => 'SecurityBundle:User', 'property' => 'username')),
))
->isRequired()
->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 count($v) === 0; })
->thenInvalid('You must set a provider definition for the provider.')
->end()
;
}
private function addEncodersSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->fixXmlConfig('encoder')
->children()
->arrayNode('encoders')
->example(array(
'AppBundle\Entity\User1' => 'bcrypt',
'AppBundle\Entity\User2' => array(
'algorithm' => 'bcrypt',
'cost' => 13,
),
))
->requiresAtLeastOneElement()
->useAttributeAsKey('class')
->prototype('array')
->canBeUnset()
->performNoDeepMerging()
->beforeNormalization()->ifString()->then(function ($v) { return array('algorithm' => $v); })->end()
->children()
->scalarNode('algorithm')->cannotBeEmpty()->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)
->defaultValue(13)
->end()
->scalarNode('id')->end()
->end()
->end()
->end()
->end()
;
}
}

View File

@@ -0,0 +1,216 @@
<?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\DefinitionDecorator;
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 = array(
'check_path' => '/login_check',
'use_forward' => false,
'require_previous_session' => true,
);
protected $defaultSuccessHandlerOptions = array(
'always_use_default_target_path' => false,
'default_target_path' => '/',
'login_path' => '/login',
'target_path_parameter' => '_target_path',
'use_referer' => false,
);
protected $defaultFailureHandlerOptions = array(
'failure_path' => null,
'failure_forward' => false,
'login_path' => '/login',
'failure_path_parameter' => '_failure_path',
);
public function create(ContainerBuilder $container, $id, $config, $userProviderId, $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', array('id' => $id, 'provider' => $userProviderId))
;
}
// create entry point if applicable (optional)
$entryPointId = $this->createEntryPoint($container, $id, $config, $defaultEntryPointId);
return array($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($name, $default = null)
{
$this->options[$name] = $default;
}
/**
* Subclasses must return the id of a service which implements the
* AuthenticationProviderInterface.
*
* @param ContainerBuilder $container
* @param string $id The unique id of the firewall
* @param array $config The options array for this listener
* @param string $userProviderId The id of the user provider
*
* @return string never null, the id of the authentication provider
*/
abstract protected function createAuthProvider(ContainerBuilder $container, $id, $config, $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.
*
* @param ContainerBuilder $container
* @param string $id
* @param array $config
* @param string $defaultEntryPointId
*
* @return string the entry point id
*/
protected function createEntryPoint($container, $id, $config, $defaultEntryPointId)
{
return $defaultEntryPointId;
}
/**
* Subclasses may disable remember-me features for the listener, by
* always returning false from this method.
*
* @param array $config
*
* @return bool Whether a possibly configured RememberMeServices should be set for this listener
*/
protected function isRememberMeAware($config)
{
return $config['remember_me'];
}
protected function createListener($container, $id, $config, $userProvider)
{
$listenerId = $this->getListenerId();
$listener = new DefinitionDecorator($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($container, $id, $config)
{
$successHandlerId = $this->getSuccessHandlerId($id);
$options = array_intersect_key($config, $this->defaultSuccessHandlerOptions);
if (isset($config['success_handler'])) {
$successHandler = $container->setDefinition($successHandlerId, new DefinitionDecorator('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 DefinitionDecorator('security.authentication.success_handler'));
$successHandler->addMethodCall('setOptions', array($options));
$successHandler->addMethodCall('setProviderKey', array($id));
}
return $successHandlerId;
}
protected function createAuthenticationFailureHandler($container, $id, $config)
{
$id = $this->getFailureHandlerId($id);
$options = array_intersect_key($config, $this->defaultFailureHandlerOptions);
if (isset($config['failure_handler'])) {
$failureHandler = $container->setDefinition($id, new DefinitionDecorator('security.authentication.custom_failure_handler'));
$failureHandler->replaceArgument(0, new Reference($config['failure_handler']));
$failureHandler->replaceArgument(1, $options);
} else {
$failureHandler = $container->setDefinition($id, new DefinitionDecorator('security.authentication.failure_handler'));
$failureHandler->addMethodCall('setOptions', array($options));
}
return $id;
}
protected function getSuccessHandlerId($id)
{
return 'security.authentication.success_handler.'.$id.'.'.str_replace('-', '_', $this->getKey());
}
protected function getFailureHandlerId($id)
{
return 'security.authentication.failure_handler.'.$id.'.'.str_replace('-', '_', $this->getKey());
}
}

View File

@@ -0,0 +1,99 @@
<?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\DefinitionDecorator;
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>
*/
class FormLoginFactory extends AbstractFactory
{
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('post_only', true);
}
public function getPosition()
{
return 'form';
}
public function getKey()
{
return 'form-login';
}
public function addConfiguration(NodeDefinition $node)
{
parent::addConfiguration($node);
$node
->children()
->scalarNode('csrf_token_generator')->cannotBeEmpty()->end()
->end()
;
}
protected function getListenerId()
{
return 'security.authentication.listener.form';
}
protected function createAuthProvider(ContainerBuilder $container, $id, $config, $userProviderId)
{
$provider = 'security.authentication.provider.dao.'.$id;
$container
->setDefinition($provider, new DefinitionDecorator('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($container, $id, $config, $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($container, $id, $config, $defaultEntryPoint)
{
$entryPointId = 'security.authentication.form_entry_point.'.$id;
$container
->setDefinition($entryPointId, new DefinitionDecorator('security.authentication.form_entry_point'))
->addArgument(new Reference('security.http_utils'))
->addArgument($config['login_path'])
->addArgument($config['use_forward'])
;
return $entryPointId;
}
}

View File

@@ -0,0 +1,58 @@
<?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\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* FormLoginLdapFactory creates services for form login ldap authentication.
*
* @author Grégoire Pineau <lyrixx@lyrixx.info>
* @author Charles Sarrazin <charles@sarraz.in>
*/
class FormLoginLdapFactory extends FormLoginFactory
{
protected function createAuthProvider(ContainerBuilder $container, $id, $config, $userProviderId)
{
$provider = 'security.authentication.provider.ldap_bind.'.$id;
$container
->setDefinition($provider, new DefinitionDecorator('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'])
;
return $provider;
}
public function addConfiguration(NodeDefinition $node)
{
parent::addConfiguration($node);
$node
->children()
->scalarNode('service')->defaultValue('ldap')->end()
->scalarNode('dn_string')->defaultValue('{username}')->end()
->end()
;
}
public function getKey()
{
return 'form-login-ldap';
}
}

View File

@@ -0,0 +1,123 @@
<?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;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Reference;
/**
* Configures the "guard" authentication provider key under a firewall.
*
* @author Ryan Weaver <ryan@knpuniversity.com>
*/
class GuardAuthenticationFactory implements SecurityFactoryInterface
{
public function getPosition()
{
return 'pre_auth';
}
public function getKey()
{
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, $id, $config, $userProvider, $defaultEntryPoint)
{
$authenticatorIds = $config['authenticators'];
$authenticatorReferences = array();
foreach ($authenticatorIds as $authenticatorId) {
$authenticatorReferences[] = new Reference($authenticatorId);
}
// configure the GuardAuthenticationFactory to have the dynamic constructor arguments
$providerId = 'security.authentication.provider.guard.'.$id;
$container
->setDefinition($providerId, new DefinitionDecorator('security.authentication.provider.guard'))
->replaceArgument(0, $authenticatorReferences)
->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 DefinitionDecorator('security.authentication.listener.guard'));
$listener->replaceArgument(2, $id);
$listener->replaceArgument(3, $authenticatorReferences);
// 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', array('id' => $id, 'provider' => $userProvider));
return array($providerId, $listenerId, $entryPointId);
}
private function determineEntryPoint($defaultEntryPointId, array $config)
{
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 (count($authenticatorIds) == 1) {
// 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 configurators, you need to set the "guard.entry_point" key to one of you configurators (%s)',
implode(', ', $authenticatorIds)
));
}
}

View File

@@ -0,0 +1,82 @@
<?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\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* HttpBasicFactory creates services for HTTP basic authentication.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class HttpBasicFactory implements SecurityFactoryInterface
{
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
{
$provider = 'security.authentication.provider.dao.'.$id;
$container
->setDefinition($provider, new DefinitionDecorator('security.authentication.provider.dao'))
->replaceArgument(0, new Reference($userProvider))
->replaceArgument(1, new Reference('security.user_checker.'.$id))
->replaceArgument(2, $id)
;
// entry point
$entryPointId = $this->createEntryPoint($container, $id, $config, $defaultEntryPoint);
// listener
$listenerId = 'security.authentication.listener.basic.'.$id;
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.basic'));
$listener->replaceArgument(2, $id);
$listener->replaceArgument(3, new Reference($entryPointId));
return array($provider, $listenerId, $entryPointId);
}
public function getPosition()
{
return 'http';
}
public function getKey()
{
return 'http-basic';
}
public function addConfiguration(NodeDefinition $node)
{
$node
->children()
->scalarNode('provider')->end()
->scalarNode('realm')->defaultValue('Secured Area')->end()
->end()
;
}
protected function createEntryPoint($container, $id, $config, $defaultEntryPoint)
{
if (null !== $defaultEntryPoint) {
return $defaultEntryPoint;
}
$entryPointId = 'security.authentication.basic_entry_point.'.$id;
$container
->setDefinition($entryPointId, new DefinitionDecorator('security.authentication.basic_entry_point'))
->addArgument($config['realm'])
;
return $entryPointId;
}
}

View File

@@ -0,0 +1,68 @@
<?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\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* 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>
*/
class HttpBasicLdapFactory extends HttpBasicFactory
{
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
{
$provider = 'security.authentication.provider.ldap_bind.'.$id;
$container
->setDefinition($provider, new DefinitionDecorator('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'])
;
// entry point
$entryPointId = $this->createEntryPoint($container, $id, $config, $defaultEntryPoint);
// listener
$listenerId = 'security.authentication.listener.basic.'.$id;
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.basic'));
$listener->replaceArgument(2, $id);
$listener->replaceArgument(3, new Reference($entryPointId));
return array($provider, $listenerId, $entryPointId);
}
public function addConfiguration(NodeDefinition $node)
{
parent::addConfiguration($node);
$node
->children()
->scalarNode('service')->defaultValue('ldap')->end()
->scalarNode('dn_string')->defaultValue('{username}')->end()
->end()
;
}
public function getKey()
{
return 'http-basic-ldap';
}
}

View File

@@ -0,0 +1,85 @@
<?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\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* HttpDigestFactory creates services for HTTP digest authentication.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class HttpDigestFactory implements SecurityFactoryInterface
{
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
{
$provider = 'security.authentication.provider.dao.'.$id;
$container
->setDefinition($provider, new DefinitionDecorator('security.authentication.provider.dao'))
->replaceArgument(0, new Reference($userProvider))
->replaceArgument(1, new Reference('security.user_checker.'.$id))
->replaceArgument(2, $id)
;
// entry point
$entryPointId = $this->createEntryPoint($container, $id, $config, $defaultEntryPoint);
// listener
$listenerId = 'security.authentication.listener.digest.'.$id;
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.digest'));
$listener->replaceArgument(1, new Reference($userProvider));
$listener->replaceArgument(2, $id);
$listener->replaceArgument(3, new Reference($entryPointId));
return array($provider, $listenerId, $entryPointId);
}
public function getPosition()
{
return 'http';
}
public function getKey()
{
return 'http-digest';
}
public function addConfiguration(NodeDefinition $node)
{
$node
->children()
->scalarNode('provider')->end()
->scalarNode('realm')->defaultValue('Secured Area')->end()
->scalarNode('secret')->isRequired()->cannotBeEmpty()->end()
->end()
;
}
protected function createEntryPoint($container, $id, $config, $defaultEntryPoint)
{
if (null !== $defaultEntryPoint) {
return $defaultEntryPoint;
}
$entryPointId = 'security.authentication.digest_entry_point.'.$id;
$container
->setDefinition($entryPointId, new DefinitionDecorator('security.authentication.digest_entry_point'))
->addArgument($config['realm'])
->addArgument($config['secret'])
;
return $entryPointId;
}
}

View File

@@ -0,0 +1,149 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class RememberMeFactory implements SecurityFactoryInterface
{
protected $options = array(
'name' => 'REMEMBERME',
'lifetime' => 31536000,
'path' => '/',
'domain' => null,
'secure' => false,
'httponly' => true,
'always_remember_me' => false,
'remember_me_parameter' => '_remember_me',
);
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
{
// authentication provider
$authProviderId = 'security.authentication.provider.rememberme.'.$id;
$container
->setDefinition($authProviderId, new DefinitionDecorator('security.authentication.provider.rememberme'))
->replaceArgument(0, new Reference('security.user_checker.'.$id))
->addArgument($config['secret'])
->addArgument($id)
;
// remember me services
if (isset($config['token_provider'])) {
$templateId = 'security.authentication.rememberme.services.persistent';
$rememberMeServicesId = $templateId.'.'.$id;
} else {
$templateId = 'security.authentication.rememberme.services.simplehash';
$rememberMeServicesId = $templateId.'.'.$id;
}
if ($container->hasDefinition('security.logout_listener.'.$id)) {
$container
->getDefinition('security.logout_listener.'.$id)
->addMethodCall('addHandler', array(new Reference($rememberMeServicesId)))
;
}
$rememberMeServices = $container->setDefinition($rememberMeServicesId, new DefinitionDecorator($templateId));
$rememberMeServices->replaceArgument(1, $config['secret']);
$rememberMeServices->replaceArgument(2, $id);
if (isset($config['token_provider'])) {
$rememberMeServices->addMethodCall('setTokenProvider', array(
new Reference($config['token_provider']),
));
}
// remember-me options
$rememberMeServices->replaceArgument(3, array_intersect_key($config, $this->options));
// attach to remember-me aware listeners
$userProviders = array();
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.');
}
$userProviders[] = new Reference($attribute['provider']);
$container
->getDefinition($serviceId)
->addMethodCall('setRememberMeServices', array(new Reference($rememberMeServicesId)))
;
}
}
if ($config['user_providers']) {
$userProviders = array();
foreach ($config['user_providers'] as $providerName) {
$userProviders[] = new Reference('security.user.provider.concrete.'.$providerName);
}
}
if (count($userProviders) === 0) {
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, array_unique($userProviders));
// remember-me listener
$listenerId = 'security.authentication.listener.rememberme.'.$id;
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.rememberme'));
$listener->replaceArgument(1, new Reference($rememberMeServicesId));
$listener->replaceArgument(5, $config['catch_exceptions']);
return array($authProviderId, $listenerId, $defaultEntryPoint);
}
public function getPosition()
{
return 'remember_me';
}
public function getKey()
{
return 'remember-me';
}
public function addConfiguration(NodeDefinition $node)
{
$builder = $node
->fixXmlConfig('user_provider')
->children()
;
$builder
->scalarNode('secret')->isRequired()->cannotBeEmpty()->end()
->scalarNode('token_provider')->end()
->arrayNode('user_providers')
->beforeNormalization()
->ifString()->then(function ($v) { return array($v); })
->end()
->prototype('scalar')->end()
->end()
->scalarNode('catch_exceptions')->defaultTrue()->end()
;
foreach ($this->options as $name => $value) {
if (is_bool($value)) {
$builder->booleanNode($name)->defaultValue($value);
} else {
$builder->scalarNode($name)->defaultValue($value);
}
}
}
}

View 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\Security\Factory;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
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>
*/
class RemoteUserFactory implements SecurityFactoryInterface
{
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
{
$providerId = 'security.authentication.provider.pre_authenticated.'.$id;
$container
->setDefinition($providerId, new DefinitionDecorator('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 DefinitionDecorator('security.authentication.listener.remote_user'));
$listener->replaceArgument(2, $id);
$listener->replaceArgument(3, $config['user']);
return array($providerId, $listenerId, $defaultEntryPoint);
}
public function getPosition()
{
return 'pre_auth';
}
public function getKey()
{
return 'remote-user';
}
public function addConfiguration(NodeDefinition $node)
{
$node
->children()
->scalarNode('provider')->end()
->scalarNode('user')->defaultValue('REMOTE_USER')->end()
->end()
;
}
}

View File

@@ -0,0 +1,57 @@
<?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>
*/
interface SecurityFactoryInterface
{
/**
* Configures the container services required to use the authentication listener.
*
* @param ContainerBuilder $container
* @param string $id The unique id of the firewall
* @param array $config The options array for the listener
* @param string $userProvider The service id of the user provider
* @param string $defaultEntryPoint
*
* @return array containing three values:
* - the provider id
* - the listener id
* - the entry point id
*/
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint);
/**
* 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);
}

View 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\Security\Factory;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class SimpleFormFactory extends FormLoginFactory
{
public function __construct()
{
parent::__construct();
$this->addOption('authenticator', null);
}
public function getKey()
{
return 'simple-form';
}
public function addConfiguration(NodeDefinition $node)
{
parent::addConfiguration($node);
$node->children()
->scalarNode('authenticator')->cannotBeEmpty()->end()
->end();
}
protected function getListenerId()
{
return 'security.authentication.listener.simple_form';
}
protected function createAuthProvider(ContainerBuilder $container, $id, $config, $userProviderId)
{
$provider = 'security.authentication.provider.simple_form.'.$id;
$container
->setDefinition($provider, new DefinitionDecorator('security.authentication.provider.simple'))
->replaceArgument(0, new Reference($config['authenticator']))
->replaceArgument(1, new Reference($userProviderId))
->replaceArgument(2, $id)
;
return $provider;
}
protected function createListener($container, $id, $config, $userProvider)
{
$listenerId = parent::createListener($container, $id, $config, $userProvider);
$simpleAuthHandlerId = 'security.authentication.simple_success_failure_handler.'.$id;
$simpleAuthHandler = $container->setDefinition($simpleAuthHandlerId, new DefinitionDecorator('security.authentication.simple_success_failure_handler'));
$simpleAuthHandler->replaceArgument(0, new Reference($config['authenticator']));
$simpleAuthHandler->replaceArgument(1, new Reference($this->getSuccessHandlerId($id)));
$simpleAuthHandler->replaceArgument(2, new Reference($this->getFailureHandlerId($id)));
$listener = $container->getDefinition($listenerId);
$listener->replaceArgument(5, new Reference($simpleAuthHandlerId));
$listener->replaceArgument(6, new Reference($simpleAuthHandlerId));
$listener->addArgument(new Reference($config['authenticator']));
return $listenerId;
}
}

View File

@@ -0,0 +1,62 @@
<?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\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class SimplePreAuthenticationFactory implements SecurityFactoryInterface
{
public function getPosition()
{
return 'pre_auth';
}
public function getKey()
{
return 'simple-preauth';
}
public function addConfiguration(NodeDefinition $node)
{
$node
->children()
->scalarNode('provider')->end()
->scalarNode('authenticator')->cannotBeEmpty()->end()
->end()
;
}
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
{
$provider = 'security.authentication.provider.simple_preauth.'.$id;
$container
->setDefinition($provider, new DefinitionDecorator('security.authentication.provider.simple'))
->replaceArgument(0, new Reference($config['authenticator']))
->replaceArgument(1, new Reference($userProvider))
->replaceArgument(2, $id)
;
// listener
$listenerId = 'security.authentication.listener.simple_preauth.'.$id;
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.simple_preauth'));
$listener->replaceArgument(2, $id);
$listener->replaceArgument(3, new Reference($config['authenticator']));
return array($provider, $listenerId, null);
}
}

View File

@@ -0,0 +1,66 @@
<?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\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* X509Factory creates services for X509 certificate authentication.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class X509Factory implements SecurityFactoryInterface
{
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
{
$providerId = 'security.authentication.provider.pre_authenticated.'.$id;
$container
->setDefinition($providerId, new DefinitionDecorator('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 DefinitionDecorator('security.authentication.listener.x509'));
$listener->replaceArgument(2, $id);
$listener->replaceArgument(3, $config['user']);
$listener->replaceArgument(4, $config['credentials']);
return array($providerId, $listenerId, $defaultEntryPoint);
}
public function getPosition()
{
return 'pre_auth';
}
public function getKey()
{
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()
;
}
}

View File

@@ -0,0 +1,68 @@
<?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\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* 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, $id, $config)
{
$definition = $container->setDefinition($id, new DefinitionDecorator('security.user.provider.in_memory'));
foreach ($config['users'] as $username => $user) {
$userId = $id.'_'.$username;
$container
->setDefinition($userId, new DefinitionDecorator('security.user.provider.in_memory.user'))
->setArguments(array($username, (string) $user['password'], $user['roles']))
;
$definition->addMethodCall('createUser', array(new Reference($userId)));
}
}
public function getKey()
{
return 'memory';
}
public function addConfiguration(NodeDefinition $node)
{
$node
->fixXmlConfig('user')
->children()
->arrayNode('users')
->useAttributeAsKey('name')
->prototype('array')
->children()
->scalarNode('password')->defaultValue(uniqid('', true))->end()
->arrayNode('roles')
->beforeNormalization()->ifString()->then(function ($v) { return preg_split('/\s*,\s*/', $v); })->end()
->prototype('scalar')->end()
->end()
->end()
->end()
->end()
->end()
;
}
}

View File

@@ -0,0 +1,66 @@
<?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\DefinitionDecorator;
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, $id, $config)
{
$container
->setDefinition($id, new DefinitionDecorator('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'])
;
}
public function getKey()
{
return 'ldap';
}
public function addConfiguration(NodeDefinition $node)
{
$node
->children()
->scalarNode('service')->isRequired()->cannotBeEmpty()->defaultValue('ldap')->end()
->scalarNode('base_dn')->isRequired()->cannotBeEmpty()->end()
->scalarNode('search_dn')->end()
->scalarNode('search_password')->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()
;
}
}

View File

@@ -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, $id, $config);
public function getKey();
public function addConfiguration(NodeDefinition $builder);
}

View File

@@ -0,0 +1,718 @@
<?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\SecurityFactoryInterface;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\UserProviderFactoryInterface;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Security\Core\Authorization\ExpressionLanguage;
/**
* SecurityExtension.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class SecurityExtension extends Extension
{
private $requestMatchers = array();
private $expressions = array();
private $contextListeners = array();
private $listenerPositions = array('pre_auth', 'form', 'http', 'remember_me');
private $factories = array();
private $userProviderFactories = array();
private $expressionLanguage;
public function __construct()
{
foreach ($this->listenerPositions as $position) {
$this->factories[$position] = array();
}
}
public function load(array $configs, ContainerBuilder $container)
{
if (!array_filter($configs)) {
return;
}
$mainConfig = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($mainConfig, $configs);
// load services
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('security.xml');
$loader->load('security_listeners.xml');
$loader->load('security_rememberme.xml');
$loader->load('templating_php.xml');
$loader->load('templating_twig.xml');
$loader->load('collectors.xml');
$loader->load('guard.xml');
if ($container->hasParameter('kernel.debug') && $container->getParameter('kernel.debug')) {
$loader->load('security_debug.xml');
}
if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
$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']);
$container
->getDefinition('security.access.decision_manager')
->addArgument($config['access_decision_manager']['strategy'])
->addArgument($config['access_decision_manager']['allow_if_all_abstain'])
->addArgument($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']);
$this->createFirewalls($config, $container);
$this->createAuthorization($config, $container);
$this->createRoleHierarchy($config, $container);
if ($config['encoders']) {
$this->createEncoders($config['encoders'], $container);
}
// load ACL
if (isset($config['acl'])) {
$this->aclLoad($config['acl'], $container);
}
// add some required classes for compilation
$this->addClassesToCompile(array(
'Symfony\Component\Security\Http\Firewall',
'Symfony\Component\Security\Core\User\UserProviderInterface',
'Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager',
'Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage',
'Symfony\Component\Security\Core\Authorization\AccessDecisionManager',
'Symfony\Component\Security\Core\Authorization\AuthorizationChecker',
'Symfony\Component\Security\Core\Authorization\Voter\VoterInterface',
'Symfony\Bundle\SecurityBundle\Security\FirewallConfig',
'Symfony\Bundle\SecurityBundle\Security\FirewallMap',
'Symfony\Bundle\SecurityBundle\Security\FirewallContext',
'Symfony\Component\HttpFoundation\RequestMatcher',
));
}
private function aclLoad($config, ContainerBuilder $container)
{
if (!interface_exists('Symfony\Component\Security\Acl\Model\AclInterface')) {
throw new \LogicException('You must install symfony/security-acl in order to use the ACL functionality.');
}
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('security_acl.xml');
if (isset($config['cache']['id'])) {
$container->setAlias('security.acl.cache', $config['cache']['id']);
}
$container->getDefinition('security.acl.voter.basic_permissions')->addArgument($config['voter']['allow_if_object_identity_unavailable']);
// custom ACL provider
if (isset($config['provider'])) {
$container->setAlias('security.acl.provider', $config['provider']);
return;
}
$this->configureDbalAclProvider($config, $container, $loader);
}
private function configureDbalAclProvider(array $config, ContainerBuilder $container, $loader)
{
$loader->load('security_acl_dbal.xml');
if (null !== $config['connection']) {
$container->setAlias('security.acl.dbal.connection', sprintf('doctrine.dbal.%s_connection', $config['connection']));
}
$container
->getDefinition('security.acl.dbal.schema_listener')
->addTag('doctrine.event_listener', array(
'connection' => $config['connection'],
'event' => 'postGenerateSchema',
'lazy' => true,
))
;
$container->getDefinition('security.acl.cache.doctrine')->addArgument($config['cache']['prefix']);
$container->setParameter('security.acl.dbal.class_table_name', $config['tables']['class']);
$container->setParameter('security.acl.dbal.entry_table_name', $config['tables']['entry']);
$container->setParameter('security.acl.dbal.oid_table_name', $config['tables']['object_identity']);
$container->setParameter('security.acl.dbal.oid_ancestors_table_name', $config['tables']['object_identity_ancestors']);
$container->setParameter('security.acl.dbal.sid_table_name', $config['tables']['security_identity']);
}
/**
* Loads the web configuration.
*
* @param array $config An array of configuration settings
* @param ContainerBuilder $container A ContainerBuilder instance
*/
private function createRoleHierarchy($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($config, ContainerBuilder $container)
{
if (!$config['access_control']) {
return;
}
$this->addClassesToCompile(array(
'Symfony\\Component\\Security\\Http\\AccessMap',
));
foreach ($config['access_control'] as $access) {
$matcher = $this->createRequestMatcher(
$container,
$access['path'],
$access['host'],
$access['methods'],
$access['ips']
);
$attributes = $access['roles'];
if ($access['allow_if']) {
$attributes[] = $this->createExpression($container, $access['allow_if']);
}
$container->getDefinition('security.access_map')
->addMethodCall('add', array($matcher, $attributes, $access['requires_channel']));
}
}
private function createFirewalls($config, ContainerBuilder $container)
{
if (!isset($config['firewalls'])) {
return;
}
$firewalls = $config['firewalls'];
$providerIds = $this->createUserProviders($config, $container);
// make the ContextListener aware of the configured user providers
$definition = $container->getDefinition('security.context_listener');
$arguments = $definition->getArguments();
$userProviders = array();
foreach ($providerIds as $userProviderId) {
$userProviders[] = new Reference($userProviderId);
}
$arguments[1] = $userProviders;
$definition->setArguments($arguments);
// load firewall map
$mapDef = $container->getDefinition('security.firewall.map');
$map = $authenticationProviders = array();
foreach ($firewalls as $name => $firewall) {
$configId = 'security.firewall.map.config.'.$name;
list($matcher, $listeners, $exceptionListener) = $this->createFirewall($container, $name, $firewall, $authenticationProviders, $providerIds, $configId);
$contextId = 'security.firewall.map.context.'.$name;
$context = $container->setDefinition($contextId, new DefinitionDecorator('security.firewall.context'));
$context
->replaceArgument(0, $listeners)
->replaceArgument(1, $exceptionListener)
->replaceArgument(2, new Reference($configId))
;
$map[$contextId] = $matcher;
}
$mapDef->replaceArgument(1, $map);
// 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, $authenticationProviders)
;
}
private function createFirewall(ContainerBuilder $container, $id, $firewall, &$authenticationProviders, $providerIds, $configId)
{
$config = $container->setDefinition($configId, new DefinitionDecorator('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 = isset($firewall['pattern']) ? $firewall['pattern'] : null;
$host = isset($firewall['host']) ? $firewall['host'] : null;
$methods = isset($firewall['methods']) ? $firewall['methods'] : array();
$matcher = $this->createRequestMatcher($container, $pattern, $host, $methods);
}
$config->replaceArgument(2, $matcher ? (string) $matcher : null);
$config->replaceArgument(3, $firewall['security']);
// Security disabled?
if (false === $firewall['security']) {
return array($matcher, array(), null);
}
$config->replaceArgument(4, $firewall['stateless']);
// Provider id (take the first registered provider if none defined)
if (isset($firewall['provider'])) {
$defaultProvider = $this->getUserProviderId($firewall['provider']);
} else {
$defaultProvider = reset($providerIds);
}
$config->replaceArgument(5, $defaultProvider);
// Register listeners
$listeners = array();
$listenerKeys = array();
// Channel listener
$listeners[] = new Reference('security.channel_listener');
$contextKey = null;
// Context serializer listener
if (false === $firewall['stateless']) {
$contextKey = $id;
if (isset($firewall['context'])) {
$contextKey = $firewall['context'];
}
$listeners[] = new Reference($this->createContextListener($container, $contextKey));
}
$config->replaceArgument(6, $contextKey);
// Logout listener
if (isset($firewall['logout'])) {
$listenerKeys[] = 'logout';
$listenerId = 'security.logout_listener.'.$id;
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.logout_listener'));
$listener->replaceArgument(3, array(
'csrf_parameter' => $firewall['logout']['csrf_parameter'],
'csrf_token_id' => $firewall['logout']['csrf_token_id'],
'logout_path' => $firewall['logout']['path'],
));
$listeners[] = new Reference($listenerId);
// add logout success handler
if (isset($firewall['logout']['success_handler'])) {
$logoutSuccessHandlerId = $firewall['logout']['success_handler'];
} else {
$logoutSuccessHandlerId = 'security.logout.success_handler.'.$id;
$logoutSuccessHandler = $container->setDefinition($logoutSuccessHandlerId, new DefinitionDecorator('security.logout.success_handler'));
$logoutSuccessHandler->replaceArgument(1, $firewall['logout']['target']);
}
$listener->replaceArgument(2, new Reference($logoutSuccessHandlerId));
// add CSRF provider
if (isset($firewall['logout']['csrf_token_generator'])) {
$listener->addArgument(new Reference($firewall['logout']['csrf_token_generator']));
}
// add session logout handler
if (true === $firewall['logout']['invalidate_session'] && false === $firewall['stateless']) {
$listener->addMethodCall('addHandler', array(new Reference('security.logout.handler.session')));
}
// add cookie logout handler
if (count($firewall['logout']['delete_cookies']) > 0) {
$cookieHandlerId = 'security.logout.handler.cookie_clearing.'.$id;
$cookieHandler = $container->setDefinition($cookieHandlerId, new DefinitionDecorator('security.logout.handler.cookie_clearing'));
$cookieHandler->addArgument($firewall['logout']['delete_cookies']);
$listener->addMethodCall('addHandler', array(new Reference($cookieHandlerId)));
}
// add custom handlers
foreach ($firewall['logout']['handlers'] as $handlerId) {
$listener->addMethodCall('addHandler', array(new Reference($handlerId)));
}
// register with LogoutUrlGenerator
$container
->getDefinition('security.logout_url_generator')
->addMethodCall('registerListener', array(
$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,
))
;
}
// Determine default entry point
$configuredEntryPoint = isset($firewall['entry_point']) ? $firewall['entry_point'] : null;
// Authentication listeners
list($authListeners, $defaultEntryPoint) = $this->createAuthenticationListeners($container, $id, $firewall, $authenticationProviders, $defaultProvider, $configuredEntryPoint);
$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));
}
// 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, isset($firewall['access_denied_handler']) ? $firewall['access_denied_handler'] : null);
$config->replaceArgument(9, isset($firewall['access_denied_url']) ? $firewall['access_denied_url'] : null);
$container->setAlias('security.user_checker.'.$id, new Alias($firewall['user_checker'], false));
foreach ($this->factories as $position) {
foreach ($position as $factory) {
$key = str_replace('-', '_', $factory->getKey());
if (array_key_exists($key, $firewall)) {
$listenerKeys[] = $key;
}
}
}
if (isset($firewall['anonymous'])) {
$listenerKeys[] = 'anonymous';
}
$config->replaceArgument(10, $listenerKeys);
return array($matcher, $listeners, $exceptionListener);
}
private function createContextListener($container, $contextKey)
{
if (isset($this->contextListeners[$contextKey])) {
return $this->contextListeners[$contextKey];
}
$listenerId = 'security.context_listener.'.count($this->contextListeners);
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.context_listener'));
$listener->replaceArgument(2, $contextKey);
return $this->contextListeners[$contextKey] = $listenerId;
}
private function createAuthenticationListeners($container, $id, $firewall, &$authenticationProviders, $defaultProvider, $defaultEntryPoint)
{
$listeners = array();
$hasListeners = false;
foreach ($this->listenerPositions as $position) {
foreach ($this->factories[$position] as $factory) {
$key = str_replace('-', '_', $factory->getKey());
if (isset($firewall[$key])) {
$userProvider = isset($firewall[$key]['provider']) ? $this->getUserProviderId($firewall[$key]['provider']) : $defaultProvider;
list($provider, $listenerId, $defaultEntryPoint) = $factory->create($container, $id, $firewall[$key], $userProvider, $defaultEntryPoint);
$listeners[] = new Reference($listenerId);
$authenticationProviders[] = $provider;
$hasListeners = true;
}
}
}
// Anonymous
if (isset($firewall['anonymous'])) {
$listenerId = 'security.authentication.listener.anonymous.'.$id;
$container
->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.anonymous'))
->replaceArgument(1, $firewall['anonymous']['secret'])
;
$listeners[] = new Reference($listenerId);
$providerId = 'security.authentication.provider.anonymous.'.$id;
$container
->setDefinition($providerId, new DefinitionDecorator('security.authentication.provider.anonymous'))
->replaceArgument(0, $firewall['anonymous']['secret'])
;
$authenticationProviders[] = $providerId;
$hasListeners = true;
}
if (false === $hasListeners) {
throw new InvalidConfigurationException(sprintf('No authentication listener registered for firewall "%s".', $id));
}
return array($listeners, $defaultEntryPoint);
}
private function createEncoders($encoders, ContainerBuilder $container)
{
$encoderMap = array();
foreach ($encoders as $class => $encoder) {
$encoderMap[$class] = $this->createEncoder($encoder, $container);
}
$container
->getDefinition('security.encoder_factory.generic')
->setArguments(array($encoderMap))
;
}
private function createEncoder($config, ContainerBuilder $container)
{
// a custom encoder service
if (isset($config['id'])) {
return new Reference($config['id']);
}
// plaintext encoder
if ('plaintext' === $config['algorithm']) {
$arguments = array($config['ignore_case']);
return array(
'class' => 'Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder',
'arguments' => $arguments,
);
}
// pbkdf2 encoder
if ('pbkdf2' === $config['algorithm']) {
return array(
'class' => 'Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder',
'arguments' => array(
$config['hash_algorithm'],
$config['encode_as_base64'],
$config['iterations'],
$config['key_length'],
),
);
}
// bcrypt encoder
if ('bcrypt' === $config['algorithm']) {
return array(
'class' => 'Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder',
'arguments' => array($config['cost']),
);
}
// run-time configured encoder
return $config;
}
// Parses user providers and returns an array of their ids
private function createUserProviders($config, ContainerBuilder $container)
{
$providerIds = array();
foreach ($config['providers'] as $name => $provider) {
$id = $this->createUserDaoProvider($name, $provider, $container);
$providerIds[] = $id;
}
return $providerIds;
}
// Parses a <provider> tag and returns the id for the related user provider service
private function createUserDaoProvider($name, $provider, ContainerBuilder $container)
{
$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 = array();
foreach ($provider['chain']['providers'] as $providerName) {
$providers[] = new Reference($this->getUserProviderId($providerName));
}
$container
->setDefinition($name, new DefinitionDecorator('security.user.provider.chain'))
->addArgument($providers);
return $name;
}
throw new InvalidConfigurationException(sprintf('Unable to create definition for "%s" user provider', $name));
}
private function getUserProviderId($name)
{
return 'security.user.provider.concrete.'.strtolower($name);
}
private function createExceptionListener($container, $config, $id, $defaultEntryPoint, $stateless)
{
$exceptionListenerId = 'security.exception_listener.'.$id;
$listener = $container->setDefinition($exceptionListenerId, new DefinitionDecorator('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($container, $id, $config, $defaultProvider)
{
$userProvider = isset($config['provider']) ? $this->getUserProviderId($config['provider']) : $defaultProvider;
$switchUserListenerId = 'security.authentication.switchuser_listener.'.$id;
$listener = $container->setDefinition($switchUserListenerId, new DefinitionDecorator('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']);
return $switchUserListenerId;
}
private function createExpression($container, $expression)
{
if (isset($this->expressions[$id = 'security.expression.'.sha1($expression)])) {
return $this->expressions[$id];
}
$container
->register($id, 'Symfony\Component\ExpressionLanguage\SerializedParsedExpression')
->setPublic(false)
->addArgument($expression)
->addArgument(serialize($this->getExpressionLanguage()->parse($expression, array('token', 'user', 'object', 'roles', 'request', 'trust_resolver'))->getNodes()))
;
return $this->expressions[$id] = new Reference($id);
}
private function createRequestMatcher($container, $path = null, $host = null, $methods = array(), $ip = null, array $attributes = array())
{
if ($methods) {
$methods = array_map('strtoupper', (array) $methods);
}
$serialized = serialize(array($path, $host, $methods, $ip, $attributes));
$id = 'security.request_matcher.'.md5($serialized).sha1($serialized);
if (isset($this->requestMatchers[$id])) {
return $this->requestMatchers[$id];
}
// only add arguments that are necessary
$arguments = array($path, $host, $methods, $ip, $attributes);
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);
}
public function addSecurityListenerFactory(SecurityFactoryInterface $factory)
{
$this->factories[$factory->getPosition()][] = $factory;
}
public function addUserProviderFactory(UserProviderFactoryInterface $factory)
{
$this->userProviderFactories[] = $factory;
}
/**
* Returns the base path for the XSD files.
*
* @return string The XSD base path
*/
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->factories, $this->userProviderFactories);
}
private function getExpressionLanguage()
{
if (null === $this->expressionLanguage) {
if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
throw new \RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
}
$this->expressionLanguage = new ExpressionLanguage();
}
return $this->expressionLanguage;
}
}