Initial commit with Symfony 2.1+Vendors

Signed-off-by: Gergely POLONKAI (W00d5t0ck) <polesz@w00d5t0ck.info>
This commit is contained in:
Polonkai Gergely
2012-07-01 09:52:20 +02:00
commit 082a0130c2
5381 changed files with 416709 additions and 0 deletions

View File

@@ -0,0 +1,111 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\AfterInvocation;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
use Symfony\Component\Security\Acl\Exception\AclNotFoundException;
use Symfony\Component\Security\Acl\Exception\NoAceFoundException;
use Symfony\Component\Security\Acl\Model\SecurityIdentityRetrievalStrategyInterface;
use Symfony\Component\Security\Acl\Model\ObjectIdentityRetrievalStrategyInterface;
use Symfony\Component\Security\Acl\Model\AclProviderInterface;
use Symfony\Component\Security\Acl\Permission\PermissionMapInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
/**
* This after invocation provider filters returned objects based on ACLs.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class AclAfterInvocationProvider implements AfterInvocationProviderInterface
{
private $aclProvider;
private $oidRetrievalStrategy;
private $sidRetrievalStrategy;
private $permissionMap;
private $logger;
public function __construct(AclProviderInterface $aclProvider, ObjectIdentityRetrievalStrategyInterface $oidRetrievalStrategy, SecurityIdentityRetrievalStrategyInterface $sidRetrievalStrategy, PermissionMapInterface $permissionMap, LoggerInterface $logger = null)
{
$this->aclProvider = $aclProvider;
$this->oidRetrievalStrategy = $oidRetrievalStrategy;
$this->sidRetrievalStrategy = $sidRetrievalStrategy;
$this->permissionMap = $permissionMap;
$this->logger = $logger;
}
public function decide(TokenInterface $token, $secureObject, array $attributes, $returnedObject)
{
if (null === $returnedObject) {
if (null !== $this->logger) {
$this->logger->debug('Returned object was null, skipping security check.');
}
return null;
}
foreach ($attributes as $attribute) {
if (!$this->supportsAttribute($attribute)) {
continue;
}
if (null === $oid = $this->oidRetrievalStrategy->getObjectIdentity($returnedObject)) {
if (null !== $this->logger) {
$this->logger->debug('Returned object was no domain object, skipping security check.');
}
return $returnedObject;
}
$sids = $this->sidRetrievalStrategy->getSecurityIdentities($token);
try {
$acl = $this->aclProvider->findAcl($oid, $sids);
if ($acl->isGranted($this->permissionMap->getMasks($attribute, $returnedObject), $sids, false)) {
return $returnedObject;
}
if (null !== $this->logger) {
$this->logger->debug('Token has been denied access for returned object.');
}
} catch (AclNotFoundException $noAcl) {
throw new AccessDeniedException('No applicable ACL found for domain object.');
} catch (NoAceFoundException $noAce) {
if (null !== $this->logger) {
$this->logger->debug('No applicable ACE found for the given Token, denying access.');
}
}
throw new AccessDeniedException('ACL has denied access for attribute: '.$attribute);
}
// no attribute was supported
return $returnedObject;
}
public function supportsAttribute($attribute)
{
return $this->permissionMap->contains($attribute);
}
public function supportsClass($className)
{
return true;
}
}

View File

@@ -0,0 +1,77 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\AfterInvocation;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* This is the pendant to the AccessDecisionManager which is used to make
* access decisions after a method has been executed.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class AfterInvocationManager implements AfterInvocationManagerInterface
{
private $providers;
public function __construct(array $providers)
{
$this->providers = $providers;
}
/**
* {@inheritDoc}
*/
public function decide(TokenInterface $token, $secureInvocation, array $attributes, $returnedObject)
{
foreach ($this->providers as $provider) {
$returnedObject = $provider->decide($token, $secureInvocation, $attributes, $returnedObject);
}
return $returnedObject;
}
/**
* {@inheritDoc}
*/
public function supportsAttribute($attribute)
{
foreach ($this->providers as $provider) {
if (true === $provider->supportsAttribute($attribute)) {
return true;
}
}
return false;
}
/**
* {@inheritDoc}
*/
public function supportsClass($className)
{
foreach ($this->providers as $provider) {
if (true === $provider->supportsClass($className)) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,56 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\AfterInvocation;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* AfterInvocationManagerInterface
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
interface AfterInvocationManagerInterface
{
/**
* Makes an access decision after the invocation of a method
*
* @param TokenInterface $token
* @param object $secureObject
* @param array $attributes
* @param mixed $returnedValue the value that was returned by the method invocation
* @return mixed the filter return value
*/
function decide(TokenInterface $token, $secureObject, array $attributes, $returnedValue);
/**
* Determines whether the given attribute is supported
*
* @param string $attribute
* @return Boolean
*/
function supportsAttribute($attribute);
/**
* Determines whether the given class is supported
*
* @param string $className the class of the secure object
* @return Boolean
*/
function supportsClass($className);
}

View File

@@ -0,0 +1,33 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\AfterInvocation;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* AfterInvocationProviderInterface
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
interface AfterInvocationProviderInterface
{
function decide(TokenInterface $token, $secureObject, array $attributes, $returnedObject);
function supportsAttribute($attribute);
function supportsClass($className);
}

View File

@@ -0,0 +1,31 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Ast;
class AndExpression implements ExpressionInterface
{
public $left;
public $right;
public function __construct(ExpressionInterface $left, ExpressionInterface $right)
{
$this->left = $left;
$this->right = $right;
}
}

View File

@@ -0,0 +1,29 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Ast;
class ArrayExpression implements ExpressionInterface
{
public $elements;
public function __construct(array $elements)
{
$this->elements = $elements;
}
}

View File

@@ -0,0 +1,29 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Ast;
class ConstantExpression implements ExpressionInterface
{
public $value;
public function __construct($value)
{
$this->value = $value;
}
}

View File

@@ -0,0 +1,23 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Ast;
interface ExpressionInterface
{
}

View File

@@ -0,0 +1,32 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Ast;
class FunctionExpression implements ExpressionInterface
{
/** READ-ONLY */
public $name;
public $args;
public function __construct($name, array $args)
{
$this->name = $name;
$this->args = $args;
}
}

View File

@@ -0,0 +1,31 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Ast;
class GetItemExpression
{
public $array;
public $key;
public function __construct(ExpressionInterface $array, ExpressionInterface $key)
{
$this->array = $array;
$this->key = $key;
}
}

View File

@@ -0,0 +1,31 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Ast;
class GetPropertyExpression implements ExpressionInterface
{
public $object;
public $name;
public function __construct(ExpressionInterface $obj, $name)
{
$this->object = $obj;
$this->name = $name;
}
}

View File

@@ -0,0 +1,31 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Ast;
class IsEqualExpression implements ExpressionInterface
{
public $left;
public $right;
public function __construct(ExpressionInterface $left, ExpressionInterface $right)
{
$this->left = $left;
$this->right = $right;
}
}

View File

@@ -0,0 +1,33 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Ast;
class MethodCallExpression implements ExpressionInterface
{
public $object;
public $method;
public $args;
public function __construct(ExpressionInterface $obj, $method, array $args)
{
$this->object = $obj;
$this->method = $method;
$this->args = $args;
}
}

View File

@@ -0,0 +1,29 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Ast;
class NotExpression implements ExpressionInterface
{
public $expr;
public function __construct(ExpressionInterface $expr)
{
$this->expr = $expr;
}
}

View File

@@ -0,0 +1,31 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Ast;
class OrExpression implements ExpressionInterface
{
public $left;
public $right;
public function __construct(ExpressionInterface $left, ExpressionInterface $right)
{
$this->left = $left;
$this->right = $right;
}
}

View File

@@ -0,0 +1,29 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Ast;
class ParameterExpression implements ExpressionInterface
{
public $name;
public function __construct($name)
{
$this->name = $name;
}
}

View File

@@ -0,0 +1,31 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Ast;
class VariableExpression implements ExpressionInterface
{
public $name;
public $allowNull;
public function __construct($name, $allowNull = false)
{
$this->name = $name;
$this->allowNull = $allowNull;
}
}

View File

@@ -0,0 +1,32 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Compiler;
class AndExpressionCompiler extends BinaryExprCompiler
{
public function getType()
{
return 'JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\AndExpression';
}
protected function getOperator()
{
return '&&';
}
}

View File

@@ -0,0 +1,51 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Compiler;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\ExpressionInterface;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\ExpressionCompiler;
/**
* Base Compiler for Binary Operators.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
abstract class BinaryExprCompiler implements TypeCompilerInterface
{
public function compilePreconditions(ExpressionCompiler $compiler, ExpressionInterface $expr)
{
$compiler
->compilePreconditions($expr->left)
->compilePreconditions($expr->right)
;
}
public function compile(ExpressionCompiler $compiler, ExpressionInterface $expr)
{
$compiler
->write("(")
->compileInternal($expr->left)
->write(") ".$this->getOperator()." (")
->compileInternal($expr->right)
->write(")")
;
}
abstract protected function getOperator();
}

View File

@@ -0,0 +1,60 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Compiler;
use Symfony\Component\DependencyInjection\ContainerInterface;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\ExpressionInterface;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\ExpressionCompiler;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Compiler\VariableExpressionCompiler;
class ContainerAwareVariableCompiler extends VariableExpressionCompiler
{
private $serviceMap = array();
private $parameterMap = array();
public function setMaps(array $serviceMap, array $parameterMap)
{
$this->serviceMap = $serviceMap;
$this->parameterMap = $parameterMap;
}
public function compile(ExpressionCompiler $compiler, ExpressionInterface $expr)
{
if (isset($this->serviceMap[$expr->name])) {
$compiler->write("\$context['container']->get('{$this->serviceMap[$expr->name]}'");
if ($expr->allowNull) {
$compiler->write(", ".ContainerInterface::NULL_ON_INVALID_REFERENCE);
}
$compiler->write(")");
return;
}
if (isset($this->parameterMap[$expr->name])) {
$compiler->write("\$context['container']->getParameter('{$this->parameterMap[$expr->name]}')");
return;
}
parent::compile($compiler, $expr);
}
}

View File

@@ -0,0 +1,35 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Compiler\Func;
use JMS\SecurityExtraBundle\Exception\InvalidArgumentException;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\FunctionExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\ExpressionCompiler;
abstract class AuthenticationTrustFunctionCompiler implements FunctionCompilerInterface
{
public function compilePreconditions(ExpressionCompiler $compiler, FunctionExpression $function)
{
if (!empty($function->args)) {
throw new InvalidArgumentException(sprintf('The '.$this->getName().'() function does not accept any arguments, but got "%s".', var_export($function->args, true)));
}
$compiler->verifyItem('token', 'Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
}
}

View File

@@ -0,0 +1,29 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Compiler\Func;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\FunctionExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\ExpressionCompiler;
interface FunctionCompilerInterface
{
function getName();
function compilePreconditions(ExpressionCompiler $compiler, FunctionExpression $function);
function compile(ExpressionCompiler $compiler, FunctionExpression $function);
}

View File

@@ -0,0 +1,63 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Compiler\Func;
use JMS\SecurityExtraBundle\Exception\RuntimeException;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\FunctionExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\ExpressionCompiler;
class HasAnyRoleFunctionCompiler implements FunctionCompilerInterface
{
private $rolesExpr;
public function getName()
{
return 'hasAnyRole';
}
public function compilePreconditions(ExpressionCompiler $compiler, FunctionExpression $function)
{
if (0 === count($function->args)) {
throw new RuntimeException('The function hasAnyRole() expects at least one argument, but got none.');
}
$this->rolesExpr = $compiler->getRolesExpr();
}
public function compile(ExpressionCompiler $compiler, FunctionExpression $function)
{
$compiler->write("(");
$first = true;
foreach ($function->args as $arg) {
if (!$first) {
$compiler->write(" || ");
}
$first = false;
$compiler
->write("isset({$this->rolesExpr}[")
->compileInternal($arg)
->write("])")
;
}
$compiler->write(")");
}
}

View File

@@ -0,0 +1,51 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Compiler\Func;
use JMS\SecurityExtraBundle\Exception\RuntimeException;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\FunctionExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\ExpressionCompiler;
class HasRoleFunctionCompiler implements FunctionCompilerInterface
{
private $rolesExpr;
public function getName()
{
return 'hasRole';
}
public function compilePreconditions(ExpressionCompiler $compiler, FunctionExpression $function)
{
if (1 !== count($function->args)) {
throw new RuntimeException(sprintf('The hasRole() function expects exactly one argument, but got "%s".', var_export($function->args, true)));
}
$this->rolesExpr = $compiler->getRolesExpr();
}
public function compile(ExpressionCompiler $compiler, FunctionExpression $function)
{
$compiler
->write("isset({$this->rolesExpr}[")
->compileInternal($function->args[0])
->write("])")
;
}
}

View File

@@ -0,0 +1,39 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Compiler\Func;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\VariableExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\FunctionExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\ExpressionCompiler;
class IsAnonymousFunctionCompiler extends AuthenticationTrustFunctionCompiler
{
public function getName()
{
return 'isAnonymous';
}
public function compile(ExpressionCompiler $compiler, FunctionExpression $function)
{
$compiler
->compileInternal(new VariableExpression('trust_resolver'))
->write("->isAnonymous(\$context['token'])");
}
}

View File

@@ -0,0 +1,41 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Compiler\Func;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\VariableExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\FunctionExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\ExpressionCompiler;
class IsAuthenticatedFunctionCompiler extends AuthenticationTrustFunctionCompiler
{
public function getName()
{
return 'isAuthenticated';
}
public function compile(ExpressionCompiler $compiler, FunctionExpression $function)
{
$compiler
->write("!")
->compileInternal(new VariableExpression('trust_resolver'))
->write("->isAnonymous(\$context['token'])")
;
}
}

View File

@@ -0,0 +1,39 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Compiler\Func;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\VariableExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\FunctionExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\ExpressionCompiler;
class IsFullyAuthenticatedFunctionCompiler extends AuthenticationTrustFunctionCompiler
{
public function getName()
{
return 'isFullyAuthenticated';
}
public function compile(ExpressionCompiler $compiler, FunctionExpression $function)
{
$compiler
->compileInternal(new VariableExpression('trust_resolver'))
->write("->isFullFledged(\$context['token'])");
}
}

View File

@@ -0,0 +1,39 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Compiler\Func;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\VariableExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\FunctionExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\ExpressionCompiler;
class IsRememberMeFunctionCompiler extends AuthenticationTrustFunctionCompiler
{
public function getName()
{
return 'isRememberMe';
}
public function compile(ExpressionCompiler $compiler, FunctionExpression $function)
{
$compiler
->compileInternal(new VariableExpression('trust_resolver'))
->write("->isRememberMe(\$context['token'])");
}
}

View File

@@ -0,0 +1,32 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Compiler;
class IsEqualExpressionCompiler extends BinaryExprCompiler
{
public function getType()
{
return 'JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\IsEqualExpression';
}
protected function getOperator()
{
return '===';
}
}

View File

@@ -0,0 +1,44 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Compiler;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\ExpressionCompiler;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\ExpressionInterface;
class NotExpressionCompiler implements TypeCompilerInterface
{
public function getType()
{
return 'JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\NotExpression';
}
public function compilePreconditions(ExpressionCompiler $compiler, ExpressionInterface $expr)
{
$compiler->compilePreconditions($expr->expr);
}
public function compile(ExpressionCompiler $compiler, ExpressionInterface $expr)
{
$compiler
->write('!(')
->compileInternal($expr->expr)
->write(')')
;
}
}

View File

@@ -0,0 +1,32 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Compiler;
class OrExpressionCompiler extends BinaryExprCompiler
{
public function getType()
{
return 'JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\OrExpression';
}
protected function getOperator()
{
return '||';
}
}

View File

@@ -0,0 +1,80 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Compiler;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\VariableExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\ExpressionCompiler;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\ExpressionInterface;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Compiler\TypeCompilerInterface;
class ParameterExpressionCompiler implements TypeCompilerInterface
{
public function getType()
{
return 'JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\ParameterExpression';
}
public function compilePreconditions(ExpressionCompiler $compiler, ExpressionInterface $parameter)
{
$compiler->verifyItem('object', 'CG\Proxy\MethodInvocation');
if (!isset($compiler->attributes['parameter_mapping_name'])) {
$this->addParameterMapping($compiler);
}
$compiler
->writeln("if (!isset(\${$compiler->attributes['parameter_mapping_name']}['{$parameter->name}'])) {")
->indent()
->write("throw new RuntimeException(sprintf('There is no parameter with name \"{$parameter->name}\" for method \"%s\".', ")
->compileInternal(new VariableExpression('object'))
->writeln("));")
->outdent()
->write("}\n\n")
;
}
public function compile(ExpressionCompiler $compiler, ExpressionInterface $parameter)
{
$compiler
->compileInternal(new VariableExpression('object'))
->write("->arguments[")
->write("\${$compiler->attributes['parameter_mapping_name']}")
->write("['{$parameter->name}']]")
;
}
private function addParameterMapping(ExpressionCompiler $compiler)
{
$name = $compiler->nextName();
$indexName = $compiler->nextName();
$paramName = $compiler->nextName();
$compiler
->setAttribute('parameter_mapping_name', $name)
->writeln("\$$name = array();")
->write("foreach (")
->compileInternal(new VariableExpression('object'))
->writeln("->reflection->getParameters() as \$$indexName => \$$paramName) {")
->indent()
->writeln("\${$name}[\${$paramName}->name] = \$$indexName;")
->outdent()
->writeln("}\n")
;
}
}

View File

@@ -0,0 +1,29 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Compiler;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\ExpressionInterface;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\ExpressionCompiler;
interface TypeCompilerInterface
{
function getType();
function compilePreconditions(ExpressionCompiler $compiler, ExpressionInterface $expr);
function compile(ExpressionCompiler $compiler, ExpressionInterface $expr);
}

View File

@@ -0,0 +1,74 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression\Compiler;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\VariableExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\ExpressionInterface;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\ExpressionCompiler;
class VariableExpressionCompiler implements TypeCompilerInterface
{
public function getType()
{
return 'JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\VariableExpression';
}
public function compilePreconditions(ExpressionCompiler $compiler, ExpressionInterface $expr)
{
if ('user' === $expr->name) {
$compiler
->setAttribute('user_var_name', $name = $compiler->nextName())
->write("\$$name = ")
->compileInternal(new VariableExpression('token'))
->write("->getUser();\n\n")
;
}
}
public function compile(ExpressionCompiler $compiler, ExpressionInterface $expr)
{
if ('permitAll' === $expr->name) {
$compiler->write('true');
return;
}
if ('denyAll' === $expr->name) {
$compiler->write('false');
return;
}
if ('user' === $expr->name) {
$compiler->write("\${$compiler->attributes['user_var_name']}");
return;
}
if ($expr->allowNull) {
$compiler->write("(isset(\$context['{$expr->name}']) ? ");
}
$compiler->write("\$context['{$expr->name}']");
if ($expr->allowNull) {
$compiler->write(" : null)");
}
}
}

View File

@@ -0,0 +1,47 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\ExpressionHandlerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Lazy-loading container aware expression handler.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ContainerAwareExpressionHandler implements ExpressionHandlerInterface
{
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function createContext(TokenInterface $token, $object)
{
return array(
'container' => $this->container,
'token' => $token,
'object' => $object,
);
}
}

View File

@@ -0,0 +1,51 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
class DefaultExpressionHandler implements ExpressionHandlerInterface
{
private $trustResolver;
private $roleHierarchy;
public function __construct(AuthenticationTrustResolverInterface $trustResolver,
RoleHierarchyInterface $roleHierarchy = null)
{
$this->trustResolver = $trustResolver;
$this->roleHierarchy = $roleHierarchy;
}
public function createContext(TokenInterface $token, $object)
{
$context = array(
'token' => $token,
'object' => $object,
'trust_resolver' => $this->trustResolver,
);
if (null !== $this->roleHierarchy) {
$context['role_hierarchy'] = $this->roleHierarchy;
}
return $context;
}
}

View File

@@ -0,0 +1,40 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression;
final class Expression
{
/** READ-ONLY */
public $expression;
public function __construct($expression)
{
$this->expression = $expression;
}
public function getHashCode()
{
return sha1($this->expression);
}
public function __toString()
{
return 'EXPRESSION('.$this->expression.')';
}
}

View File

@@ -0,0 +1,395 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression;
use JMS\SecurityExtraBundle\Exception\RuntimeException;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Compiler\TypeCompilerInterface;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\IsEqualExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Compiler\Func\FunctionCompilerInterface;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\ExpressionInterface;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\VariableExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\OrExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\MethodCallExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\GetPropertyExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\GetItemExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\FunctionExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\ConstantExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\ArrayExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\AndExpression;
class ExpressionCompiler
{
public $attributes = array();
private $indentationLevel = 0;
private $indentationSpaces = 4;
private $nameCount = 0;
private $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
private $charCount = 52;
private $reservedNames = array('context' => true);
private $itemExists = array();
private $itemType = array();
private $rolesName;
private $code;
private $parser;
private $typeCompilers;
private $functionCompilers;
public function __construct()
{
$this->addTypeCompiler(new Compiler\AndExpressionCompiler());
$this->addTypeCompiler(new Compiler\IsEqualExpressionCompiler());
$this->addTypeCompiler(new Compiler\OrExpressionCompiler());
$this->addTypeCompiler(new Compiler\VariableExpressionCompiler());
$this->addTypeCompiler(new Compiler\NotExpressionCompiler());
$this->functionCompilers = array(
'isAnonymous' => new Compiler\Func\IsAnonymousFunctionCompiler(),
'isAuthenticated' => new Compiler\Func\IsAuthenticatedFunctionCompiler(),
'isRememberMe' => new Compiler\Func\IsRememberMeFunctionCompiler(),
'isFullyAuthenticated' => new Compiler\Func\IsFullyAuthenticatedFunctionCompiler(),
'hasRole' => new Compiler\Func\HasRoleFunctionCompiler(),
'hasAnyRole' => new Compiler\Func\HasAnyRoleFunctionCompiler(),
);
}
public function setAttribute($name, $value)
{
$this->attributes[$name] = $value;
return $this;
}
public function addTypeCompiler(TypeCompilerInterface $compiler)
{
$this->typeCompilers[$compiler->getType()] = $compiler;
}
public function addFunctionCompiler(FunctionCompilerInterface $compiler)
{
$this->functionCompilers[$compiler->getName()] = $compiler;
}
public function compileExpression(Expression $expr)
{
return $this->compile($this->getParser()->parse($expr->expression),
$expr->expression);
}
public function compile(ExpressionInterface $expr, $raw = null)
{
$this->nameCount = 0;
$this->code = '';
$this->itemExists = $this->itemType = $this->attributes = array();
$this->rolesName = null;
if ($raw) {
$this->writeln('// Expression: '.$raw);
}
$this
->writeln('return function(array $context) {')
->indent()
->compilePreconditions($expr)
->write('return ')
->compileInternal($expr)
->writeln(';')
->outdent()
->writeln('};')
;
return $this->code;
}
public function indent()
{
$this->indentationLevel += 1;
return $this;
}
public function outdent()
{
$this->indentationLevel -= 1;
if ($this->indentationLevel < 0) {
throw new RuntimeException('The identation level cannot be less than zero.');
}
return $this;
}
public function writeln($content)
{
$this->write($content."\n");
return $this;
}
public function getRolesExpr()
{
if (null !== $this->rolesName) {
return '$'.$this->rolesName;
}
$this->verifyItem('token', 'Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
$this->rolesName = $rolesName = $this->nextName();
$hierarchyName = $this->nextName();
$tmpName = $this->nextName();
$this
->writeln("\$$rolesName = \$context['token']->getRoles();")
->write("if (null !== \$$hierarchyName = ")
->compileInternal(new VariableExpression('role_hierarchy', true))
->writeln(") {")
->indent()
->writeln("\$$rolesName = \${$hierarchyName}->getReachableRoles(\$$rolesName);")
->outdent()
->write("}\n\n")
->writeln("\$$tmpName = array();")
->writeln("foreach (\$$rolesName as \$role) {")
->indent()
->writeln("\${$tmpName}[\$role->getRole()] = true;")
->outdent()
->writeln("}")
->write("\$$rolesName = \$$tmpName;\n\n")
;
return '$'.$rolesName;
}
public function verifyItem($key, $expectedType = null)
{
if (!isset($this->itemExists[$key])) {
$this->itemExists[$key] = true;
$this
->writeln("if (!isset(\$context['$key'])) {")
->indent()
->writeln("throw new RuntimeException('The context contains no item with key \"$key\".');")
->outdent()
->write("}\n\n")
;
}
if (null !== $expectedType) {
if (isset($this->itemType[$key])) {
if ($this->itemType[$key] !== $expectedType) {
throw new RuntimeException(sprintf('Cannot verify that item "%s" is of type "%s" because it is already expected to be of type "%s".',
$key, $expectedType, $this->itemType[$key]
));
}
return $this;
}
$this
->writeln("if (!\$context['$key'] instanceof $expectedType) {")
->indent()
->writeln("throw new RuntimeException(sprintf('The item \"$key\" is expected to be of type \"$expectedType\", but got \"%s\".', get_class(\$context['$key'])));")
->outdent()
->write("}\n\n")
;
}
return $this;
}
public function write($content)
{
$lines = explode("\n", $content);
for ($i=0,$c=count($lines); $i<$c; $i++) {
if ($this->indentationLevel > 0
&& !empty($lines[$i])
&& (empty($this->code) || "\n" === substr($this->code, -1))) {
$this->code .= str_repeat(' ', $this->indentationLevel * $this->indentationSpaces);
}
$this->code .= $lines[$i];
if ($i+1 < $c) {
$this->code .= "\n";
}
}
return $this;
}
public function nextName()
{
while (true) {
$name = '';
$i = $this->nameCount;
$name .= $this->chars[$i % $this->charCount];
$i = intval($i / $this->charCount);
while ($i > 0) {
$i -= 1;
$name .= $this->chars[$i % $this->charCount];
$i = intval($i / $this->charCount);
}
$this->nameCount += 1;
// check that the name is not reserved
if (isset($this->reservedNames[$name])) {
continue;
}
return $name;
}
}
public function compilePreconditions(ExpressionInterface $expr)
{
if ($typeCompiler = $this->findTypeCompiler(get_class($expr))) {
$typeCompiler->compilePreconditions($this, $expr);
return $this;
}
if ($expr instanceof FunctionExpression) {
$this->getFunctionCompiler($expr->name)->compilePreconditions($this, $expr);
foreach ($expr->args as $arg) {
$this->compilePreconditions($arg);
}
return $this;
}
if ($expr instanceof VariableExpression) {
$this->getVariableCompiler($expr->name)->compilePreconditions($this, $expr);
return $this;
}
if ($expr instanceof MethodCallExpression) {
$this->compilePreconditions($expr->object);
foreach ($expr->args as $arg) {
$this->compilePreconditions($arg);
}
return $this;
}
if ($expr instanceof GetPropertyExpression) {
$this->compilePreconditions($expr->object);
return $this;
}
return $this;
}
public function compileInternal(ExpressionInterface $expr)
{
if ($typeCompiler = $this->findTypeCompiler(get_class($expr))) {
$typeCompiler->compile($this, $expr);
return $this;
}
if ($expr instanceof ArrayExpression) {
$this->code .= 'array(';
foreach ($expr->elements as $key => $value) {
$this->code .= var_export($key, true).' => ';
$this->compileInternal($value);
$this->code .= ',';
}
$this->code .= ')';
return $this;
}
if ($expr instanceof ConstantExpression) {
$this->code .= var_export($expr->value, true);
return $this;
}
if ($expr instanceof FunctionExpression) {
$this->getFunctionCompiler($expr->name)->compile($this, $expr);
return $this;
}
if ($expr instanceof GetItemExpression) {
$this->compileInternal($expr->array);
$this->code .= '['.$expr->key.']';
return $this;
}
if ($expr instanceof GetPropertyExpression) {
$this->compileInternal($expr->object);
$this->code .= '->'.$expr->name;
return $this;
}
if ($expr instanceof MethodCallExpression) {
$this->compileInternal($expr->object);
$this->code .= '->'.$expr->method.'(';
$first = true;
foreach ($expr->args as $arg) {
if (!$first) {
$this->code .= ', ';
}
$first = false;
$this->compileInternal($arg);
}
$this->code .= ')';
return $this;
}
throw new RuntimeException(sprintf('Unknown expression "%s".', get_class($expr)));
}
public function getFunctionCompiler($name)
{
if (!isset($this->functionCompilers[$name])) {
throw new RuntimeException(sprintf('There is no compiler for function "%s".', $name));
}
return $this->functionCompilers[$name];
}
private function findTypeCompiler($type)
{
return isset($this->typeCompilers[$type]) ? $this->typeCompilers[$type] : null;
}
private function getParser()
{
if (null !== $this->parser) {
return $this->parser;
}
return $this->parser = new ExpressionParser();
}
}

View File

@@ -0,0 +1,26 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
interface ExpressionHandlerInterface
{
function createContext(TokenInterface $token, $object);
}

View File

@@ -0,0 +1,134 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression;
use JMS\SecurityExtraBundle\Exception\InvalidArgumentException;
final class ExpressionLexer
{
public $token;
public $lookahead;
private $tokens;
private $pointer;
const T_STRING = 1;
const T_IDENTIFIER = 2;
const T_NONE = 3;
const T_COMMA = 4;
const T_OPEN_PARENTHESIS = 5;
const T_CLOSE_PARENTHESIS = 6;
const T_AND = 7;
const T_OR = 8;
const T_PARAMETER = 9;
const T_OBJECT_OPERATOR = 10;
const T_OPEN_BRACKET = 11;
const T_CLOSE_BRACKET = 12;
const T_OPEN_BRACE = 13;
const T_CLOSE_BRACE = 14;
const T_COLON = 15;
const T_IS_EQUAL = 16;
const T_NOT = 17;
public static function getLiteral($type)
{
static $constants;
if (null === $constants) {
$ref = new \ReflectionClass(get_called_class());
$constants = $ref->getConstants();
}
if (false === $literal = array_search($type, $constants, true)) {
throw new InvalidArgumentException(sprintf('There is no token of value "%s".', $type));
}
return $literal;
}
public function initialize($input)
{
static $pattern = '/(#?[a-z][a-z0-9]*|\'(?:[^\']|(?<=\\\\)\')*\'|"(?:[^"]|(?<=\\\\)")*"|&&|\|\||==)|\s+|(.)/i';
$parts = preg_split($pattern, $input, -1, PREG_SPLIT_OFFSET_CAPTURE
| PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
$tokens = array();
foreach ($parts as $part) {
list($value, $position) = $part;
$type = self::T_NONE;
if ("'" === $value[0] || '"' === $value[0]) {
$type = self::T_STRING;
$value = substr($value, 1, -1);
} else if (',' === $value) {
$type = self::T_COMMA;
} else if ('(' === $value) {
$type = self::T_OPEN_PARENTHESIS;
} else if (')' === $value) {
$type = self::T_CLOSE_PARENTHESIS;
} else if ('[' === $value) {
$type = self::T_OPEN_BRACKET;
} else if (']' === $value) {
$type = self::T_CLOSE_BRACKET;
} else if ('{' === $value) {
$type = self::T_OPEN_BRACE;
} else if ('}' === $value) {
$type = self::T_CLOSE_BRACE;
} else if ('&&' === $value || 'and' === strtolower($value)) {
$type = self::T_AND;
} else if ('||' === $value || 'or' === strtolower($value)) {
$type = self::T_OR;
} else if ('!' === $value || 'not' === strtolower($value)) {
$type = self::T_NOT;
} else if (':' === $value) {
$type = self::T_COLON;
} else if ('.' === $value) {
$type = self::T_OBJECT_OPERATOR;
} else if ('==' === $value) {
$type = self::T_IS_EQUAL;
} else if ('#' === $value[0]) {
$type = self::T_PARAMETER;
$value = substr($value, 1);
} else if (ctype_alpha($value)) {
$type = self::T_IDENTIFIER;
}
$tokens[] = array(
'type' => $type,
'value' => $value,
'position' => $position,
);
}
$this->tokens = $tokens;
$this->pointer = -1;
$this->next();
}
public function next()
{
$this->pointer += 1;
$this->token = $this->lookahead;
$this->lookahead = isset($this->tokens[$this->pointer]) ?
$this->tokens[$this->pointer] : null;
return $this->lookahead !== null;
}
}

View File

@@ -0,0 +1,290 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\NotExpression;
use JMS\SecurityExtraBundle\Exception\RuntimeException;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\IsEqualExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\ParameterExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\VariableExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\ConstantExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\OrExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\AndExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\ArrayExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\GetItemExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\GetPropertyExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\MethodCallExpression;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\ExpressionInterface;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\FunctionExpression;
final class ExpressionParser
{
const PRECEDENCE_OR = 10;
const PRECEDENCE_AND = 15;
const PRECEDENCE_IS_EQUAL = 20;
const PRECEDENCE_NOT = 30;
private $lexer;
public function __construct()
{
$this->lexer = new ExpressionLexer();
}
public function parse($str)
{
$this->lexer->initialize($str);
return $this->Expression();
}
private function Expression($precedence = 0)
{
$expr = $this->Primary();
while (true) {
if (ExpressionLexer::T_AND === $this->lexer->lookahead['type']
&& $precedence <= self::PRECEDENCE_AND) {
$this->lexer->next();
$expr = new AndExpression($expr, $this->Expression(
self::PRECEDENCE_AND + 1));
continue;
}
if (ExpressionLexer::T_OR === $this->lexer->lookahead['type']
&& $precedence <= self::PRECEDENCE_OR) {
$this->lexer->next();
$expr = new OrExpression($expr, $this->Expression(
self::PRECEDENCE_OR + 1));
continue;
}
if (ExpressionLexer::T_IS_EQUAL === $this->lexer->lookahead['type']
&& $precedence <= self::PRECEDENCE_IS_EQUAL) {
$this->lexer->next();
$expr = new IsEqualExpression($expr, $this->Expression(
self::PRECEDENCE_IS_EQUAL + 1));
continue;
}
break;
}
return $expr;
}
private function Primary()
{
if (ExpressionLexer::T_NOT === $this->lexer->lookahead['type']) {
$this->lexer->next();
$expr = new NotExpression($this->Expression(self::PRECEDENCE_NOT));
return $this->Suffix($expr);
}
if (ExpressionLexer::T_OPEN_PARENTHESIS === $this->lexer->lookahead['type']) {
$this->lexer->next();
$expr = $this->Expression();
$this->match(ExpressionLexer::T_CLOSE_PARENTHESIS);
return $this->Suffix($expr);
}
if (ExpressionLexer::T_STRING === $this->lexer->lookahead['type']) {
return new ConstantExpression($this->match(ExpressionLexer::T_STRING));
}
if (ExpressionLexer::T_OPEN_BRACE === $this->lexer->lookahead['type']) {
return $this->Suffix($this->MapExpr());
}
if (ExpressionLexer::T_OPEN_BRACKET === $this->lexer->lookahead['type']) {
return $this->Suffix($this->ListExpr());
}
if (ExpressionLexer::T_IDENTIFIER === $this->lexer->lookahead['type']) {
$name = $this->match(ExpressionLexer::T_IDENTIFIER);
if (ExpressionLexer::T_OPEN_PARENTHESIS === $this->lexer->lookahead['type']) {
$args = $this->Arguments();
return $this->Suffix(new FunctionExpression($name, $args));
}
return $this->Suffix(new VariableExpression($name));
}
if (ExpressionLexer::T_PARAMETER === $this->lexer->lookahead['type']) {
return $this->Suffix(new ParameterExpression($this->match(ExpressionLexer::T_PARAMETER)));
}
$this->error('primary expression');
}
private function ListExpr()
{
$this->match(ExpressionLexer::T_OPEN_BRACKET);
$elements = array();
while (ExpressionLexer::T_CLOSE_BRACKET !== $this->lexer->lookahead['type']) {
$elements[] = $this->Expression();
if (ExpressionLexer::T_COMMA !== $this->lexer->lookahead['type']) {
break;
}
$this->lexer->next();
}
$this->match(ExpressionLexer::T_CLOSE_BRACKET);
return new ArrayExpression($elements);
}
private function MapExpr()
{
$this->match(ExpressionLexer::T_OPEN_BRACE);
$entries = array();
while (ExpressionLexer::T_CLOSE_BRACE !== $this->lexer->lookahead['type']) {
$key = $this->match(ExpressionLexer::T_STRING);
$this->match(ExpressionLexer::T_COLON);
$entries[$key] = $this->Expression();
if (ExpressionLexer::T_COMMA !== $this->lexer->lookahead['type']) {
break;
}
$this->lexer->next();
}
$this->match(ExpressionLexer::T_CLOSE_BRACE);
return new ArrayExpression($entries);
}
private function Suffix(ExpressionInterface $expr)
{
while (true) {
if (ExpressionLexer::T_OBJECT_OPERATOR === $this->lexer->lookahead['type']) {
$this->lexer->next();
$name = $this->match(ExpressionLexer::T_IDENTIFIER);
if (ExpressionLexer::T_OPEN_PARENTHESIS === $this->lexer->lookahead['type']) {
$args = $this->Arguments();
$expr = new MethodCallExpression($expr, $name, $args);
continue;
}
$expr = new GetPropertyExpression($expr, $name);
continue;
}
if (ExpressionLexer::T_OPEN_BRACKET === $this->lexer->lookahead['type']) {
$this->lexer->next();
$key = $this->Expression();
$this->match(ExpressionLexer::T_CLOSE_BRACKET);
$expr = new GetItemExpression($expr, $key);
continue;
}
break;
}
return $expr;
}
private function FunctionCall()
{
$name = $this->match(ExpressionLexer::T_IDENTIFIER);
$args = $this->Arguments();
return new FunctionExpression($name, $args);
}
private function Arguments()
{
$this->match(ExpressionLexer::T_OPEN_PARENTHESIS);
$args = array();
while (ExpressionLexer::T_CLOSE_PARENTHESIS !== $this->lexer->lookahead['type']) {
$args[] = $this->Expression();
if (ExpressionLexer::T_COMMA !== $this->lexer->lookahead['type']) {
break;
}
$this->match(ExpressionLexer::T_COMMA);
}
$this->match(ExpressionLexer::T_CLOSE_PARENTHESIS);
return $args;
}
private function Value()
{
return $this->matchAny(array(ExpressionLexer::T_STRING));
}
private function matchAny(array $types)
{
if (null !== $this->lexer->lookahead) {
foreach ($types as $type) {
if ($type === $this->lexer->lookahead['type']) {
$this->lexer->next();
return $this->lexer->token['value'];
}
}
}
$this->error(sprintf('one of these tokens "%s"',
implode('", "', array_map(array('JMS\SecurityExtraBundle\Security\Authorization\Expression\Lexer', 'getLiteral'), $types))
));
}
private function match($type)
{
if (null === $this->lexer->lookahead
|| $type !== $this->lexer->lookahead['type']) {
$this->error(sprintf('token "%s"', ExpressionLexer::getLiteral($type)));
}
$this->lexer->next();
return $this->lexer->token['value'];
}
private function error($expected)
{
$actual = null === $this->lexer->lookahead ? 'end of file'
: sprintf('token "%s" with value "%s" at position %d',
ExpressionLexer::getLiteral($this->lexer->lookahead['type']),
$this->lexer->lookahead['value'],
$this->lexer->lookahead['position']);
throw new RuntimeException(sprintf('Expected %s, but got %s.', $expected, $actual));
}
}

View File

@@ -0,0 +1,114 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression;
use JMS\SecurityExtraBundle\Exception\RuntimeException;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
/**
* Expression-based voter.
*
* This voter allows to use complex access expression in a high-performance
* way. This is the preferred voter for any non-simple access checks.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ExpressionVoter implements VoterInterface
{
private $evaluators = array();
private $compiler;
private $cacheDir;
private $expressionHandler;
public function __construct(ExpressionHandlerInterface $expressionHandler) {
$this->expressionHandler = $expressionHandler;
}
public function setCacheDir($cacheDir)
{
$this->cacheDir = $cacheDir;
}
public function setCompiler(ExpressionCompiler $compiler)
{
$this->compiler = $compiler;
}
public function vote(TokenInterface $token, $object, array $attributes)
{
$result = VoterInterface::ACCESS_ABSTAIN;
foreach ($attributes as $attribute) {
if (!$attribute instanceof Expression) {
continue;
}
$result = VoterInterface::ACCESS_DENIED;
if (!isset($this->evaluators[$attribute->expression])) {
$this->evaluators[$attribute->expression] =
$this->createEvaluator($attribute);
}
if (call_user_func($this->evaluators[$attribute->expression],
$this->expressionHandler->createContext($token, $object))) {
return VoterInterface::ACCESS_GRANTED;
}
}
return $result;
}
public function supportsAttribute($attribute)
{
return $attribute instanceof Expression;
}
public function supportsClass($class)
{
return true;
}
protected function getCompiler()
{
if (null === $this->compiler) {
throw new RuntimeException('A compiler must be set.');
}
return $this->compiler;
}
private function createEvaluator(Expression $expr)
{
if ($this->cacheDir) {
if (is_file($file = $this->cacheDir.'/'.sha1($expr->expression).'.php')) {
return require $file;
}
$source = $this->getCompiler()->compileExpression($expr);
file_put_contents($file, "<?php\n".$source);
return require $file;
}
return eval($this->getCompiler()->compileExpression($expr));
}
}

View File

@@ -0,0 +1,39 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Expression;
use Symfony\Component\DependencyInjection\ContainerInterface;
use JMS\SecurityExtraBundle\Security\Authorization\Expression\ExpressionVoter;
class LazyLoadingExpressionVoter extends ExpressionVoter
{
private $container;
private $compilerId;
public function setLazyCompiler(ContainerInterface $container, $id)
{
$this->container = $container;
$this->compilerId = $id;
}
protected function getCompiler()
{
return $this->container->get($this->compilerId);
}
}

View File

@@ -0,0 +1,150 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Interception;
use JMS\SecurityExtraBundle\Exception\RuntimeException;
use CG\Core\ClassUtils;
use CG\Proxy\MethodInterceptorInterface;
use CG\Proxy\MethodInvocation;
use JMS\SecurityExtraBundle\Metadata\MethodMetadata;
use JMS\SecurityExtraBundle\Security\Authentication\Token\RunAsUserToken;
use JMS\SecurityExtraBundle\Security\Authorization\AfterInvocation\AfterInvocationManagerInterface;
use JMS\SecurityExtraBundle\Security\Authorization\RunAsManagerInterface;
use Metadata\MetadataFactoryInterface;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
/**
* All invocations of secure methods will go through this class.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class MethodSecurityInterceptor implements MethodInterceptorInterface
{
private $alwaysAuthenticate;
private $securityContext;
private $metadataFactory;
private $authenticationManager;
private $accessDecisionManager;
private $afterInvocationManager;
private $runAsManager;
private $logger;
public function __construct(SecurityContext $securityContext, AuthenticationManagerInterface $authenticationManager, AccessDecisionManagerInterface $accessDecisionManager,
AfterInvocationManagerInterface $afterInvocationManager, RunAsManagerInterface $runAsManager, MetadataFactoryInterface $metadataFactory, LoggerInterface $logger = null)
{
$this->alwaysAuthenticate = false;
$this->securityContext = $securityContext;
$this->metadataFactory = $metadataFactory;
$this->authenticationManager = $authenticationManager;
$this->accessDecisionManager = $accessDecisionManager;
$this->afterInvocationManager = $afterInvocationManager;
$this->runAsManager = $runAsManager;
$this->logger = $logger;
}
public function setAlwaysAuthenticate($boolean)
{
$this->alwaysAuthenticate = !!$boolean;
}
public function intercept(MethodInvocation $method)
{
$metadata = $this->metadataFactory->getMetadataForClass($method->reflection->class);
// no security metadata, proceed
if (empty($metadata) || !isset($metadata->methodMetadata[$method->reflection->name])) {
return $method->proceed();
}
$metadata = $metadata->methodMetadata[$method->reflection->name];
if (null === $token = $this->securityContext->getToken()) {
throw new AuthenticationCredentialsNotFoundException(
'The security context was not populated with a Token.'
);
}
if ($this->alwaysAuthenticate || !$token->isAuthenticated()) {
$token = $this->authenticationManager->authenticate($token);
$this->securityContext->setToken($token);
}
if (!empty($metadata->roles) && false === $this->accessDecisionManager->decide($token, $metadata->roles, $method)) {
throw new AccessDeniedException('Token does not have the required roles.');
}
if (!empty($metadata->paramPermissions)) {
foreach ($method->arguments as $index => $argument) {
if (null !== $argument && isset($metadata->paramPermissions[$index]) && false === $this->accessDecisionManager->decide($token, $metadata->paramPermissions[$index], $argument)) {
throw new AccessDeniedException(sprintf('Token does not have the required permissions for method "%s::%s".', $method->reflection->class, $method->reflection->name));
}
}
}
$runAsToken = null;
if (!empty($metadata->runAsRoles)) {
$runAsToken = $this->runAsManager->buildRunAs($token, $method, $metadata->runAsRoles);
if (null !== $this->logger) {
$this->logger->debug('Populating security context with RunAsToken');
}
if (null === $runAsToken) {
throw new RuntimeException('RunAsManager must not return null from buildRunAs().');
}
$this->securityContext->setToken($runAsToken);
}
try {
$returnValue = $method->proceed();
if (null !== $runAsToken) {
$this->restoreOriginalToken($runAsToken);
}
if (empty($metadata->returnPermissions)) {
return $returnValue;
}
return $this->afterInvocationManager->decide($this->securityContext->getToken(), $method, $metadata->returnPermissions, $returnValue);
} catch (\Exception $failed) {
if (null !== $runAsToken) {
$this->restoreOriginalToken($runAsToken);
}
throw $failed;
}
}
private function restoreOriginalToken(RunAsUserToken $runAsToken)
{
if (null !== $this->logger) {
$this->logger->debug('Populating security context with original Token.');
}
$this->securityContext->setToken($runAsToken->getOriginalToken());
}
}

View File

@@ -0,0 +1,92 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Interception;
use CG\Core\ClassUtils;
use Metadata\MetadataFactoryInterface;
use JMS\AopBundle\Aop\PointcutInterface;
class SecurityPointcut implements PointcutInterface
{
private $metadataFactory;
private $secureAllServices;
private $securedClasses = array();
private $patterns;
public function __construct(MetadataFactoryInterface $metadataFactory, $secureAllServices = false, array $patterns = array())
{
$this->metadataFactory = $metadataFactory;
$this->secureAllServices = $secureAllServices;
$this->patterns = $patterns;
}
public function setSecuredClasses(array $classes)
{
$this->securedClasses = $classes;
}
public function matchesClass(\ReflectionClass $class)
{
if ($this->secureAllServices) {
return true;
}
if ('Controller' === substr(ClassUtils::getUserClass($class->name), -10)) {
return true;
}
foreach ($this->patterns as $pattern => $expr) {
// if not for all patterns the class is specified, then we need to scan all
// classes to catch all methods
if (false === $pos = strpos($pattern, '::')) {
// controller notation is already checked by JMSDiExtraBundle,
// we can safely ignore these patterns here
if (2 === substr_count($pattern, ':')) {
continue;
}
return true;
}
if (0 < preg_match('#'.substr($pattern, 0, $pos).'$#', $class->name)) {
return true;
}
}
foreach ($this->securedClasses as $securedClass) {
if ($class->name === $securedClass || $class->isSubclassOf($securedClass)) {
return true;
}
}
return false;
}
public function matchesMethod(\ReflectionMethod $method)
{
$userClass = ClassUtils::getUserClass($method->class);
$metadata = $this->metadataFactory->getMetadataForClass($userClass);
if (null === $metadata) {
return false;
}
return isset($metadata->methodMetadata[$method->name]);
}
}

View File

@@ -0,0 +1,79 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization;
use JMS\SecurityExtraBundle\Security\Authentication\Token\RunAsUserToken;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* The RunAsManager creates throw-away Tokens which are temporarily injected into
* the security context for the duration of the invocation of a specific method.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class RunAsManager implements RunAsManagerInterface
{
private $key;
private $rolePrefix;
public function __construct($key, $rolePrefix = 'ROLE_')
{
$this->key = $key;
$this->rolePrefix = $rolePrefix;
}
/**
* {@inheritDoc}
*/
public function buildRunAs(TokenInterface $token, $secureObject, array $attributes)
{
$roles = array();
foreach ($attributes as $attribute)
{
if ($this->supportsAttribute($attribute)) {
$roles[] = new Role($attribute);
}
}
if (0 === count($roles)) {
return null;
}
$roles = array_merge($roles, $token->getRoles());
return new RunAsUserToken($this->key, $token->getUser(), $token->getCredentials(), $roles, $token);
}
/**
* {@inheritDoc}
*/
public function supportsAttribute($attribute)
{
return !empty($attribute) && 0 === strpos($attribute, $this->rolePrefix);
}
/**
* {@inheritDoc}
*/
public function supportsClass($className)
{
return true;
}
}

View File

@@ -0,0 +1,57 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* RunAsManagerInterface
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
interface RunAsManagerInterface
{
/**
* Creates a temporary RunAsToken.
*
* The returned Token must have a complementing AuthenticationProvider implementation.
*
* @param TokenInterface $token the original Token
* @param object $secureObject the secure object which caused this call
* @param array $attributes an array of attributes to apply to the built token
* @return TokenInterface
*/
function buildRunAs(TokenInterface $token, $secureObject, array $attributes);
/**
* Whether this RunAsManager supports the given attribute
*
* @param string $attribute
* @return Boolean
*/
function supportsAttribute($attribute);
/**
* Whether this RunAsManager supports the given class.
*
* @param string $className The class of the secure object which requests RunAs capabilities
* @return Boolean
*/
function supportsClass($className);
}

View File

@@ -0,0 +1,61 @@
<?php
/*
* Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
*
* 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\Authorization\Voter;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
/**
* This voter adds a special role "ROLE_IDDQD" which effectively bypasses any,
* and all security checks.
*
* Most of the time, you will want to use this rule in combination with a
* @RunAs annotation to disable security checks for the invocation of a
* specific method.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class IddqdVoter implements VoterInterface
{
public function vote(TokenInterface $token, $object, array $attributes)
{
return $this->isIddqd($token) ? VoterInterface::ACCESS_GRANTED : VoterInterface::ACCESS_ABSTAIN;
}
protected function isIddqd(TokenInterface $token)
{
foreach ($token->getRoles() as $role) {
if ('ROLE_IDDQD' === $role->getRole()) {
return true;
}
}
return false;
}
public function supportsAttribute($attribute)
{
return true;
}
public function supportsClass($class)
{
return true;
}
}