vendor/symfony/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * This file is part of the Symfony framework.
       
     5  *
       
     6  * (c) Fabien Potencier <fabien@symfony.com>
       
     7  *
       
     8  * This source file is subject to the MIT license that is bundled
       
     9  * with this source code in the file LICENSE.
       
    10  */
       
    11 
       
    12 namespace Symfony\Bundle\SecurityBundle\DependencyInjection;
       
    13 
       
    14 use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AbstractFactory;
       
    15 
       
    16 use Symfony\Component\Config\Definition\Builder\TreeBuilder;
       
    17 use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
       
    18 use Symfony\Component\Config\Definition\ConfigurationInterface;
       
    19 
       
    20 /**
       
    21  * This class contains the configuration information for the following tags:
       
    22  *
       
    23  *   * security.config
       
    24  *   * security.acl
       
    25  *
       
    26  * This information is solely responsible for how the different configuration
       
    27  * sections are normalized, and merged.
       
    28  *
       
    29  * @author Johannes M. Schmitt <schmittjoh@gmail.com>
       
    30  */
       
    31 class MainConfiguration implements ConfigurationInterface
       
    32 {
       
    33     private $factories;
       
    34 
       
    35     /**
       
    36      * Constructor.
       
    37      *
       
    38      * @param array $factories
       
    39      */
       
    40     public function __construct(array $factories)
       
    41     {
       
    42         $this->factories = $factories;
       
    43     }
       
    44 
       
    45     /**
       
    46      * Generates the configuration tree builder.
       
    47      *
       
    48      * @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
       
    49      */
       
    50     public function getConfigTreeBuilder()
       
    51     {
       
    52         $tb = new TreeBuilder();
       
    53         $rootNode = $tb->root('security');
       
    54 
       
    55         $rootNode
       
    56             ->children()
       
    57                 ->scalarNode('access_denied_url')->defaultNull()->end()
       
    58                 ->scalarNode('session_fixation_strategy')->cannotBeEmpty()->defaultValue('migrate')->end()
       
    59                 ->booleanNode('hide_user_not_found')->defaultTrue()->end()
       
    60                 ->booleanNode('always_authenticate_before_granting')->defaultFalse()->end()
       
    61                 ->arrayNode('access_decision_manager')
       
    62                     ->addDefaultsIfNotSet()
       
    63                     ->children()
       
    64                         ->scalarNode('strategy')->defaultValue('affirmative')->end()
       
    65                         ->booleanNode('allow_if_all_abstain')->defaultFalse()->end()
       
    66                         ->booleanNode('allow_if_equal_granted_denied')->defaultTrue()->end()
       
    67                     ->end()
       
    68                 ->end()
       
    69             ->end()
       
    70             // add a faux-entry for factories, so that no validation error is thrown
       
    71             ->fixXmlConfig('factory', 'factories')
       
    72             ->children()
       
    73                 ->arrayNode('factories')->ignoreExtraKeys()->end()
       
    74             ->end()
       
    75         ;
       
    76 
       
    77         $this->addAclSection($rootNode);
       
    78         $this->addEncodersSection($rootNode);
       
    79         $this->addProvidersSection($rootNode);
       
    80         $this->addFirewallsSection($rootNode, $this->factories);
       
    81         $this->addAccessControlSection($rootNode);
       
    82         $this->addRoleHierarchySection($rootNode);
       
    83 
       
    84         return $tb;
       
    85     }
       
    86 
       
    87     private function addAclSection(ArrayNodeDefinition $rootNode)
       
    88     {
       
    89         $rootNode
       
    90             ->children()
       
    91                 ->arrayNode('acl')
       
    92                     ->children()
       
    93                         ->scalarNode('connection')->end()
       
    94                         ->arrayNode('cache')
       
    95                             ->addDefaultsIfNotSet()
       
    96                             ->children()
       
    97                                 ->scalarNode('id')->end()
       
    98                                 ->scalarNode('prefix')->defaultValue('sf2_acl_')->end()
       
    99                             ->end()
       
   100                         ->end()
       
   101                         ->scalarNode('provider')->end()
       
   102                         ->arrayNode('tables')
       
   103                             ->addDefaultsIfNotSet()
       
   104                             ->children()
       
   105                                 ->scalarNode('class')->defaultValue('acl_classes')->end()
       
   106                                 ->scalarNode('entry')->defaultValue('acl_entries')->end()
       
   107                                 ->scalarNode('object_identity')->defaultValue('acl_object_identities')->end()
       
   108                                 ->scalarNode('object_identity_ancestors')->defaultValue('acl_object_identity_ancestors')->end()
       
   109                                 ->scalarNode('security_identity')->defaultValue('acl_security_identities')->end()
       
   110                             ->end()
       
   111                         ->end()
       
   112                         ->arrayNode('voter')
       
   113                             ->addDefaultsIfNotSet()
       
   114                             ->children()
       
   115                                 ->booleanNode('allow_if_object_identity_unavailable')->defaultTrue()->end()
       
   116                             ->end()
       
   117                         ->end()
       
   118                     ->end()
       
   119                 ->end()
       
   120             ->end()
       
   121         ;
       
   122     }
       
   123 
       
   124     private function addRoleHierarchySection(ArrayNodeDefinition $rootNode)
       
   125     {
       
   126         $rootNode
       
   127             ->fixXmlConfig('role', 'role_hierarchy')
       
   128             ->children()
       
   129                 ->arrayNode('role_hierarchy')
       
   130                     ->useAttributeAsKey('id')
       
   131                     ->prototype('array')
       
   132                         ->performNoDeepMerging()
       
   133                         ->beforeNormalization()->ifString()->then(function($v) { return array('value' => $v); })->end()
       
   134                         ->beforeNormalization()
       
   135                             ->ifTrue(function($v) { return is_array($v) && isset($v['value']); })
       
   136                             ->then(function($v) { return preg_split('/\s*,\s*/', $v['value']); })
       
   137                         ->end()
       
   138                         ->prototype('scalar')->end()
       
   139                     ->end()
       
   140                 ->end()
       
   141             ->end()
       
   142         ;
       
   143     }
       
   144 
       
   145     private function addAccessControlSection(ArrayNodeDefinition $rootNode)
       
   146     {
       
   147         $rootNode
       
   148             ->fixXmlConfig('rule', 'access_control')
       
   149             ->children()
       
   150                 ->arrayNode('access_control')
       
   151                     ->cannotBeOverwritten()
       
   152                     ->prototype('array')
       
   153                         ->children()
       
   154                             ->scalarNode('requires_channel')->defaultNull()->end()
       
   155                             ->scalarNode('path')->defaultNull()->end()
       
   156                             ->scalarNode('host')->defaultNull()->end()
       
   157                             ->scalarNode('ip')->defaultNull()->end()
       
   158                             ->arrayNode('methods')
       
   159                                 ->beforeNormalization()->ifString()->then(function($v) { return preg_split('/\s*,\s*/', $v); })->end()
       
   160                                 ->prototype('scalar')->end()
       
   161                             ->end()
       
   162                         ->end()
       
   163                         ->fixXmlConfig('role')
       
   164                         ->children()
       
   165                             ->arrayNode('roles')
       
   166                                 ->beforeNormalization()->ifString()->then(function($v) { return preg_split('/\s*,\s*/', $v); })->end()
       
   167                                 ->prototype('scalar')->end()
       
   168                             ->end()
       
   169                         ->end()
       
   170                     ->end()
       
   171                 ->end()
       
   172             ->end()
       
   173         ;
       
   174     }
       
   175 
       
   176     private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $factories)
       
   177     {
       
   178         $firewallNodeBuilder = $rootNode
       
   179             ->fixXmlConfig('firewall')
       
   180             ->children()
       
   181                 ->arrayNode('firewalls')
       
   182                     ->isRequired()
       
   183                     ->requiresAtLeastOneElement()
       
   184                     ->disallowNewKeysInSubsequentConfigs()
       
   185                     ->useAttributeAsKey('name')
       
   186                     ->prototype('array')
       
   187                         ->children()
       
   188         ;
       
   189 
       
   190         $firewallNodeBuilder
       
   191             ->scalarNode('pattern')->end()
       
   192             ->booleanNode('security')->defaultTrue()->end()
       
   193             ->scalarNode('request_matcher')->end()
       
   194             ->scalarNode('access_denied_url')->end()
       
   195             ->scalarNode('access_denied_handler')->end()
       
   196             ->scalarNode('entry_point')->end()
       
   197             ->scalarNode('provider')->end()
       
   198             ->booleanNode('stateless')->defaultFalse()->end()
       
   199             ->scalarNode('context')->cannotBeEmpty()->end()
       
   200             ->arrayNode('logout')
       
   201                 ->treatTrueLike(array())
       
   202                 ->canBeUnset()
       
   203                 ->children()
       
   204                     ->scalarNode('path')->defaultValue('/logout')->end()
       
   205                     ->scalarNode('target')->defaultValue('/')->end()
       
   206                     ->scalarNode('success_handler')->end()
       
   207                     ->booleanNode('invalidate_session')->defaultTrue()->end()
       
   208                 ->end()
       
   209                 ->fixXmlConfig('delete_cookie')
       
   210                 ->children()
       
   211                     ->arrayNode('delete_cookies')
       
   212                         ->beforeNormalization()
       
   213                             ->ifTrue(function($v) { return is_array($v) && is_int(key($v)); })
       
   214                             ->then(function($v) { return array_map(function($v) { return array('name' => $v); }, $v); })
       
   215                         ->end()
       
   216                         ->useAttributeAsKey('name')
       
   217                         ->prototype('array')
       
   218                             ->children()
       
   219                                 ->scalarNode('path')->defaultNull()->end()
       
   220                                 ->scalarNode('domain')->defaultNull()->end()
       
   221                             ->end()
       
   222                         ->end()
       
   223                     ->end()
       
   224                 ->end()
       
   225                 ->fixXmlConfig('handler')
       
   226                 ->children()
       
   227                     ->arrayNode('handlers')
       
   228                         ->prototype('scalar')->end()
       
   229                     ->end()
       
   230                 ->end()
       
   231             ->end()
       
   232             ->arrayNode('anonymous')
       
   233                 ->canBeUnset()
       
   234                 ->children()
       
   235                     ->scalarNode('key')->defaultValue(uniqid())->end()
       
   236                 ->end()
       
   237             ->end()
       
   238             ->arrayNode('switch_user')
       
   239                 ->canBeUnset()
       
   240                 ->children()
       
   241                     ->scalarNode('provider')->end()
       
   242                     ->scalarNode('parameter')->defaultValue('_switch_user')->end()
       
   243                     ->scalarNode('role')->defaultValue('ROLE_ALLOWED_TO_SWITCH')->end()
       
   244                 ->end()
       
   245             ->end()
       
   246         ;
       
   247 
       
   248         $abstractFactoryKeys = array();
       
   249         foreach ($factories as $factoriesAtPosition) {
       
   250             foreach ($factoriesAtPosition as $factory) {
       
   251                 $name = str_replace('-', '_', $factory->getKey());
       
   252                 $factoryNode = $firewallNodeBuilder->arrayNode($name)
       
   253                     ->canBeUnset()
       
   254                 ;
       
   255 
       
   256                 if ($factory instanceof AbstractFactory) {
       
   257                     $abstractFactoryKeys[] = $name;
       
   258                 }
       
   259 
       
   260                 $factory->addConfiguration($factoryNode);
       
   261             }
       
   262         }
       
   263 
       
   264         // check for unreachable check paths
       
   265         $firewallNodeBuilder
       
   266             ->end()
       
   267             ->validate()
       
   268                 ->ifTrue(function($v) {
       
   269                     return true === $v['security'] && isset($v['pattern']) && !isset($v['request_matcher']);
       
   270                 })
       
   271                 ->then(function($firewall) use($abstractFactoryKeys) {
       
   272                     foreach ($abstractFactoryKeys as $k) {
       
   273                         if (!isset($firewall[$k]['check_path'])) {
       
   274                             continue;
       
   275                         }
       
   276 
       
   277                         if (!preg_match('#'.$firewall['pattern'].'#', $firewall[$k]['check_path'])) {
       
   278                             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']));
       
   279                         }
       
   280                     }
       
   281 
       
   282                     return $firewall;
       
   283                 })
       
   284             ->end()
       
   285         ;
       
   286     }
       
   287 
       
   288     private function addProvidersSection(ArrayNodeDefinition $rootNode)
       
   289     {
       
   290         $rootNode
       
   291             ->fixXmlConfig('provider')
       
   292             ->children()
       
   293                 ->arrayNode('providers')
       
   294                     ->disallowNewKeysInSubsequentConfigs()
       
   295                     ->isRequired()
       
   296                     ->requiresAtLeastOneElement()
       
   297                     ->useAttributeAsKey('name')
       
   298                     ->prototype('array')
       
   299                         ->children()
       
   300                             ->scalarNode('id')->end()
       
   301                             ->arrayNode('entity')
       
   302                                 ->children()
       
   303                                     ->scalarNode('class')->isRequired()->cannotBeEmpty()->end()
       
   304                                     ->scalarNode('property')->defaultNull()->end()
       
   305                                 ->end()
       
   306                             ->end()
       
   307                         ->end()
       
   308                         ->fixXmlConfig('provider')
       
   309                         ->children()
       
   310                             ->arrayNode('providers')
       
   311                                 ->beforeNormalization()
       
   312                                     ->ifString()
       
   313                                     ->then(function($v) { return preg_split('/\s*,\s*/', $v); })
       
   314                                 ->end()
       
   315                                 ->prototype('scalar')->end()
       
   316                             ->end()
       
   317                         ->end()
       
   318                         ->fixXmlConfig('user')
       
   319                         ->children()
       
   320                             ->arrayNode('users')
       
   321                                 ->useAttributeAsKey('name')
       
   322                                 ->prototype('array')
       
   323                                     ->children()
       
   324                                         ->scalarNode('password')->defaultValue(uniqid())->end()
       
   325                                         ->arrayNode('roles')
       
   326                                             ->beforeNormalization()->ifString()->then(function($v) { return preg_split('/\s*,\s*/', $v); })->end()
       
   327                                             ->prototype('scalar')->end()
       
   328                                         ->end()
       
   329                                     ->end()
       
   330                                 ->end()
       
   331                             ->end()
       
   332                         ->end()
       
   333                     ->end()
       
   334                 ->end()
       
   335             ->end()
       
   336         ;
       
   337     }
       
   338 
       
   339     private function addEncodersSection(ArrayNodeDefinition $rootNode)
       
   340     {
       
   341         $rootNode
       
   342             ->fixXmlConfig('encoder')
       
   343             ->children()
       
   344                 ->arrayNode('encoders')
       
   345                     ->requiresAtLeastOneElement()
       
   346                     ->useAttributeAsKey('class')
       
   347                     ->prototype('array')
       
   348                         ->canBeUnset()
       
   349                         ->performNoDeepMerging()
       
   350                         ->beforeNormalization()->ifString()->then(function($v) { return array('algorithm' => $v); })->end()
       
   351                         ->children()
       
   352                             ->scalarNode('algorithm')->cannotBeEmpty()->end()
       
   353                             ->booleanNode('ignore_case')->defaultFalse()->end()
       
   354                             ->booleanNode('encode_as_base64')->defaultTrue()->end()
       
   355                             ->scalarNode('iterations')->defaultValue(5000)->end()
       
   356                             ->scalarNode('id')->end()
       
   357                         ->end()
       
   358                     ->end()
       
   359                 ->end()
       
   360             ->end()
       
   361         ;
       
   362     }
       
   363 }