0
votes

I want to check the acl entry for several child entities while listing the parent.

Thats the current setup:

Gallery (parent)
    Gallerycategory (child)
    Gallerylanguage (child)
  • Every Usergroup has its own ROLE.
  • When creating the Gallerycategory or Gallerylanguage i make a listing of all Groups to that should get access to this entity.
  • When checked the Group gets an VIEW entry in ACL for the Gallerycategory -> ROLE_(Usergroup) relation.

Now, when i want to list my galleries, just the entries for the allowed Gallerycategory or Gallerylanguage should appear.

Whats the best way to achieve that? Getting into the Repository and checking the current user?

2

2 Answers

0
votes

I think i figured it out.

First of all i created a new Interface, called AclChildEntityInterface. Pretty simple:

interface AclChildEntityInterface{ 
    public function getAclChildren(); 
}

Every entity i want to check for child ACL / ACE implements it and returns an array of the functions to get the child entites.

class Gallery implements AclChildEntityInterface
{
    public function getAclChildren(){
        return array(
            'mediacategories' => 'getMediacategories',
            'medialanguages' => 'getMedialanguages',
        );
    }
}

NOTE: the array values must exist as function in the current Entity Class.

After that i created a new AclVoter that extends the Symfony\Component\Security\Acl\Voter\AclVoter:

The Class is almost the same, i juste changed the behavior in the vote function of the

catch (AclNotFoundException $noAcl)

use Symfony\Component\Security\Acl\Voter\AclVoter as BaseVoter;
...
use Develth\Prodcut\GalleryBundle\Entity\AclChildEntityInterface;

class MediaAclVoter extends BaseVoter
{
    ...
    public function vote(TokenInterface $token, $object, array $attributes)
    {
        ...
        } catch (AclNotFoundException $noAcl) {
            if (null !== $this->logger) {
                $this->logger->debug('No ACL found for the object identity. Voting to deny access.');
            }

            // Check if entity has childs to check
            if($object instanceof AclChildEntityInterface){
                $entityChilds = $object->getAclChildren();
                foreach ($entityChilds as $child) {
                    $childEntites = call_user_func( array($object,$child) );
                    foreach ($childEntites as $childEntity) {
                        $mapping =  $childEntity->getName();
                        $oid = $this->objectIdentityRetrievalStrategy->getObjectIdentity($childEntity);
                        try{
                            $acl = $this->aclProvider->findAcl($oid, $sids);
                            if($acl->isGranted($masks, $sids, false)){
                                // Has permission to view. show it. 
                                return self::ACCESS_GRANTED;
                            }
                        }catch(AclNotFoundException $noAcl){
                            // No ACL for this entity. Ignore
                        }catch(NoAceFoundException $noAce){
                            // No ACE for this entity. Ignore because other could have.
                        }
                    }
                }
            }

            return self::ACCESS_DENIED;
        } catch (NoAceFoundException $noAce) {
           ...

}    

What happens here?

If there is no ACL found for the current entity, it checks if its an instance of the previous created AclChildEntityInterface. It gets every childAcl to check and returns an ACCESS_GRANTED if an ACE is found.

But there are still some things i don´t like and i think it could be improved.

In the Entity class that implements AclChildEntityInterface i want to do something like that:

public function getAclChildren(){
    return array(
        'mediacategories' => $this->mediacategories,
        'medialanguages' => $this->medialanguages,
    );
 }

or the regarding get Methods.

But if i want to access those in the Voter i always get the PersistentCollection with the main entity media as owner, so i cannot access those directly. Thats why i use the call_user_funk.

I´m thankful for improvements!

0
votes

I just published a Symfony bundle that solve the exact problem, based on the methodology that @develth described.

https://github.com/GoDisco/AclTreeBundle

The AclTree Bundle allows you to create hierarchy relationship between your entities for ACL Permissions.