Skip to content

Commit

Permalink
Merge pull request #113 from benjamindulau/has_class_permission_expre…
Browse files Browse the repository at this point in the history
…ssion

Added a "hasClassPermission" Expression for checking classe scope permissions
  • Loading branch information
schmittjoh committed Jun 25, 2015
2 parents 9e9a697 + 50df067 commit 75bd0f7
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 48 deletions.
8 changes: 7 additions & 1 deletion Resources/config/security_expressions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<parameters>
<parameter key="security.acl.permission_evaluator.class">JMS\SecurityExtraBundle\Security\Acl\Expression\PermissionEvaluator</parameter>
<parameter key="security.acl.has_permission_compiler.class">JMS\SecurityExtraBundle\Security\Acl\Expression\HasPermissionFunctionCompiler</parameter>
<parameter key="security.acl.has_class_permission_compiler.class">JMS\SecurityExtraBundle\Security\Acl\Expression\HasClassPermissionFunctionCompiler</parameter>

<parameter key="security.expressions.voter.class">JMS\SecurityExtraBundle\Security\Authorization\Expression\LazyLoadingExpressionVoter</parameter>
<parameter key="security.expressions.handler.class">JMS\SecurityExtraBundle\Security\Authorization\Expression\ContainerAwareExpressionHandler</parameter>
Expand Down Expand Up @@ -88,6 +89,11 @@
<service id="security.acl.has_permission_compiler" class="%security.acl.has_permission_compiler.class%" public="false">
<tag name="security.expressions.function_compiler" />
<tag name="security.expressions.variable" variable="permission_evaluator" service="security.acl.permission_evaluator"/>
</service>
</service>

<service id="security.acl.has_class_permission_compiler" class="%security.acl.has_class_permission_compiler.class%" public="false">
<tag name="security.expressions.function_compiler" />
<tag name="security.expressions.variable" variable="security_context" service="security.context"/>
</service>
</services>
</container>
97 changes: 50 additions & 47 deletions Resources/doc/expressions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,53 +63,56 @@ in your config, otherwise you will get an exception upon checking access.

Reference
---------
+-----------------------------------+--------------------------------------------+
| Expression | Description |
+===================================+============================================+
| hasRole('ROLE') | Checks whether the token has a certain |
| | role. |
+-----------------------------------+--------------------------------------------+
| hasAnyRole('ROLE1', 'ROLE2', ...) | Checks whether the token has any of the |
| | given roles. |
+-----------------------------------+--------------------------------------------+
| isAnonymous() | Checks whether the token is anonymous. |
+-----------------------------------+--------------------------------------------+
| isRememberMe() | Checks whether the token is remember me. |
+-----------------------------------+--------------------------------------------+
| isFullyAuthenticated() | Checks whether the token is fully |
| | authenticated. |
+-----------------------------------+--------------------------------------------+
| isAuthenticated() | Checks whether the token is not anonymous. |
+-----------------------------------+--------------------------------------------+
| hasPermission(*var*, 'PERMISSION')| Checks whether the token has the given |
| | permission for the given object (requires |
| | the ACL system). |
+-----------------------------------+--------------------------------------------+
| token | Variable that refers to the token |
| | which is currently in the security context.|
+-----------------------------------+--------------------------------------------+
| user | Variable that refers to the user |
| | which is currently in the security context.|
+-----------------------------------+--------------------------------------------+
| object | Variable that refers to the object for |
| | which access is being requested. |
+-----------------------------------+--------------------------------------------+
| denyAll | Variable that evaluates to ``false``. |
+-----------------------------------+--------------------------------------------+
| permitAll | Variable that evaluates to ``true``. |
+-----------------------------------+--------------------------------------------+
| #*paramName* | Any identifier prefixed with # refers to |
| | a parameter of the same name that is passed|
| | to the method where the expression is used.|
+-----------------------------------+--------------------------------------------+
| and / && | Binary "and" operator |
+-----------------------------------+--------------------------------------------+
| or / || | Binary "or" operator |
+-----------------------------------+--------------------------------------------+
| == | Binary "is equal" operator |
+-----------------------------------+--------------------------------------------+
| not / ! | Negation operator |
+-----------------------------------+--------------------------------------------+
+-----------------------------------------+--------------------------------------------+
| Expression | Description |
+=========================================+============================================+
| hasRole('ROLE') | Checks whether the token has a certain |
| | role. |
+-----------------------------------------+--------------------------------------------+
| hasAnyRole('ROLE1', 'ROLE2', ...) | Checks whether the token has any of the |
| | given roles. |
+-----------------------------------------+--------------------------------------------+
| isAnonymous() | Checks whether the token is anonymous. |
+-----------------------------------------+--------------------------------------------+
| isRememberMe() | Checks whether the token is remember me. |
+-----------------------------------------+--------------------------------------------+
| isFullyAuthenticated() | Checks whether the token is fully |
| | authenticated. |
+-----------------------------------------+--------------------------------------------+
| isAuthenticated() | Checks whether the token is not anonymous. |
+-----------------------------------------+--------------------------------------------+
| hasPermission(*var*, 'PERMISSION') | Checks whether the token has the given |
| | permission for the given object (requires |
| | the ACL system). |
+-----------------------------------------+--------------------------------------------+
| hasClassPermission('MyEntity', 'CREATE')| Checks whether the token has the given |
| | permission for the given class name. |
+-----------------------------------------+--------------------------------------------+
| token | Variable that refers to the token |
| | which is currently in the security context.|
+-----------------------------------------+--------------------------------------------+
| user | Variable that refers to the user |
| | which is currently in the security context.|
+-----------------------------------------+--------------------------------------------+
| object | Variable that refers to the object for |
| | which access is being requested. |
+-----------------------------------------+--------------------------------------------+
| denyAll | Variable that evaluates to ``false``. |
+-----------------------------------------+--------------------------------------------+
| permitAll | Variable that evaluates to ``true``. |
+-----------------------------------------+--------------------------------------------+
| #*paramName* | Any identifier prefixed with # refers to |
| | a parameter of the same name that is passed|
| | to the method where the expression is used.|
+-----------------------------------------+--------------------------------------------+
| and / && | Binary "and" operator |
+-----------------------------------------+--------------------------------------------+
| or / || | Binary "or" operator |
+-----------------------------------------+--------------------------------------------+
| == | Binary "is equal" operator |
+-----------------------------------------+--------------------------------------------+
| not / ! | Negation operator |
+-----------------------------------------+--------------------------------------------+

Further Resources
-----------------
Expand Down
63 changes: 63 additions & 0 deletions Security/Acl/Expression/HasClassPermissionFunctionCompiler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

/*
* Copyright 2011 Johannes M. Schmitt <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace JMS\SecurityExtraBundle\Security\Acl\Expression;

use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\ConstantExpression;

use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\VariableExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\FunctionExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\ExpressionCompiler;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Compiler\Func\FunctionCompilerInterface;

class HasClassPermissionFunctionCompiler implements FunctionCompilerInterface
{
public function getName()
{
return 'hasClassPermission';
}

public function compilePreconditions(ExpressionCompiler $compiler, FunctionExpression $function)
{
$compiler->verifyItem('token', 'Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
}

public function compile(ExpressionCompiler $compiler, FunctionExpression $function)
{
$compiler
->compileInternal(new VariableExpression('permission_evaluator'))
->write('->hasPermission(')
->compileInternal(new VariableExpression('token'))
->write(", new Symfony\Component\Security\Acl\Domain\ObjectIdentity(")
->compileInternal($function->args[0])
->write(", -1), ")
;

if ($function->args[1] instanceof ConstantExpression) {
$compiler->write(var_export(strtoupper($function->args[1]->value), true).')');

return;
}

$compiler
->write('strtoupper(')
->compileInternal($function->args[1])
->write('))')
;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace JMS\SecurityExtraBundle\Tests\Security\Acl\Expression;

use JMS\SecurityExtraBundle\Security\Acl\Expression\HasClassPermissionFunctionCompiler;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\VariableExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\ConstantExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\FunctionExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\ExpressionCompiler;

class HasClassPermissionFunctionCompilerTest extends \PHPUnit_Framework_TestCase
{
private $compiler;

public function testCompile()
{
$source = $this->compiler->compile(new FunctionExpression('hasClassPermission',
array(new VariableExpression('foo'), new ConstantExpression('VIEW'))));

$this->assertContains(
"\$context['permission_evaluator']->hasPermission(\$context['token'], new Symfony\\Component\\Security\\Acl\\Domain\\ObjectIdentity(\$context['foo'], -1), 'VIEW');",
$source);
}

public function testCompileUpperCasesPermissions()
{
$source = $this->compiler->compile(new FunctionExpression('hasClassPermission',
array(new VariableExpression('foo'), new ConstantExpression('view'))));

$this->assertContains(
"\$context['permission_evaluator']->hasPermission(\$context['token'], new Symfony\\Component\\Security\\Acl\\Domain\\ObjectIdentity(\$context['foo'], -1), 'VIEW');",
$source);
}

protected function setUp()
{
$this->compiler = new ExpressionCompiler();
$this->compiler->addFunctionCompiler(new HasClassPermissionFunctionCompiler());
}
}

0 comments on commit 75bd0f7

Please sign in to comment.