Created
December 30, 2011 13:09
-
-
Save CodingNinja/1539784 to your computer and use it in GitHub Desktop.
Grant / Revoke ACL Permissions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace ApplicationBundle\Security; | |
use Symfony\Component\Security\Acl\Domain\Entry; | |
use Symfony\Component\Security\Acl\Domain\Acl; | |
use Symfony\Component\Security\Acl\Dbal\MutableAclProvider; | |
use Symfony\Component\Security\Core\SecurityContextInterface; | |
use Symfony\Component\Security\Acl\Model\AclProviderInterface; | |
use Symfony\Component\Security\Acl\Domain\ObjectIdentity; | |
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity; | |
use ApplicationBundle\Security\MaskBuilder; | |
/** | |
* Easily work with Symfony ACL | |
* | |
* This class abstracts some of the ACL layer and | |
* gives you very easy "Grant" and "Revoke" methods | |
* which will update existing ACL's and create new ones | |
* when required | |
* | |
* @author CodinNinja | |
*/ | |
class Manager { | |
protected $provider; | |
protected $context; | |
/** | |
* Constructor | |
* | |
* @param AclProviderInterface $provider | |
* @param SecurityContextInterface $context | |
*/ | |
public function __construct(AclProviderInterface $provider, SecurityContextInterface $context) { | |
$this->provider = $provider; | |
$this->context = $context; | |
} | |
/** | |
* Grant a permission | |
* | |
* @param Object $entity The DomainObject to add the permissions for | |
* @param integer|string $mask The initial mask | |
* @return Object The original Entity | |
*/ | |
public function grant($entity, $mask = MaskBuilder::MASK_OWNER) { | |
$acl = $this->getAcl($entity); | |
// retrieving the security identity of the currently logged-in user | |
$securityContext = $this->context; | |
$user = $securityContext->getToken()->getUser(); | |
$securityIdentity = UserSecurityIdentity::fromAccount($user); | |
// grant owner access | |
$this->addMask($securityIdentity, $mask, $acl); | |
return $entity; | |
} | |
/** | |
* Get or create an ACL object | |
* | |
* @param object $entity The Domain Object to get the ACL for | |
* | |
* @return Acl The found / craeted ACL | |
*/ | |
protected function getAcl($entity) { | |
// creating the ACL | |
$aclProvider = $this->provider; | |
$objectIdentity = ObjectIdentity::fromDomainObject($entity); | |
try { | |
$acl = $aclProvider->createAcl($objectIdentity); | |
}catch(\Exception $e) { | |
$acl = $aclProvider->findAcl($objectIdentity); | |
} | |
return $acl; | |
} | |
/** | |
* Revoke a permission | |
* | |
* <pre> | |
* $manager->revoke($myDomainObject, 'delete'); // Remove "delete" permission for the $myDomainObject | |
* </pre> | |
* | |
* @param Object $entity The DomainObject that we are revoking the permission for | |
* @param int|string $mask The mask to revoke | |
* | |
* @return \ApplicationBundle\Security\Manager Reference to $this for fluent interface | |
*/ | |
public function revoke($entity, $mask = MaskBuilder::MASK_OWNER) { | |
$acl = $this->getAcl($entity); | |
$aces = $acl->getObjectAces(); | |
$user = $this->context->getToken()->getUser(); | |
$securityIdentity = UserSecurityIdentity::fromAccount($user); | |
foreach($aces as $i => $ace) { | |
if($securityIdentity->equals($ace->getSecurityIdentity())) { | |
} | |
} | |
$this->provider->updateAcl($acl); | |
return $this; | |
} | |
/** | |
* Remove a mask | |
* | |
* @param Acl $acl The ACL to update | |
* @param Entry $ace The ACE to remove the mask from | |
* @param unknown_type $mask The mask to remove | |
* | |
* @return \ApplicationBundle\Security\Manager Reference to $this for fluent interface | |
*/ | |
protected function revokeMask(Acl $acl, Entry $ace, $mask) { | |
$acl->updateObjectAce($i, $ace->getMask() & ~$mask); | |
return $this; | |
} | |
/** | |
* Add a mask | |
* | |
* @param SecurityIdentityInterface $securityIdentity The ACE to add | |
* @param integer|string $mask The initial mask to set | |
* @param ACL $acl The ACL to update | |
* | |
* @return \ApplicationBundle\Security\Manager Reference to $this for fluent interface | |
*/ | |
protected function addMask($securityIdentity, $mask, $acl) { | |
$acl->insertObjectAce($securityIdentity, $mask); | |
$this->provider->updateAcl($acl); | |
return $this; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" ?> | |
<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="application.acl_manager.class">ApplicationBundle\Security\Manager</parameter> | |
</parameters> | |
<services> | |
<service id="application.acl_manager" class="%application.acl_manager.class%"> | |
<argument type="service" id="security.acl.provider" /> | |
<argument type="service" id="security.context" /> | |
</service> | |
</services> | |
</container> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace ApplicationBundle\Controller; | |
use ApplicationBundle\Security\MaskBuilder; | |
use ApplicationBundle\Entity\Entity; | |
use JMS\SecurityExtraBundle\Annotation as Secure; | |
use Symfony\Bundle\FrameworkBundle\Controller\Controller; | |
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | |
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; | |
class TestController extends Controller | |
{ | |
/** | |
* @param Entity $entity | |
* @Template() | |
* @Route("/test/{id}/join", name="test_grant") | |
* @Secure\Secure(roles="ROLE_USER") | |
*/ | |
public function grantAction(Entity $trip) { | |
$this->get('application.acl_manager')->grant($trip, MaskBuilder::MASK_VIEW); | |
} | |
/** | |
* @param Entity $entity | |
* @Template() | |
* @Route("/test/{id}/leave", name="test_leave") | |
* @Secure\SecureParam(name="entity", permissions="VIEW") | |
*/ | |
public function revokeAction(Entity $entity) { | |
$this->get('application.acl_manager')->revoke($entity, MaskBuilder::MASK_VIEW); | |
} | |
} |
You can revoke using deleteObjectAce instead of updating :
$user = $em->getRepository('VendorBundle:User')->find($id);
$aclProvider = $this->get('security.acl.provider');
$objectIdentity = ObjectIdentity::fromDomainObject($entity);
$acl = $aclProvider->findAcl($objectIdentity);
$aces = $acl->getObjectAces();
$securityIdentity = UserSecurityIdentity::fromAccount($user);
foreach($aces as $index=>$ace)
{
if($ace->getSecurityIdentity() == $securityIdentity)
{
$acl->deleteObjectAce($index);
}
}
$aclProvider->updateAcl($acl);
I had to change the function "addMask" to the following function, or else i would get an error when I tried to change the permissions of an existing ACE.
protected function addMask($securityIdentity, $mask, $acl)
{
$updated = false;
foreach($acl->getObjectAces() as $index=>$ace)
{
if($ace->getSecurityIdentity() == $securityIdentity)
{
$acl->updateObjectAce($index, $mask, null);
$updated = true;
}
}
if(!$updated)
{
$acl->insertObjectAce($securityIdentity, $mask);
}
$this->provider->updateAcl($acl);
return $this;
}
What if I also want to delete the object identity object when deleting my domain object? How to do that?
Do you have an example how to add ACE for class scopes as defined here : http://symfony.com/doc/current/cookbook/security/acl_advanced.html
I could able to store the ACE but its not reflecting on permission.
Function to delete ACL entity from database
/**
* Delete ACL entity
*
* @param $entity
* @return $this
* @throws \Symfony\Component\Security\Acl\Exception\InvalidDomainObjectException
*/
public function clean($entity)
{
$objectIdentity = ObjectIdentity::fromDomainObject($entity);
$this->provider->deleteAcl($objectIdentity);
return $this;
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
$i is undefined here