Check if a role is granted for a specific user in Symfony2 ACL
Asked Answered
N

3

7

I want to check if a role is granted for a specific user in Symfony2 (not the logged user). I know that I can check it for the logged user by:

$securityContext = $this->get('security.context');

if (false === $securityContext->isGranted('VIEW', $objectIdentity)) {
        //do anything
}

but if I'm the logged user and I wand to check other user if isGranted ??

Negrillo answered 6/6, 2014 at 9:17 Comment(0)
I
6

The "VIEW" is a permission, not a role.

The best way to check if a user has a right (be it a role or permission) would be to access the AccessDecisionManager. Something like:

$token = new UsernamePasswordToken($user, 'none', 'none', $user->getRoles());
$attributes = is_array($attributes) ? $attributes : array($attributes);
$this->get('security.access.decision_manager')->decide($token, $attributes, $object);

See original answer here: https://mcmap.net/q/729243/-how-to-use-the-accessdecisionmanager-in-symfony2-for-authorization-of-arbitrary-users for details.

Isle answered 28/4, 2015 at 7:52 Comment(1)
I think this is the correct answer. Access Control Lists are way too complicated for common use cases.Raviv
L
5

You just need to create a custom security context that will take a user object and generate a UserSecurityIdentity out of it. Here are the steps:

Create a new service in YourApp/AppBundle/Resources/config.yml

yourapp.security_context:
    class: YourApp\AppBundle\Security\Core\SecurityContext
    arguments: [ @security.acl.provider ]

Create a custom Security Context Class like this:

namespace YourApp\AppBundle\Security\Core;

use Symfony\Component\Security\Acl\Model\MutableAclProviderInterface;
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
use Symfony\Component\Security\Acl\Permission\MaskBuilder;

use Symfony\Component\Security\Acl\Exception\AclNotFoundException;
use Symfony\Component\Security\Acl\Exception\NoAceFoundException;

use YourApp\AppBundle\Document\User;

/**
 * Allows ACL checking against a specific user object (regardless of whether that user is logged in or not)
 *
 */
class SecurityContext
{
    public function __construct(MutableAclProviderInterface $aclProvider)
    {
        $this->aclProvider = $aclProvider;
    }

    public function isGranted($mask, $object, User $user)
    {
        $objectIdentity = ObjectIdentity::fromDomainObject($object);
        $securityIdentity = UserSecurityIdentity::fromAccount($user);

        try {
            $acl = $this->aclProvider->findAcl($objectIdentity, array($securityIdentity));
        } catch (AclNotFoundException $e) {
            return false;
        }

        if (!is_int($mask)) {
            $builder = new MaskBuilder;
            $builder->add($mask);

            $mask = $builder->get();
        }

        try {
            return $acl->isGranted(array($mask), array($securityIdentity), false);
        } catch (NoAceFoundException $e) {
            return false;
        }
    }
}

Now you can inject that service where needed, or use it from a controller like this:

$someUser = $this->findSomeUserFromYourDatabase();

if ($this->get('yourapp.security_context')->isGranted('VIEW', $article, $someUser) {
   // ...
}
Lyman answered 14/11, 2014 at 22:50 Comment(0)
M
1

Checking roles for another user can not be done via the SecurityContext as this will always hold the current user's session token. Your task can be achieved for example via the getRoles method, if the user you need to check implements the UserInterface.

$otherUser = $this->get('doctrine')->...   // fetch the user

if( $otherUser instanceof \Symfony\Component\Security\Core\User\UserInterface  )
{ 
     $roles = $otherUser->getRoles();

     // your role could be VIEW or ROLE_VIEW, check the $roles array above. 
     if ( in_array( 'VIEW' , $roles ) )
     {
      // do something else
     }
}

If your user entity implement the FosUserBundle UserInterFace, that has a dedicated method hasRole. In that case you could use a one-liner:

$otherUser = $this->get('doctrine')->...   // fetch the user

if( $otherUser instanceof \FOS\UserBundle\Model\UserInterface  )
{ 
     // your role could be VIEW or ROLE_VIEW, check the proper role names
     if ( $otherUser->hasRole( 'VIEW' ) )
     {
      // do something else
     }
}
Mande answered 6/6, 2014 at 9:31 Comment(4)
No, I want something like this: $user = $em->getRepository('ZxZZBundle:User')->find($id); if(false === $user->isGranted('VIEW', $objectIdentity) ) { // xxxxx } but User not have isGranted method.Negrillo
I want to check if he has "VIEW" role on specific entity, for example I want to check if user3 can view Product entity or user2 can create Product entity.Negrillo
What kind of mechanism are you using to keep track of these ACL definitions?Mull
Note that in_array() & hasRole() don't take into account the ROLE inheritanceEo

© 2022 - 2024 — McMap. All rights reserved.