Skip to content

Commit

Permalink
added ACL system to the Security Component
Browse files Browse the repository at this point in the history
  • Loading branch information
schmittjoh authored and fabpot committed Dec 31, 2010
1 parent 5c73619 commit b428845
Show file tree
Hide file tree
Showing 64 changed files with 7,674 additions and 2 deletions.
3 changes: 3 additions & 0 deletions src/Symfony/Bundle/DoctrineBundle/Resources/config/orm.xml
Expand Up @@ -38,6 +38,9 @@

<!-- 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>
</parameters>

<services>
Expand Down
58 changes: 58 additions & 0 deletions src/Symfony/Bundle/DoctrineBundle/Security/AclCollectionCache.php
@@ -0,0 +1,58 @@
<?php

namespace Symfony\Bundle\DoctrineBundle\Security;

use Doctrine\Common\Collections\Collection;
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
*
* @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 Collection $collection
* @param array $tokens an array of TokenInterface implementations
* @return void
*/
public function cache(Collection $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);
}
}
67 changes: 67 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/Command/InitAclCommand.php
@@ -0,0 +1,67 @@
<?php

namespace Symfony\Bundle\FrameworkBundle\Command;

use Symfony\Component\Security\Acl\Dbal\Schema;

use Doctrine\DBAL\DriverManager;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

/**
* Installs the tables required by the ACL system
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class InitAclCommand extends Command
{
/**
* @see Command
*/
protected function configure()
{
$this
->setName('init:acl')
;
}

/**
* @see Command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$connection = $this->container->get('security.acl.dbal.connection');
$sm = $connection->getSchemaManager();
$tableNames = $sm->listTableNames();
$tables = array(
'class_table_name' => $this->container->getParameter('security.acl.dbal.class_table_name'),
'sid_table_name' => $this->container->getParameter('security.acl.dbal.sid_table_name'),
'oid_table_name' => $this->container->getParameter('security.acl.dbal.oid_table_name'),
'oid_ancestors_table_name' => $this->container->getParameter('security.acl.dbal.oid_ancestors_table_name'),
'entry_table_name' => $this->container->getParameter('security.acl.dbal.entry_table_name'),
);

foreach ($tables as $table) {
if (in_array($table, $tableNames, true)) {
$output->writeln(sprintf('The table "%s" already exists. Aborting.', $table));
return;
}
}

$schema = new Schema($tables);
foreach ($schema->toSql($connection->getDatabasePlatform()) as $sql) {
$connection->exec($sql);
}

$output->writeln('ACL tables have been initialized successfully.');
}
}
Expand Up @@ -2,6 +2,7 @@

namespace Symfony\Bundle\FrameworkBundle\DependencyInjection;

use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Resource\FileResource;
Expand Down Expand Up @@ -487,6 +488,25 @@ protected function createSwitchUserListener($container, $id, $config, $defaultPr

return $switchUserListenerId;
}

public function aclLoad(array $config, ContainerBuilder $container)
{
if (!$container->hasDefinition('security.acl')) {
$loader = new XmlFileLoader($container, array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config'));
$loader->load('security_acl.xml');
}

if (isset($config['connection'])) {
$container->setAlias(sprintf('doctrine.dbal.%s_connection', $config['connection']), 'security.acl.dbal.connection');
}

if (isset($config['cache'])) {
$container->setAlias('security.acl.cache', sprintf('security.acl.cache.%s', $config['cache']));
} else {
$container->remove('security.acl.cache.doctrine');
$container->removeAlias('security.acl.cache.doctrine.cache_impl');
}
}

/**
* Returns the base path for the XSD files.
Expand Down
@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>

<container xmlns="http://www.symfony-project.org/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.symfony-project.org/schema/dic/services http://www.symfony-project.org/schema/dic/services/services-1.0.xsd">

<parameters>
<parameter key="security.acl.dbal.class_table_name">acl_classes</parameter>
<parameter key="security.acl.dbal.entry_table_name">acl_entries</parameter>
<parameter key="security.acl.dbal.oid_table_name">acl_object_identities</parameter>
<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.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>
</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%"></service>

<service id="security.acl.security_identity_retrieval_strategy" class="%security.acl.security_identity_retrieval_strategy.class%">
<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%">
<argument type="service" id="security.acl.dbal.connection" />
<argument type="service" id="security.acl.permission_granting_strategy" />
<argument type="collection">
<argument key="class_table_name">%security.acl.dbal.class_table_name%</argument>
<argument key="entry_table_name">%security.acl.dbal.entry_table_name%</argument>
<argument key="oid_table_name">%security.acl.dbal.oid_table_name%</argument>
<argument key="oid_ancestors_table_name">%security.acl.dbal.oid_ancestors_table_name%</argument>
<argument key="sid_table_name">%security.acl.dbal.sid_table_name%</argument>
</argument>
<argument type="service" id="security.acl.cache" on-invalid="null" />
</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%">
<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%">
<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" />

<service id="security.acl.permission.map" class="%security.acl.permission.map.class%"></service>

<service id="security.acl.voter.basic_permissions" class="%security.acl.voter.class%">
<argument type="service" id="security.acl.provider" />
<argument type="service" id="security.acl.object_identity_retrieval_strategy" />
<argument type="service" id="security.acl.security_identity_retrieval_strategy" />
<argument type="service" id="security.acl.permission.map" />
<tag name="security.voter" />
</service>
</services>
</container>
Expand Up @@ -2,6 +2,7 @@

namespace Symfony\Bundle\FrameworkBundle\Templating\Helper;

use Symfony\Component\Security\Acl\Voter\FieldVote;
use Symfony\Component\Templating\Helper\Helper;
use Symfony\Component\Security\SecurityContext;

Expand Down Expand Up @@ -33,11 +34,19 @@ public function __construct(SecurityContext $context = null)
$this->context = $context;
}

public function vote($role, $object = null)
public function vote($role, $object = null, $field = null)
{
if (null === $this->context) {
return false;
}

if ($field !== null) {
if (null === $object) {
throw new \InvalidArgumentException('$object cannot be null when field is not null.');
}

$object = new FieldVote($object, $field);
}

return $this->context->vote($role, $object);
}
Expand Down
10 changes: 9 additions & 1 deletion src/Symfony/Bundle/TwigBundle/Extension/SecurityExtension.php
Expand Up @@ -27,11 +27,19 @@ public function __construct(SecurityContext $context = null)
$this->context = $context;
}

public function vote($role, $object = null)
public function vote($role, $object = null, $field = null)
{
if (null === $this->context) {
return false;
}

if ($field !== null) {
if (null === $object) {
throw new \InvalidArgumentException('$object cannot be null when field is not null.');
}

$object = new FieldVote($object, $field);
}

return $this->context->vote($role, $object);
}
Expand Down

0 comments on commit b428845

Please sign in to comment.