Browse Source

Merge remote branch 'schmittjoh/security'

* schmittjoh/security:
  [SecurityBundle] fixed a regression
  [SecurityBundle] re-use local variable
  [SecurityBundle] added validation for check paths
  [SecurityBundle] added user_providers option for remember_me
  [Security/Core] added missing method to interface
Fabien Potencier 14 years ago
parent
commit
4b86b15105

+ 30 - 0
src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php

@@ -11,6 +11,8 @@
 
 namespace Symfony\Bundle\SecurityBundle\DependencyInjection;
 
+use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AbstractFactory;
+
 use Symfony\Component\Config\Definition\Builder\TreeBuilder;
 use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
 use Symfony\Component\Config\Definition\ConfigurationInterface;
@@ -242,6 +244,7 @@ class MainConfiguration implements ConfigurationInterface
             ->end()
         ;
 
+        $abstractFactoryKeys = array();
         foreach ($factories as $factoriesAtPosition) {
             foreach ($factoriesAtPosition as $factory) {
                 $name = str_replace('-', '_', $factory->getKey());
@@ -249,9 +252,36 @@ class MainConfiguration implements ConfigurationInterface
                     ->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 (!preg_match('#'.$firewall['pattern'].'#', $firewall[$k]['check_path'])) {
+                            throw new \Exception(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)

+ 13 - 2
src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php

@@ -12,9 +12,7 @@
 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\Parameter;
 use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -90,6 +88,12 @@ class RememberMeFactory implements SecurityFactoryInterface
                 ;
             }
         }
+        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.');
         }
@@ -115,11 +119,18 @@ class RememberMeFactory implements SecurityFactoryInterface
 
     public function addConfiguration(NodeDefinition $node)
     {
+        $node->fixXmlConfig('user_provider');
         $builder = $node->children();
 
         $builder
             ->scalarNode('key')->isRequired()->cannotBeEmpty()->end()
             ->scalarNode('token_provider')->end()
+            ->arrayNode('user_providers')
+                ->beforeNormalization()
+                    ->ifString()->then(function($v) { return array($v); })
+                ->end()
+                ->prototype('scalar')->end()
+            ->end()
         ;
 
         foreach ($this->options as $name => $value) {

+ 1 - 1
src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php

@@ -387,7 +387,7 @@ class SecurityExtension extends Extension
         }
 
         if (false === $hasListeners) {
-            throw new \LogicException(sprintf('No authentication listener registered for pattern "%s".', isset($firewall['pattern']) ? $firewall['pattern'] : ''));
+            throw new \LogicException(sprintf('No authentication listener registered for firewall "%s".', $id));
         }
 
         return array($listeners, $defaultEntryPoint);

+ 5 - 1
src/Symfony/Component/Config/Definition/Builder/ExprBuilder.php

@@ -39,10 +39,14 @@ class ExprBuilder
      *
      * @return ExprBuilder
      */
-    public function always()
+    public function always(\Closure $then = null)
     {
         $this->ifPart = function($v) { return true; };
 
+        if (null !== $then) {
+            $this->thenPart = $then;
+        }
+
         return $this;
     }
 

+ 6 - 0
src/Symfony/Component/Security/Core/Authentication/RememberMe/PersistentTokenInterface.php

@@ -19,6 +19,12 @@ namespace Symfony\Component\Security\Core\Authentication\RememberMe;
  */
 interface PersistentTokenInterface
 {
+    /**
+     * Returns the class of the user
+     * @return string
+     */
+    function getClass();
+
     /**
      * Returns the username
      * @return string