719 lines
28 KiB
PHP
719 lines
28 KiB
PHP
<?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;
|
|
}
|
|
}
|