Skip to content

Instantly share code, notes, and snippets.

@CodingNinja
Created December 30, 2011 13:09

Revisions

  1. CodingNinja revised this gist Jul 6, 2012. 1 changed file with 3 additions and 2 deletions.
    5 changes: 3 additions & 2 deletions Manager.php
    Original file line number Diff line number Diff line change
    @@ -122,6 +122,7 @@ public function revoke($entity, $mask = MaskBuilder::MASK_OWNER) {

    foreach($aces as $i => $ace) {
    if($securityIdentity->equals($ace->getSecurityIdentity())) {
    $this->revokeMask($i, $acl, $ace, $mask);
    }
    }

    @@ -139,8 +140,8 @@ public function revoke($entity, $mask = MaskBuilder::MASK_OWNER) {
    *
    * @return \ApplicationBundle\Security\Manager Reference to $this for fluent interface
    */
    protected function revokeMask(Acl $acl, Entry $ace, $mask) {
    $acl->updateObjectAce($i, $ace->getMask() & ~$mask);
    protected function revokeMask($index, Acl $acl, Entry $ace, $mask) {
    $acl->updateObjectAce($index, $ace->getMask() & ~$mask);

    return $this;
    }
  2. CodingNinja revised this gist Dec 30, 2011. 2 changed files with 44 additions and 0 deletions.
    22 changes: 22 additions & 0 deletions Manager.php
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,27 @@
    <?php

    /*
    * Copyright (C) 2011 David Mann
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of
    * this software and associated documentation files (the "Software"), to deal in
    * the Software without restriction, including without limitation the rights to
    * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
    * of the Software, and to permit persons to whom the Software is furnished to do
    * so, subject to the following conditions:
    *
    * The above copyright notice and this permission notice shall be included in all
    * copies or substantial portions of the Software.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    * SOFTWARE.
    */

    namespace ApplicationBundle\Security;

    use Symfony\Component\Security\Acl\Domain\Entry;
    22 changes: 22 additions & 0 deletions TestController.php
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,27 @@
    <?php

    /*
    * Copyright (C) 2011 David Mann
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of
    * this software and associated documentation files (the "Software"), to deal in
    * the Software without restriction, including without limitation the rights to
    * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
    * of the Software, and to permit persons to whom the Software is furnished to do
    * so, subject to the following conditions:
    *
    * The above copyright notice and this permission notice shall be included in all
    * copies or substantial portions of the Software.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    * SOFTWARE.
    */

    namespace ApplicationBundle\Controller;

    use ApplicationBundle\Security\MaskBuilder;
  3. CodingNinja created this gist Dec 30, 2011.
    141 changes: 141 additions & 0 deletions Manager.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,141 @@
    <?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;
    }
    }
    33 changes: 33 additions & 0 deletions TestController.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,33 @@
    <?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);
    }
    }
    17 changes: 17 additions & 0 deletions services.xml
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,17 @@
    <?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>