I've got a problem with class-scope aces. I've created an ace for a class like this :
$userIdentity = UserSecurityIdentity::fromAccount($user);
$classIdentity = new ObjectIdentity('some_identifier', 'Class\FQCN');
$acl = $aclProvider->createAcl($classIdentity);
$acl->insertClassAce($userIdentity, MaskBuilder::MASK_CREATE);
$aclProvider->updateAcl($acl);
Now, I'm trying to check the user's permissions. I've found this way of doing things, which is not documented, but gives the expected results on a class basis :
$securityContext->isGranted('CREATE', $classIdentity); // returns true
$securityContext->isGranted('VIEW', $classIdentity); // returns true
$securityContext->isGranted('DELETE', $classIdentity); // returns false
This method is well adapated to the "CREATE" permission check, where there's no available object instance to pass to the method. However, it should be possible to check if another permission is granted on a particular instance basis :
$entity = new Class\FQCN();
$em->persist($entity);
$em->flush();
$securityContext->isGranted('VIEW', $entity); // returns false
This is where the test fails. I expected that an user who has a given permission mask on a class would have the same permissions on every instance of that class, as stated in the documentation ("The PermissionGrantingStrategy first checks all your object-scope ACEs if none is applicable, the class-scope ACEs will be checked"), but it seems not to be the case here.
you are doing it right. and according to the bottom of this page, it should work, but it does not.
the easiest way to make it work is creating an AclVoter class:
namespace Core\Security\Acl\Voter;
use JMS\SecurityExtraBundle\Security\Acl\Voter\AclVoter as BaseAclVoter;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Doctrine\Common\Util\ClassUtils;
class AclVoter extends BaseAclVoter
{
public function vote( TokenInterface $token , $object , array $attributes )
{
//vote for object first
$objectVote = parent::vote( $token , $object , $attributes );
if( self::ACCESS_GRANTED === $objectVote )
{
return self::ACCESS_GRANTED;
}
else
{
//then for object's class
$oid = new ObjectIdentity( 'class' , ClassUtils::getRealClass( get_class( $object ) ) );
$classVote = parent::vote( $token , $oid , $attributes );
if( self::ACCESS_ABSTAIN === $objectVote )
{
if( self::ACCESS_ABSTAIN === $classVote )
{
return self::ACCESS_ABSTAIN;
}
else
{
return $classVote;
}
}
else if( self::ACCESS_DENIED === $objectVote )
{
if( self::ACCESS_ABSTAIN === $classVote )
{
return self::ACCESS_DENIED;
}
else
{
return $classVote;
}
}
}
return self::ACCESS_ABSTAIN;
}
}
then in security.yml set this:
jms_security_extra:
voters:
disable_acl: true
and finally set up the voter as a service:
core.security.acl.voter.basic_permissions:
class: Core\Security\Acl\Voter\AclVoter
public: false
arguments:
- '@security.acl.provider'
- '@security.acl.object_identity_retrieval_strategy'
- '@security.acl.security_identity_retrieval_strategy'
- '@security.acl.permission.map'
- '@?logger'
tags:
- { name: security.voter , priority: 255 }
- { name: monolog.logger , channel: security }
You need to ensure each object has its own ACL (use $aclProvider->createAcl($entity)
) for class-scope permissions to work correctly.
See this discussion: https://groups.google.com/forum/?fromgroups=#!topic/symfony2/pGIs0UuYKX4
If you don't have an existing entity, you can check against the objectIdentity you created. Be careful to use "double-backslashes", because of the escaping of the backslash.
$post = $postRepository->findOneBy(array('id' => 1));
$securityContext = $this->get('security.context');
$objectIdentity = new ObjectIdentity('class', 'Liip\\TestBundle\\Entity\\Post');
// check for edit access
if (true === $securityContext->isGranted('EDIT', $objectIdentity)) {
echo "Edit Access granted to: <br/><br/> ";
print_r("<pre>");
print_r($post);
print_r("</pre>");
} else {
throw new AccessDeniedException();
}
That should work!
If you would check for "object-scope" you could just use $post instead of $objectIdentity in the isGranted function call.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With