said.seven
said.seven

Reputation: 71

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

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

Upvotes: 7

Views: 18055

Answers (3)

medowlock
medowlock

Reputation: 1539

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.

Upvotes: 6

Cristian
Cristian

Reputation: 1694

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) {
   // ...
}

Upvotes: 5

Debreczeni András
Debreczeni András

Reputation: 1678

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

Upvotes: 1

Related Questions