Skip to content

Commit

Permalink
ACL UI
Browse files Browse the repository at this point in the history
  • Loading branch information
dunglas committed Jul 25, 2013
1 parent f66001d commit 6a27daa
Show file tree
Hide file tree
Showing 51 changed files with 1,261 additions and 2 deletions.
9 changes: 9 additions & 0 deletions Admin/Admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
use Sonata\AdminBundle\Route\RouteGeneratorInterface;

use Sonata\AdminBundle\Security\Handler\SecurityHandlerInterface;
use Sonata\AdminBundle\Security\Handler\AclSecurityHandlerInterface;
use Sonata\AdminBundle\Route\RouteCollection;
use Sonata\AdminBundle\Model\ModelManagerInterface;

Expand Down Expand Up @@ -2618,4 +2619,12 @@ protected function predefinePerPageOptions()
$this->perPageOptions = array_unique($this->perPageOptions);
sort($this->perPageOptions);
}

/**
* {@inheritdoc}
*/
public function isAclEnabled()
{
return $this->getSecurityHandler() instanceof AclSecurityHandlerInterface;
}
}
7 changes: 7 additions & 0 deletions Admin/AdminInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -595,4 +595,11 @@ public function setFormGroups(array $formGroups);
* @return void
*/
public function addFormFieldDescription($name, FieldDescriptionInterface $fieldDescription);

/**
* Returns true if this admin uses ACL
*
* @return boolean
*/
public function isAclEnabled();
}
81 changes: 81 additions & 0 deletions Controller/CRUDController.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Symfony\Component\HttpFoundation\Request;
use Sonata\AdminBundle\Datagrid\ProxyQueryInterface;
use Sonata\AdminBundle\Admin\BaseFieldDescription;
use Sonata\AdminBundle\Util\AdminObjectAclData;

class CRUDController extends Controller
{
Expand Down Expand Up @@ -720,6 +721,86 @@ public function exportAction(Request $request)
return $this->get('sonata.admin.exporter')->getResponse($format, $filename, $this->admin->getDataSourceIterator());
}

/**
* Gets ACL users
*
* @return array
*/
protected function getAclUsers()
{
$userManagerServiceName = $this->container->getParameter('sonata.admin.security.acl_user_manager');
if ($userManagerServiceName !== null && $this->has($userManagerServiceName)) {
$userManager = $this->get($userManagerServiceName);

if (method_exists($userManager, 'findUsers')) {
return $userManager->findUsers();
}
}

return array();
}

/**
* return the Response object associated to the acl action
*
* @param null $id
*
* @throws \Symfony\Component\Security\Core\Exception\AccessDeniedException
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
*
* @return Response
*/
public function aclAction($id = null)
{
if (!$this->admin->isAclEnabled()) {
throw new NotFoundHttpException('ACL are not enabled for this admin');
}

$object = $this->admin->getObject($id);

if (!$object) {
throw new NotFoundHttpException(sprintf('unable to find the object with id : %s', $id));
}

if (false === $this->admin->isGranted('MASTER', $object)) {
throw new AccessDeniedException();
}

$this->admin->setSubject($object);
$aclUsers = $this->getAclUsers();

$adminObjectAclManipulator = $this->get('sonata.admin.object.manipulator.acl.admin');
$adminObjectAclData = new AdminObjectAclData(
$this->admin,
$object,
$aclUsers,
$adminObjectAclManipulator->getMaskBuilderClass()
);

$form = $adminObjectAclManipulator->createForm($adminObjectAclData);

$request = $this->getRequest();
if ($request->getMethod() === 'POST') {
$form->bind($request);

if ($form->isValid()) {
$adminObjectAclManipulator->updateAcl($adminObjectAclData);

$this->addFlash('sonata_flash_success', 'flash_acl_edit_success');

return new RedirectResponse($this->admin->generateObjectUrl('acl', $object));
}
}

return $this->render($this->admin->getTemplate('acl'), array(
'action' => 'acl',
'permissions' => $adminObjectAclData->getUserPermissions(),
'object' => $object,
'users' => $aclUsers,
'form' => $form->createView()
));
}

/**
* Adds a flash message for type.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ public function fixTemplates(ContainerBuilder $container, Definition $definition
'edit' => 'SonataAdminBundle:CRUD:edit.html.twig',
'history' => 'SonataAdminBundle:CRUD:history.html.twig',
'history_revision' => 'SonataAdminBundle:CRUD:history_revision.html.twig',
'acl' => 'SonataAdminBundle:CRUD:acl.html.twig',
'action' => 'SonataAdminBundle:CRUD:action.html.twig',
'short_object_description' => 'SonataAdminBundle:Helper:short-object-description.html.twig',
'preview' => 'SonataAdminBundle:CRUD:preview.html.twig',
Expand Down
2 changes: 2 additions & 0 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public function getConfigTreeBuilder()
->defaultValue(array('VIEW', 'EDIT', 'DELETE', 'UNDELETE', 'OPERATOR', 'MASTER', 'OWNER'))
->prototype('scalar')->end()
->end()
->scalarNode('acl_user_manager')->defaultValue(null)->end()
->end()
->end()

Expand Down Expand Up @@ -148,6 +149,7 @@ public function getConfigTreeBuilder()
->scalarNode('preview')->defaultValue('SonataAdminBundle:CRUD:preview.html.twig')->cannotBeEmpty()->end()
->scalarNode('history')->defaultValue('SonataAdminBundle:CRUD:history.html.twig')->cannotBeEmpty()->end()
->scalarNode('history_revision')->defaultValue('SonataAdminBundle:CRUD:history_revision.html.twig')->cannotBeEmpty()->end()
->scalarNode('acl')->defaultValue('SonataAdminBundle:CRUD:acl.html.twig')->cannotBeEmpty()->end()
->scalarNode('action')->defaultValue('SonataAdminBundle:CRUD:action.html.twig')->cannotBeEmpty()->end()
->scalarNode('list_block')->defaultValue('SonataAdminBundle:Block:block_admin_list.html.twig')->cannotBeEmpty()->end()
->scalarNode('short_object_description')->defaultValue('SonataAdminBundle:Helper:short-object-description.html.twig')->cannotBeEmpty()->end()
Expand Down
6 changes: 6 additions & 0 deletions DependencyInjection/SonataAdminExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ public function load(array $configs, ContainerBuilder $container)
$container->setParameter('sonata.admin.configuration.dashboard_groups', $config['dashboard']['groups']);
$container->setParameter('sonata.admin.configuration.dashboard_blocks', $config['dashboard']['blocks']);

if (null === $config['security']['acl_user_manager'] && isset($bundles['FOSUserBundle'])) {
$container->setParameter('sonata.admin.security.acl_user_manager', 'fos_user.user_manager');
} else {
$container->setParameter('sonata.admin.security.acl_user_manager', $config['security']['acl_user_manager']);
}

$container->setAlias('sonata.admin.security.handler', $config['security']['handler']);

switch ($config['security']['handler']) {
Expand Down
5 changes: 5 additions & 0 deletions Resources/config/security.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<parameter key="sonata.admin.security.handler.acl.class" >Sonata\AdminBundle\Security\Handler\AclSecurityHandler</parameter>
<parameter key="sonata.admin.security.mask.builder.class" >Sonata\AdminBundle\Security\Acl\Permission\MaskBuilder</parameter>
<parameter key="sonata.admin.manipulator.acl.admin.class">Sonata\AdminBundle\Util\AdminAclManipulator</parameter>
<parameter key="sonata.admin.object.manipulator.acl.admin.class">Sonata\AdminBundle\Util\AdminObjectAclManipulator</parameter>
</parameters>

<services>
Expand Down Expand Up @@ -37,5 +38,9 @@
<service id="sonata.admin.manipulator.acl.admin" class="%sonata.admin.manipulator.acl.admin.class%" >
<argument>%sonata.admin.security.mask.builder.class%</argument>
</service>
<service id="sonata.admin.object.manipulator.acl.admin" class="%sonata.admin.object.manipulator.acl.admin.class%">
<argument type="service" id="form.factory"/>
<argument>%sonata.admin.security.mask.builder.class%</argument>
</service>
</services>
</container>
Binary file added Resources/doc/images/acl_editor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions Resources/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,8 @@ Overview
:width: 700px

The modal model edition

.. figure:: ./images/acl_editor.png
:align: center
:alt: The ACL editor
:width: 700px
1 change: 1 addition & 0 deletions Resources/doc/reference/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Full Configuration Options
sonata_admin:
security:
handler: sonata.admin.security.handler.role
acl_user_manager: fos_user.user_manager # Name of the user manager service used to retrieve ACL users
title: Sonata Project
title_logo: bundles/sonataadmin/logo_title.png
Expand Down
60 changes: 60 additions & 0 deletions Resources/doc/reference/security.rst
Original file line number Diff line number Diff line change
Expand Up @@ -612,3 +612,63 @@ In the templates, or in your code, you can use the Admin method ``isGranted()``

{# or use the default is_granted symfony helper, the following will give the same result #}
{% if is_granted('ROLE_SUPER_ADMIN') or is_granted('DELETE', object) %} {# ... #} {% endif %}

ACL editor
----------

SonataAdminBundle provides a user-friendly ACL editor
interface.
It will be automatically available if the ``sonata.admin.security.handler.acl``
security handler is used and properly configured.

The ACL editor is only available for users with `OWNER` or `MASTER` permissions
on the object instance.
The `OWNER` and `MASTER` permissions can only be edited by an user with the
`OWNER` permission on the object instance.

.. figure:: ./images/acl_editor.png
:align: center
:alt: The ACL editor
:width: 700px

User list customization
~~~~~~~~~~~~~~~~~~~~~~~

By default, the ACL editor allows to set permissions for all users managed by
``FOSUserBundle``.

To cutomize displayed user override
`Sonata\AdminBundle\Controller\CRUDController::getAclUsers()`. This method must
return an iterable collection of users.

.. code-block:: php
/**
* {@InheritDoc}
*/
protected function getAclUsers()
{
$userManager = $container->get('fos_user.user_manager');
// Display only kevin and anne
$kevin = $userManager->findUserByUsername('kevin');
$anne = $userManager->findUserByUsername('anne');
return array($kevin, $anne);
}
Custom user manager
~~~~~~~~~~~~~~~~~~~

If your project does not use `FOSUserBundle`, you can globally configure another
service to use when retrieving your users.

- Create a service with a method called `findUsers()` returning an iterable
collection of users
- Update your admin configuration to reference your service name

.. code-block:: yaml
sonata_admin:
security:
acl_user_manager: my_user_manager # The name of your service
16 changes: 16 additions & 0 deletions Resources/translations/SonataAdminBundle.bg.xliff
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,22 @@
<source>confirm_exit</source>
<target>confirm_exit</target>
</trans-unit>
<trans-unit id="link_edit_acl">
<source>link_edit_acl</source>
<target>link_edit_acl</target>
</trans-unit>
<trans-unit id="btn_update_acl">
<source>btn_update_acl</source>
<target>btn_update_acl</target>
</trans-unit>
<trans-unit id="flash_acl_update_success">
<source>flash_acl_edit_success</source>
<target>flash_acl_update_success</target>
</trans-unit>
<trans-unit id="link_action_acl">
<source>link_action_acl</source>
<target>link_action_acl</target>
</trans-unit>
</body>
</file>
</xliff>
16 changes: 16 additions & 0 deletions Resources/translations/SonataAdminBundle.ca.xliff
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,22 @@
<source>confirm_exit</source>
<target>confirm_exit</target>
</trans-unit>
<trans-unit id="link_edit_acl">
<source>link_edit_acl</source>
<target>link_edit_acl</target>
</trans-unit>
<trans-unit id="btn_update_acl">
<source>btn_update_acl</source>
<target>btn_update_acl</target>
</trans-unit>
<trans-unit id="flash_acl_update_success">
<source>flash_acl_edit_success</source>
<target>flash_acl_update_success</target>
</trans-unit>
<trans-unit id="link_action_acl">
<source>link_action_acl</source>
<target>link_action_acl</target>
</trans-unit>
</body>
</file>
</xliff>
16 changes: 16 additions & 0 deletions Resources/translations/SonataAdminBundle.cs.xliff
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,22 @@
<source>confirm_exit</source>
<target>confirm_exit</target>
</trans-unit>
<trans-unit id="link_edit_acl">
<source>link_edit_acl</source>
<target>link_edit_acl</target>
</trans-unit>
<trans-unit id="btn_update_acl">
<source>btn_update_acl</source>
<target>btn_update_acl</target>
</trans-unit>
<trans-unit id="flash_acl_update_success">
<source>flash_acl_edit_success</source>
<target>flash_acl_update_success</target>
</trans-unit>
<trans-unit id="link_action_acl">
<source>link_action_acl</source>
<target>link_action_acl</target>
</trans-unit>
</body>
</file>
</xliff>
16 changes: 16 additions & 0 deletions Resources/translations/SonataAdminBundle.de.xliff
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,22 @@
<source>confirm_exit</source>
<target>Es gibt ungespeicherte Änderungen.</target>
</trans-unit>
<trans-unit id="link_edit_acl">
<source>link_edit_acl</source>
<target>link_edit_acl</target>
</trans-unit>
<trans-unit id="btn_update_acl">
<source>btn_update_acl</source>
<target>btn_update_acl</target>
</trans-unit>
<trans-unit id="flash_acl_update_success">
<source>flash_acl_edit_success</source>
<target>flash_acl_update_success</target>
</trans-unit>
<trans-unit id="link_action_acl">
<source>link_action_acl</source>
<target>link_action_acl</target>
</trans-unit>
</body>
</file>
</xliff>
16 changes: 16 additions & 0 deletions Resources/translations/SonataAdminBundle.en.xliff
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,22 @@
<source>confirm_exit</source>
<target>You have unsaved changes.</target>
</trans-unit>
<trans-unit id="link_edit_acl">
<source>link_edit_acl</source>
<target>Edit ACL</target>
</trans-unit>
<trans-unit id="btn_update_acl">
<source>btn_update_acl</source>
<target>Update ACL</target>
</trans-unit>
<trans-unit id="flash_acl_update_success">
<source>flash_acl_edit_success</source>
<target>ACL has been successfuly updated.</target>
</trans-unit>
<trans-unit id="link_action_acl">
<source>link_action_acl</source>
<target>ACL</target>
</trans-unit>
</body>
</file>
</xliff>
Loading

0 comments on commit 6a27daa

Please sign in to comment.