Файл: symfony-2.7/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php
Строк: 613
<?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 SymfonyBundleSecurityBundleDependencyInjection;
use SymfonyBundleSecurityBundleDependencyInjectionSecurityFactoryAbstractFactory;
use SymfonyComponentSecurityCoreAuthorizationAccessDecisionManager;
use SymfonyComponentConfigDefinitionBuilderTreeBuilder;
use SymfonyComponentConfigDefinitionBuilderArrayNodeDefinition;
use SymfonyComponentConfigDefinitionConfigurationInterface;
/**
* 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()
->scalarNode('session_fixation_strategy')->cannotBeEmpty()->info('strategy can be: none, migrate, invalidate')->defaultValue('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()
->scalarNode('strategy')->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')
->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('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()
->beforeNormalization()
->ifTrue(function ($v) { return isset($v['csrf_provider']) && isset($v['csrf_token_generator']); })
->thenInvalid("You should define a value for only one of 'csrf_provider' and 'csrf_token_generator' on a security firewall. Use 'csrf_token_generator' as this replaces 'csrf_provider'.")
->end()
->beforeNormalization()
->ifTrue(function ($v) { return isset($v['intention']) && isset($v['csrf_token_id']); })
->thenInvalid("You should define a value for only one of 'intention' and 'csrf_token_id' on a security firewall. Use 'csrf_token_id' as this replaces 'intention'.")
->end()
->beforeNormalization()
->ifTrue(function ($v) { return isset($v['csrf_provider']); })
->then(function ($v) {
$v['csrf_token_generator'] = $v['csrf_provider'];
unset($v['csrf_provider']);
return $v;
})
->end()
->beforeNormalization()
->ifTrue(function ($v) { return isset($v['intention']); })
->then(function ($v) {
$v['csrf_token_id'] = $v['intention'];
unset($v['intention']);
return $v;
})
->end()
->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('key')->defaultValue(uniqid())->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')),
))
->disallowNewKeysInSubsequentConfigs()
->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(
'AcmeDemoBundleEntityUser1' => 'sha512',
'AcmeDemoBundleEntityUser2' => array(
'algorithm' => 'sha512',
'encode_as_base64' => 'true',
'iterations' => 5000,
),
))
->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()
;
}
}