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 ??

said.seven
  • 71
  • 1
  • 1
  • 4

3 Answers3

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://stackoverflow.com/a/22380765/971254 for details.

Community
  • 1
  • 1
medowlock
  • 1,469
  • 1
  • 19
  • 25
  • I think this is the correct answer. Access Control Lists are way too complicated for common use cases. – Alberto Oct 28 '16 at 09:48
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) {
   // ...
}
Cristian
  • 1,051
  • 7
  • 10
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
     }
}
Debreczeni András
  • 1,597
  • 10
  • 18
  • 1
    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. – said.seven Jun 06 '14 at 09:47
  • 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. – said.seven Jun 06 '14 at 10:42
  • What kind of mechanism are you using to keep track of these ACL definitions? – Debreczeni András Jun 06 '14 at 11:01
  • 6
    Note that `in_array()` & `hasRole()` don't take into account the ROLE inheritance – Pierre de LESPINAY Jul 13 '15 at 15:04