瀏覽代碼

add RoleSecurityHandler

Roel Sint 13 年之前
父節點
當前提交
43aa6779ea

+ 21 - 7
Admin/Admin.php

@@ -364,6 +364,13 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
 
     protected $labelTranslatorStrategy;
 
+    /**
+     * Roles and permissions per role
+     *
+     * @var array [role] => array([permission], [permission])
+     */
+    protected $securityInformation = array();
+
     /**
      * This method can be overwritten to tweak the form construction, by default the form
      * is built by reading the FieldDescription
@@ -2078,19 +2085,26 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
     }
 
     /**
-     * Return the roles and permissions per role for the admin ACL
+     * Set the roles and permissions per role
+     *
+     * @param array $information
+     */
+    public function setSecurityInformation(array $information)
+    {
+        $this->securityInformation = $information;
+    }
+
+    /**
+     * Return the roles and permissions per role
+     * - different permissions per role for the acl handler
+     * - one permission that has the same name as the role for the role handler 
      * This should be used by experimented users
      *
      * @return array [role] => array([permission], [permission])
      */
     public function getSecurityInformation()
     {
-        return array(
-            'GUEST'    => array('VIEW', 'LIST'),
-            'STAFF'    => array('EDIT', 'LIST', 'CREATE'),
-            'EDITOR'   => array('OPERATOR'),
-            'ADMIN'    => array('MASTER'),
-        );
+        return $this->securityInformation;
     }
 
     /**

+ 4 - 0
DependencyInjection/Compiler/AddDependencyCallsCompilerPass.php

@@ -203,6 +203,10 @@ class AddDependencyCallsCompilerPass implements CompilerPassInterface
             $definition->addMethodCall('setTemplates', array('%sonata.admin.configuration.templates%'));
         }
 
+        if ($container->hasParameter('sonata.admin.configuration.security.information') && !$definition->hasMethodCall('setSecurityInformation')) {
+            $definition->addMethodCall('setSecurityInformation', array('%sonata.admin.configuration.security.information%'));
+        }
+
         return $definition;
     }
 

+ 22 - 1
DependencyInjection/Configuration.php

@@ -39,7 +39,28 @@ class Configuration implements ConfigurationInterface
             ->fixXmlConfig('dashboard_group')
             ->fixXmlConfig('admin_service')
             ->children()
-                ->scalarNode('security_handler')->defaultValue('sonata.admin.security.handler.noop')->end()
+
+                ->arrayNode('security')
+                    ->addDefaultsIfNotSet()
+                    ->children()
+                        ->scalarNode('handler')->defaultValue('sonata.admin.security.handler.noop')->end()
+                        ->arrayNode('information')
+                            ->useAttributeAsKey('id')
+                            ->prototype('array')
+                                ->performNoDeepMerging()
+                                ->beforeNormalization()
+                                    ->ifString()
+                                    ->then(function($v){ return array($v); })
+                                ->end()
+                                ->prototype('scalar')->end()
+                            ->end()
+                        ->end()
+                        ->arrayNode('admin_permissions')
+                            ->defaultValue(array('CREATE', 'LIST'))
+                            ->prototype('scalar')->end()
+                        ->end()
+                    ->end()
+                ->end()
 
                 ->scalarNode('title')->defaultValue('Sonata Admin')->cannotBeEmpty()->end()
                 ->scalarNode('title_logo')->defaultValue('bundles/sonataadmin/logo_title.png')->cannotBeEmpty()->end()

+ 41 - 1
DependencyInjection/SonataAdminExtension.php

@@ -67,7 +67,47 @@ class SonataAdminExtension extends Extension
         $container->setParameter('sonata.admin.configuration.admin_services', $config['admin_services']);
         $container->setParameter('sonata.admin.configuration.dashboard_groups', $config['dashboard_groups']);
 
-        $container->setAlias('sonata.admin.security.handler', $config['security_handler']);
+        $container->setAlias('sonata.admin.security.handler', $config['security']['handler']);
+
+        switch ($config['security']['handler']) {
+            case 'sonata.admin.security.handler.noop':
+                $container->setParameter('sonata.admin.security.handler.noop.class', 'Sonata\AdminBundle\Security\Handler\NoopSecurityHandler');
+                $container->setDefinition('sonata.admin.security.handler.noop', new Definition('%sonata.admin.security.handler.noop.class%'));
+                break;
+            case 'sonata.admin.security.handler.role':
+                $container->setParameter('sonata.admin.security.handler.role.class', 'Sonata\AdminBundle\Security\Handler\RoleSecurityHandler');
+                $roleService = new Definition('%sonata.admin.security.handler.role.class%', array(new Reference('security.context'), array('ROLE_SUPER_ADMIN')));
+                $container->setDefinition('sonata.admin.security.handler.role', $roleService);
+
+                if (count($config['security']['information']) === 0) {
+                    $config['security']['information'] = array(
+                        'EDIT'      => array('EDIT'),
+                        'LIST'      => array('LIST'),
+                        'CREATE'    => array('CREATE'),
+                        'VIEW'      => array('VIEW'),
+                        'DELETE'    => array('DELETE'),
+                        'OPERATOR'  => array('OPERATOR')
+                    );
+                }
+                break;
+            case 'sonata.admin.security.handler.acl':
+                $container->setParameter('sonata.admin.configuration.security.admin_permissions', $config['security']['admin_permissions']);
+                $loader->load('security_acl.xml');
+
+                if (count($config['security']['information']) === 0) {
+                    $config['security']['information'] = array(
+                        'GUEST'    => array('VIEW', 'LIST'),
+                        'STAFF'    => array('EDIT', 'LIST', 'CREATE'),
+                        'EDITOR'   => array('OPERATOR'),
+                        'ADMIN'    => array('MASTER')
+                    );
+                }
+                break;
+            default:
+                throw new \InvalidArgumentException(sprintf('Unknown security handler "%s"', $config['security']['handler']));
+        }
+
+        $container->setParameter('sonata.admin.configuration.security.information', $config['security']['information']);
 
         /**
          * This is a work in progress, so for now it is hardcoded

+ 0 - 11
Resources/config/core.xml

@@ -30,17 +30,6 @@
             <argument />
         </service>
 
-        <!-- Some security services -->
-        <service id="sonata.admin.security.handler.noop" class="Sonata\AdminBundle\Security\Handler\NoopSecurityHandler" />
-
-        <service id="sonata.admin.security.handler.acl" class="Sonata\AdminBundle\Security\Handler\AclSecurityHandler">
-            <argument type="service" id="security.context" on-invalid="null" />
-            <argument type="service" id="security.acl.provider" on-invalid="null" />
-            <argument type="collection">
-                <argument>ROLE_SUPER_ADMIN</argument>
-            </argument>
-        </service>
-
         <!-- Services used to format the label, default is sonata.admin.label.strategy.noop -->
         <service id="sonata.admin.label.strategy.bc" class="Sonata\AdminBundle\Translator\BCLabelTranslatorStrategy" />
         <service id="sonata.admin.label.strategy.native" class="Sonata\AdminBundle\Translator\NativeLabelTranslatorStrategy" />

+ 23 - 0
Resources/config/security_acl.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<container xmlns="http://symfony.com/schema/dic/services"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
+
+    <parameters>
+        <parameter key="sonata.admin.security.handler.acl.class" >Sonata\AdminBundle\Security\Handler\AclSecurityHandler</parameter>
+    </parameters>
+
+    <services>
+        <service id="sonata.admin.security.handler.acl" class="%sonata.admin.security.handler.acl.class%">
+            <argument type="service" id="security.context" on-invalid="null" />
+            <argument type="service" id="security.acl.provider" on-invalid="null" />
+            <argument type="collection">
+                <argument>ROLE_SUPER_ADMIN</argument>
+            </argument>
+            <call method="setAdminPermissions">
+                <argument>%sonata.admin.configuration.security.admin_permissions%</argument>
+            </call>            
+        </service>
+    </services>    
+</container>

+ 24 - 0
Security/Handler/AclSecurityHandler.php

@@ -25,6 +25,7 @@ class AclSecurityHandler implements SecurityHandlerInterface
     protected $securityContext;
     protected $aclProvider;
     protected $superAdminRoles;
+    protected $adminPermissions;
 
     /**
      * @param \Symfony\Component\Security\Core\SecurityContextInterface $securityContext
@@ -37,6 +38,26 @@ class AclSecurityHandler implements SecurityHandlerInterface
         $this->superAdminRoles = $superAdminRoles;
     }
 
+    /**
+     * Set the permissions not related to an object instance and also to be available when objects do not exist
+     *
+     * @param array $permissions
+     */
+    public function setAdminPermissions(array $permissions)
+    {
+        $this->adminPermissions = $permissions;
+    }
+
+    /**
+     * Return the permissions not related to an object instance and also to be available when objects do not exist
+     *
+     * @return array
+     */
+    public function getAdminPermissions()
+    {
+        return $this->adminPermissions;
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -55,6 +76,9 @@ class AclSecurityHandler implements SecurityHandlerInterface
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     public function getBaseRole(AdminInterface $admin)
     {
         return 'ROLE_'.str_replace('.', '_', strtoupper($admin->getCode())).'_%s';

+ 8 - 0
Security/Handler/NoopSecurityHandler.php

@@ -23,6 +23,14 @@ class NoopSecurityHandler implements SecurityHandlerInterface
         return true;
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    public function getBaseRole(AdminInterface $admin)
+    {
+        return '';
+    }
+
     /**
      * {@inheritDoc}
      */

+ 78 - 0
Security/Handler/RoleSecurityHandler.php

@@ -0,0 +1,78 @@
+<?php
+
+/*
+ * This file is part of the Sonata project.
+ *
+ * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Sonata\AdminBundle\Security\Handler;
+
+use Symfony\Component\Security\Core\SecurityContextInterface;
+use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
+use Sonata\AdminBundle\Admin\AdminInterface;
+
+class RoleSecurityHandler implements SecurityHandlerInterface
+{
+    protected $securityContext;
+
+    protected $superAdminRoles;
+
+    /**
+     * @param \Symfony\Component\Security\Core\SecurityContextInterface $securityContext
+     * @param array $superAdminRoles
+     */
+    public function __construct(SecurityContextInterface $securityContext, array $superAdminRoles)
+    {
+        $this->securityContext = $securityContext;
+        $this->superAdminRoles = $superAdminRoles;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function isGranted(AdminInterface $admin, $attributes, $object = null)
+    {
+        if (!is_array($attributes)) {
+            $attributes = array($attributes);
+        }
+
+        foreach ($attributes as $pos => $attribute) {
+            $attributes[$pos] = sprintf($this->getBaseRole($admin), $attribute);
+        }
+
+        try {
+            return $this->securityContext->isGranted($this->superAdminRoles) || $this->securityContext->isGranted($attributes);
+        } catch (AuthenticationCredentialsNotFoundException $e) {
+            return false;
+        } catch (\Exception $e) {
+            throw $e;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getBaseRole(AdminInterface $admin)
+    {
+        return 'ROLE_'.str_replace('.', '_', strtoupper($admin->getCode())).'_%s';
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
+    public function buildSecurityInformation(AdminInterface $admin)
+    {
+        return array();
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
+    public function createObjectOwner(AdminInterface $admin, $object)
+    {
+    }
+}

+ 9 - 0
Security/Handler/SecurityHandlerInterface.php

@@ -23,6 +23,15 @@ interface SecurityHandlerInterface
      */
     function isGranted(AdminInterface $admin, $attributes, $object = null);
 
+    /**
+     * Get a sprintf template to get the role
+     *
+     * @abstract
+     * @param \Sonata\AdminBundle\Admin\AdminInterface $admin
+     * @return string
+     */
+    function getBaseRole(AdminInterface $admin);
+
     /**
      * @abstract
      * @param \Sonata\AdminBundle\Admin\AdminInterface $admin