소스 검색

[Security] moved Security classes out of DoctrineBundle, cleaned-up SecurityExtension accordingly

Note that this commit removes the built-in support for MongoDB user providers.
This code can be moved back in once there is a stable release for MongoDB, but
for now you have to set-up that user provider just like you would set-up any
custom user provider:

    security:
         providers:
             document_provider:
                 id: my.mongo.provider
Johannes Schmitt 14 년 전
부모
커밋
82c6844147

+ 0 - 8
src/Symfony/Bundle/DoctrineBundle/Resources/config/orm.xml

@@ -37,12 +37,6 @@
         <parameter key="doctrine.orm.metadata.staticphp_class">Doctrine\ORM\Mapping\Driver\StaticPHPDriver</parameter>
         <parameter key="doctrine.orm.class_metadata_factory_name">Doctrine\ORM\Mapping\ClassMetadataFactory</parameter>
 
-        <!-- security/user -->
-        <parameter key="security.user.provider.entity.class">Symfony\Bundle\DoctrineBundle\Security\EntityUserProvider</parameter>
-        
-        <!--  security/acl -->
-        <parameter key="security.acl.collection_cache.class">Symfony\Bundle\DoctrineBundle\Security\AclCollectionCache</parameter>
-
         <!-- cache warmer -->
         <parameter key="doctrine.orm.proxy_cache_warmer.class">Symfony\Bundle\DoctrineBundle\CacheWarmer\ProxyCacheWarmer</parameter>
         
@@ -59,8 +53,6 @@
             </call>
         </service>
 
-        <service id="security.user.entity_manager" alias="doctrine.orm.default_entity_manager" public="false" />
-
         <service id="doctrine.orm.proxy_cache_warmer" class="%doctrine.orm.proxy_cache_warmer.class%" public="false">
             <tag name="kernel.cache_warmer" />
             <argument type="service" id="service_container" />

+ 11 - 12
src/Symfony/Bundle/SecurityBundle/DependencyInjection/Configuration.php

@@ -17,18 +17,6 @@ use Symfony\Component\DependencyInjection\Configuration\Builder\TreeBuilder;
  */
 class Configuration
 {
-    public function getAclConfigTree()
-    {
-        $tb = new TreeBuilder();
-
-        return $tb
-            ->root('security', 'array')
-                ->scalarNode('connection')->end()
-                ->scalarNode('cache')->end()
-            ->end()
-            ->buildTree();
-    }
-
     public function getFactoryConfigTree()
     {
         $tb = new TreeBuilder();
@@ -53,6 +41,7 @@ class Configuration
             ->scalarNode('session_fixation_strategy')->cannotBeEmpty()->defaultValue('migrate')->end()
         ;
 
+        $this->addAclSection($rootNode);
         $this->addEncodersSection($rootNode);
         $this->addProvidersSection($rootNode);
         $this->addFirewallsSection($rootNode, $factories);
@@ -62,6 +51,16 @@ class Configuration
         return $tb->buildTree();
     }
 
+    protected function addAclSection($rootNode)
+    {
+        $rootNode
+            ->arrayNode('acl')
+                ->scalarNode('connection')->end()
+                ->scalarNode('cache')->end()
+            ->end()
+        ;
+    }
+
     protected function addRoleHierarchySection($rootNode)
     {
         $rootNode

+ 23 - 45
src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php

@@ -47,8 +47,6 @@ class SecurityExtension extends Extension
 
     public function load(array $configs, ContainerBuilder $container)
     {
-        $this->aclLoad($configs, $container);
-
         $tmp = array_filter($configs);
         if (empty($tmp)) {
             return;
@@ -83,22 +81,10 @@ class SecurityExtension extends Extension
         if ($config['encoders']) {
             $this->createEncoders($config['encoders'], $container);
         }
-    }
-
-    protected function aclLoad(array $configs, ContainerBuilder $container)
-    {
-        $processor = new Processor();
-        $config = $processor->process($this->configuration->getAclConfigTree(), $configs);
-
-        $loader = new XmlFileLoader($container, new FileLocator(array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config')));
-        $loader->load('security_acl.xml');
-
-        if (isset($config['connection'])) {
-            $container->setAlias('security.acl.dbal.connection', sprintf('doctrine.dbal.%s_connection', $config['connection']));
-        }
 
-        if (isset($config['cache'])) {
-            $container->setAlias('security.acl.cache', sprintf('security.acl.cache.%s', $config['cache']));
+        // load ACL
+        if (isset($config['acl'])) {
+            $this->aclLoad($config['acl'], $container);
         }
     }
 
@@ -122,6 +108,20 @@ class SecurityExtension extends Extension
         return 'security';
     }
 
+    protected function aclLoad($config, ContainerBuilder $container)
+    {
+        $loader = new XmlFileLoader($container, new FileLocator(array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config')));
+        $loader->load('security_acl.xml');
+
+        if (isset($config['connection'])) {
+            $container->setAlias('security.acl.dbal.connection', sprintf('doctrine.dbal.%s_connection', $config['connection']));
+        }
+
+        if (isset($config['cache'])) {
+            $container->setAlias('security.acl.cache', sprintf('security.acl.cache.%s', $config['cache']));
+        }
+    }
+
     /**
      * Loads the web configuration.
      *
@@ -421,8 +421,6 @@ class SecurityExtension extends Extension
     }
 
     // Parses a <provider> tag and returns the id for the related user provider service
-    // FIXME: Replace register() calls in this method with DefinitionDecorator
-    //        and move the actual definition to an xml file
     protected function createUserDaoProvider($name, $provider, ContainerBuilder $container, $master = true)
     {
         $name = $this->getUserProviderId(strtolower($name));
@@ -443,42 +441,22 @@ class SecurityExtension extends Extension
         // Doctrine Entity DAO provider
         if (isset($provider['entity'])) {
             $container
-                ->register($name, '%security.user.provider.entity.class%')
-                ->setPublic(false)
-                ->setArguments(array(
-                    new Reference('security.user.entity_manager'),
-                    $provider['entity']['class'],
-                    $provider['entity']['property'],
-                ))
+                ->setDefinition($name, new DefinitionDecorator('security.user.provider.entity'))
+                ->addArgument($provider['entity']['class'])
+                ->addArgument($provider['entity']['property'])
             ;
 
             return $name;
         }
 
-        // Doctrine Document DAO provider
-        if (isset($provider['document'])) {
-            $container
-                ->register($name, '%security.user.provider.document.class%')
-                ->setPublic(false)
-                ->setArguments(array(
-                    new Reference('security.user.document_manager'),
-                    $provider['document']['class'],
-                    $provider['document']['property'],
-            ));
-
-            return $name;
-        }
-
         // In-memory DAO provider
-        $definition = $container->register($name, '%security.user.provider.in_memory.class%');
-        $definition->setPublic(false);
+        $definition = $container->setDefinition($name, new DefinitionDecorator('security.user.provider.in_memory'));
         foreach ($provider['users'] as $username => $user) {
             $userId = $name.'_'.$username;
 
             $container
-                ->register($userId, 'Symfony\Component\Security\Core\User\User')
+                ->setDefinition($userId, new DefinitionDecorator('security.user.provider.in_memory.user'))
                 ->setArguments(array($username, $user['password'], $user['roles']))
-                ->setPublic(false)
             ;
 
             $definition->addMethodCall('createUser', array(new Reference($userId)));
@@ -489,7 +467,7 @@ class SecurityExtension extends Extension
 
     protected function getUserProviderId($name)
     {
-        return 'security.user.provider.'.$name;
+        return 'security.user.provider.concrete.'.$name;
     }
 
     protected function createExceptionListener($container, $config, $id, $defaultEntryPoint)

+ 12 - 0
src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml

@@ -14,7 +14,9 @@
         <parameter key="security.encoder.digest.class">Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder</parameter>
         <parameter key="security.encoder.plain.class">Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder</parameter>
 
+        <parameter key="security.user.provider.entity.class">Symfony\Component\Security\Core\User\EntityUserProvider</parameter>
         <parameter key="security.user.provider.in_memory.class">Symfony\Component\Security\Core\User\InMemoryUserProvider</parameter>
+        <parameter key="security.user.provider.in_memory.user.class">Symfony\Component\Security\Core\User\User</parameter>
 
         <parameter key="security.authentication.trust_resolver.class">Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver</parameter>
         <parameter key="security.authentication.trust_resolver.anonymous_class">Symfony\Component\Security\Core\Authentication\Token\AnonymousToken</parameter>
@@ -117,5 +119,15 @@
             <argument type="collection" />
             <argument type="service" id="security.exception_listener" />
         </service>
+
+
+        <!-- Provisioning -->
+        <service id="security.user.provider.entity" class="%security.user.provider.entity.class%" abstract="true" public="false">
+            <argument type="service" id="security.user.entity_manager" />
+        </service>
+        <service id="security.user.entity_manager" alias="doctrine.orm.default_entity_manager" public="false" />
+
+        <service id="security.user.provider.in_memory" class="%security.user.provider.in_memory.class%" abstract="true" public="false" />
+        <service id="security.user.provider.in_memory.user" class="%security.user.provider.in_memory.user.class%" abstract="true" public="false" />
     </services>
 </container>

+ 14 - 12
src/Symfony/Bundle/SecurityBundle/Resources/config/security_acl.xml

@@ -11,30 +11,32 @@
         <parameter key="security.acl.dbal.oid_ancestors_table_name">acl_object_identity_ancestors</parameter>
         <parameter key="security.acl.dbal.sid_table_name">acl_security_identities</parameter>
         <parameter key="security.acl.dbal.provider.class">Symfony\Component\Security\Acl\Dbal\MutableAclProvider</parameter>
-        
+
         <parameter key="security.acl.permission_granting_strategy.class">Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy</parameter>
-        
+
         <parameter key="security.acl.voter.class">Symfony\Component\Security\Acl\Voter\AclVoter</parameter>
         <parameter key="security.acl.voter.allow_if_object_identity_unavailable">true</parameter>
         <parameter key="security.acl.permission.map.class">Symfony\Component\Security\Acl\Permission\BasicPermissionMap</parameter>
-        
+
         <parameter key="security.acl.object_identity_retrieval_strategy.class">Symfony\Component\Security\Acl\Domain\ObjectIdentityRetrievalStrategy</parameter>
         <parameter key="security.acl.security_identity_retrieval_strategy.class">Symfony\Component\Security\Acl\Domain\SecurityIdentityRetrievalStrategy</parameter>
-        
+
         <parameter key="security.acl.cache.doctrine.class">Symfony\Component\Security\Acl\Domain\DoctrineAclCache</parameter>
         <parameter key="security.acl.cache.doctrine.prefix">sf2_acl_</parameter>
+
+        <parameter key="security.acl.collection_cache.class">Symfony\Component\Security\Acl\Domain\AclCollectionCache</parameter>
     </parameters>
 
     <services>
         <service id="security.acl.dbal.connection" alias="doctrine.dbal.default_connection" />
-    
+
         <service id="security.acl.object_identity_retrieval_strategy" class="%security.acl.object_identity_retrieval_strategy.class%" public="false"></service>
-        
+
         <service id="security.acl.security_identity_retrieval_strategy" class="%security.acl.security_identity_retrieval_strategy.class%" public="false">
             <argument type="service" id="security.role_hierarchy" />
             <argument type="service" id="security.authentication.trust_resolver" />
         </service>
-    
+
         <service id="security.acl.dbal.provider" class="%security.acl.dbal.provider.class%" public="false">
             <argument type="service" id="security.acl.dbal.connection" />
             <argument type="service" id="security.acl.permission_granting_strategy" />
@@ -49,23 +51,23 @@
         </service>
 
         <service id="security.acl.provider" alias="security.acl.dbal.provider" />
-        
+
         <service id="security.acl.permission_granting_strategy" class="%security.acl.permission_granting_strategy.class%" public="false">
             <call method="setAuditLogger">
                 <argument type="service" id="security.acl.audit_logger" on-invalid="ignore" />
             </call>
         </service>
-        
+
         <service id="security.acl.cache.doctrine" class="%security.acl.cache.doctrine.class%" public="false">
             <argument type="service" id="security.acl.cache.doctrine_cache_impl" />
             <argument type="service" id="security.acl.permission_granting_strategy" />        
             <argument>%security.acl.cache.doctrine.prefix%</argument>
         </service>
-        
+
         <service id="security.acl.cache.doctrine.cache_impl" alias="doctrine.orm.default_result_cache" public="false" />
-        
+
         <service id="security.acl.permission.map" class="%security.acl.permission.map.class%" public="false"></service>
-        
+
         <service id="security.acl.voter.basic_permissions" class="%security.acl.voter.class%" public="false">
             <argument type="service" id="security.acl.provider" />
             <argument type="service" id="security.acl.object_identity_retrieval_strategy" />

+ 10 - 10
src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php

@@ -36,18 +36,18 @@ abstract class SecurityExtensionTest extends \PHPUnit_Framework_TestCase
     {
         $container = $this->getContainer('container1');
 
-        $providers = array_values(array_filter($container->getServiceIds(), function ($key) { return 0 === strpos($key, 'security.user.provider.'); }));
+        $providers = array_values(array_filter($container->getServiceIds(), function ($key) { return 0 === strpos($key, 'security.user.provider.concrete'); }));
 
         $expectedProviders = array(
-            'security.user.provider.default',
-            'security.user.provider.default_foo',
-            'security.user.provider.digest',
-            'security.user.provider.digest_foo',
-            'security.user.provider.basic',
-            'security.user.provider.basic_foo',
-            'security.user.provider.basic_bar',
-            'security.user.provider.doctrine',
-            'security.user.provider.service',
+            'security.user.provider.concrete.default',
+            'security.user.provider.concrete.default_foo',
+            'security.user.provider.concrete.digest',
+            'security.user.provider.concrete.digest_foo',
+            'security.user.provider.concrete.basic',
+            'security.user.provider.concrete.basic_foo',
+            'security.user.provider.concrete.basic_bar',
+            'security.user.provider.concrete.doctrine',
+            'security.user.provider.concrete.service',
         );
 
         $this->assertEquals(array(), array_diff($expectedProviders, $providers));

+ 66 - 0
src/Symfony/Component/Security/Acl/Domain/AclCollectionCache.php

@@ -0,0 +1,66 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Acl\Domain;
+
+use Symfony\Component\Security\Acl\Model\AclProviderInterface;
+use Symfony\Component\Security\Acl\Model\ObjectIdentityRetrievalStrategyInterface;
+use Symfony\Component\Security\Acl\Model\SecurityIdentityRetrievalStrategyInterface;
+
+/**
+ * This service caches ACLs for an entire collection of objects.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class AclCollectionCache
+{
+    protected $aclProvider;
+    protected $objectIdentityRetrievalStrategy;
+    protected $securityIdentityRetrievalStrategy;
+
+    /**
+     * Constructor
+     *
+     * @param AclProviderInterface $aclProvider
+     * @param ObjectIdentityRetrievalStrategy $oidRetrievalStrategy
+     * @param SecurityIdentityRetrievalStrategy $sidRetrievalStrategy
+     * @return void
+     */
+    public function __construct(AclProviderInterface $aclProvider, ObjectIdentityRetrievalStrategyInterface $oidRetrievalStrategy, SecurityIdentityRetrievalStrategyInterface $sidRetrievalStrategy)
+    {
+        $this->aclProvider = $aclProvider;
+        $this->objectIdentityRetrievalStrategy = $oidRetrievalStrategy;
+        $this->securityIdentityRetrievalStrategy = $sidRetrievalStrategy;
+    }
+
+    /**
+     * Batch loads ACLs for an entire collection; thus, it reduces the number
+     * of required queries considerably.
+     *
+     * @param mixed $collection anything that can be passed to foreach()
+     * @param array $tokens an array of TokenInterface implementations
+     * @return void
+     */
+    public function cache($collection, array $tokens = array())
+    {
+        $sids = array();
+        foreach ($tokens as $token) {
+            $sids = array_merge($sids, $this->securityIdentityRetrievalStrategy->getSecurityIdentities($token));
+        }
+
+        $oids = array();
+        foreach ($collection as $domainObject) {
+            $oids[] = $this->objectIdentityRetrievalStrategy->getObjectIdentity($domainObject);
+        }
+
+        $this->aclProvider->findAcls($oids, $sids);
+    }
+}

+ 11 - 4
src/Symfony/Bundle/DoctrineBundle/Security/EntityUserProvider.php

@@ -9,20 +9,27 @@
  * file that was distributed with this source code.
  */
 
-namespace Symfony\Bundle\DoctrineBundle\Security;
+namespace Symfony\Component\Security\Core\User;
 
-use Symfony\Component\Security\Core\User\AccountInterface;
-use Symfony\Component\Security\Core\User\UserProviderInterface;
+use Doctrine\ORM\EntityManager;
 use Symfony\Component\Security\Core\Exception\UnsupportedAccountException;
 use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
 
+/**
+ * Wrapper around a Doctrine EntityManager.
+ *
+ * Provides easy to use provisioning for Doctrine entity users.
+ *
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
 class EntityUserProvider implements UserProviderInterface
 {
     protected $class;
     protected $repository;
     protected $property;
 
-    public function __construct($em, $class, $property = null)
+    public function __construct(EntityManager $em, $class, $property = null)
     {
         $this->class = $class;
 

+ 1 - 1
src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php

@@ -64,7 +64,7 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL
         if (null !== $this->csrfProvider) {
             $csrfToken = $request->get($this->options['csrf_parameter']);
 
-            if (false === $this->csrfProvider->isTokenValid($this->options['csrf_page_id'], $csrfToken)) {
+            if (false === $this->csrfProvider->isCsrfTokenValid($this->options['csrf_page_id'], $csrfToken)) {
                 throw new InvalidCsrfTokenException('Invalid CSRF token.');
             }
         }