added support for expression in control access rules
This commit is contained in:
parent
2777ac7854
commit
38b7fde8ed
@ -169,6 +169,7 @@ class MainConfiguration implements ConfigurationInterface
|
|||||||
->beforeNormalization()->ifString()->then(function($v) { return preg_split('/\s*,\s*/', $v); })->end()
|
->beforeNormalization()->ifString()->then(function($v) { return preg_split('/\s*,\s*/', $v); })->end()
|
||||||
->prototype('scalar')->end()
|
->prototype('scalar')->end()
|
||||||
->end()
|
->end()
|
||||||
|
->scalarNode('allow_if')->defaultNull()->end()
|
||||||
->end()
|
->end()
|
||||||
->fixXmlConfig('role')
|
->fixXmlConfig('role')
|
||||||
->children()
|
->children()
|
||||||
|
@ -23,6 +23,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
|
|||||||
use Symfony\Component\DependencyInjection\Reference;
|
use Symfony\Component\DependencyInjection\Reference;
|
||||||
use Symfony\Component\DependencyInjection\Parameter;
|
use Symfony\Component\DependencyInjection\Parameter;
|
||||||
use Symfony\Component\Config\FileLocator;
|
use Symfony\Component\Config\FileLocator;
|
||||||
|
use Symfony\Component\ExpressionLanguage\Expression;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SecurityExtension.
|
* SecurityExtension.
|
||||||
@ -33,6 +34,7 @@ use Symfony\Component\Config\FileLocator;
|
|||||||
class SecurityExtension extends Extension
|
class SecurityExtension extends Extension
|
||||||
{
|
{
|
||||||
private $requestMatchers = array();
|
private $requestMatchers = array();
|
||||||
|
private $expressions = array();
|
||||||
private $contextListeners = array();
|
private $contextListeners = array();
|
||||||
private $listenerPositions = array('pre_auth', 'form', 'http', 'remember_me');
|
private $listenerPositions = array('pre_auth', 'form', 'http', 'remember_me');
|
||||||
private $factories = array();
|
private $factories = array();
|
||||||
@ -188,8 +190,13 @@ class SecurityExtension extends Extension
|
|||||||
$access['ips']
|
$access['ips']
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$attributes = $access['roles'];
|
||||||
|
if ($access['allow_if']) {
|
||||||
|
$attributes[] = $this->createExpression($container, $access['allow_if']);
|
||||||
|
}
|
||||||
|
|
||||||
$container->getDefinition('security.access_map')
|
$container->getDefinition('security.access_map')
|
||||||
->addMethodCall('add', array($matcher, $access['roles'], $access['requires_channel']));
|
->addMethodCall('add', array($matcher, $attributes, $access['requires_channel']));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,6 +603,21 @@ class SecurityExtension extends Extension
|
|||||||
return $switchUserListenerId;
|
return $switchUserListenerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function createExpression($container, $expression)
|
||||||
|
{
|
||||||
|
if (isset($this->expressions[$id = 'security.expression.'.sha1($expression)])) {
|
||||||
|
return $this->expressions[$id];
|
||||||
|
}
|
||||||
|
|
||||||
|
$container
|
||||||
|
->register($id, 'Symfony\Component\ExpressionLanguage\Expression')
|
||||||
|
->setPublic(false)
|
||||||
|
->addArgument($expression)
|
||||||
|
;
|
||||||
|
|
||||||
|
return $this->expressions[$id] = new Reference($id);
|
||||||
|
}
|
||||||
|
|
||||||
private function createRequestMatcher($container, $path = null, $host = null, $methods = array(), $ip = null, array $attributes = array())
|
private function createRequestMatcher($container, $path = null, $host = null, $methods = array(), $ip = null, array $attributes = array())
|
||||||
{
|
{
|
||||||
$serialized = serialize(array($path, $host, $methods, $ip, $attributes));
|
$serialized = serialize(array($path, $host, $methods, $ip, $attributes));
|
||||||
|
@ -32,17 +32,21 @@
|
|||||||
<parameter key="security.access.simple_role_voter.class">Symfony\Component\Security\Core\Authorization\Voter\RoleVoter</parameter>
|
<parameter key="security.access.simple_role_voter.class">Symfony\Component\Security\Core\Authorization\Voter\RoleVoter</parameter>
|
||||||
<parameter key="security.access.authenticated_voter.class">Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter</parameter>
|
<parameter key="security.access.authenticated_voter.class">Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter</parameter>
|
||||||
<parameter key="security.access.role_hierarchy_voter.class">Symfony\Component\Security\Core\Authorization\Voter\RoleHierarchyVoter</parameter>
|
<parameter key="security.access.role_hierarchy_voter.class">Symfony\Component\Security\Core\Authorization\Voter\RoleHierarchyVoter</parameter>
|
||||||
|
<parameter key="security.access.expression_voter.class">Symfony\Component\Security\Core\Authorization\Voter\ExpressionVoter</parameter>
|
||||||
|
|
||||||
<parameter key="security.firewall.class">Symfony\Component\Security\Http\Firewall</parameter>
|
<parameter key="security.firewall.class">Symfony\Component\Security\Http\Firewall</parameter>
|
||||||
<parameter key="security.firewall.map.class">Symfony\Bundle\SecurityBundle\Security\FirewallMap</parameter>
|
<parameter key="security.firewall.map.class">Symfony\Bundle\SecurityBundle\Security\FirewallMap</parameter>
|
||||||
<parameter key="security.firewall.context.class">Symfony\Bundle\SecurityBundle\Security\FirewallContext</parameter>
|
<parameter key="security.firewall.context.class">Symfony\Bundle\SecurityBundle\Security\FirewallContext</parameter>
|
||||||
<parameter key="security.matcher.class">Symfony\Component\HttpFoundation\RequestMatcher</parameter>
|
<parameter key="security.matcher.class">Symfony\Component\HttpFoundation\RequestMatcher</parameter>
|
||||||
|
<parameter key="security.expression_matcher.class">Symfony\Component\HttpFoundation\ExpressionRequestMatcher</parameter>
|
||||||
|
|
||||||
<parameter key="security.role_hierarchy.class">Symfony\Component\Security\Core\Role\RoleHierarchy</parameter>
|
<parameter key="security.role_hierarchy.class">Symfony\Component\Security\Core\Role\RoleHierarchy</parameter>
|
||||||
|
|
||||||
<parameter key="security.http_utils.class">Symfony\Component\Security\Http\HttpUtils</parameter>
|
<parameter key="security.http_utils.class">Symfony\Component\Security\Http\HttpUtils</parameter>
|
||||||
|
|
||||||
<parameter key="security.validator.user_password.class">Symfony\Component\Security\Core\Validator\Constraints\UserPasswordValidator</parameter>
|
<parameter key="security.validator.user_password.class">Symfony\Component\Security\Core\Validator\Constraints\UserPasswordValidator</parameter>
|
||||||
|
|
||||||
|
<parameter key="security.expression_language.class">Symfony\Component\Security\Core\Authorization\ExpressionLanguage</parameter>
|
||||||
</parameters>
|
</parameters>
|
||||||
|
|
||||||
<services>
|
<services>
|
||||||
@ -78,6 +82,7 @@
|
|||||||
|
|
||||||
<service id="security.user_checker" class="%security.user_checker.class%" public="false" />
|
<service id="security.user_checker" class="%security.user_checker.class%" public="false" />
|
||||||
|
|
||||||
|
<service id="security.expression_language" class="%security.expression_language.class%" public="false" />
|
||||||
|
|
||||||
<!-- Authorization related services -->
|
<!-- Authorization related services -->
|
||||||
<service id="security.access.decision_manager" class="%security.access.decision_manager.class%" public="false">
|
<service id="security.access.decision_manager" class="%security.access.decision_manager.class%" public="false">
|
||||||
@ -104,6 +109,13 @@
|
|||||||
<tag name="security.voter" priority="245" />
|
<tag name="security.voter" priority="245" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<service id="security.access.expression_voter" class="%security.access.expression_voter.class%" public="false">
|
||||||
|
<argument type="service" id="security.expression_language" />
|
||||||
|
<argument type="service" id="security.authentication.trust_resolver" />
|
||||||
|
<argument type="service" id="security.role_hierarchy" on-invalid="null" />
|
||||||
|
<tag name="security.voter" priority="245" />
|
||||||
|
</service>
|
||||||
|
|
||||||
|
|
||||||
<!-- Firewall related services -->
|
<!-- Firewall related services -->
|
||||||
<service id="security.firewall" class="%security.firewall.class%">
|
<service id="security.firewall" class="%security.firewall.class%">
|
||||||
|
@ -17,6 +17,7 @@ use Symfony\Component\DependencyInjection\Parameter;
|
|||||||
use Symfony\Bundle\SecurityBundle\SecurityBundle;
|
use Symfony\Bundle\SecurityBundle\SecurityBundle;
|
||||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityExtension;
|
use Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityExtension;
|
||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
use Symfony\Component\ExpressionLanguage\Expression;
|
||||||
|
|
||||||
abstract class CompleteConfigurationTest extends \PHPUnit_Framework_TestCase
|
abstract class CompleteConfigurationTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
@ -133,7 +134,7 @@ abstract class CompleteConfigurationTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$matcherIds = array();
|
$matcherIds = array();
|
||||||
foreach ($rules as $rule) {
|
foreach ($rules as $rule) {
|
||||||
list($matcherId, $roles, $channel) = $rule;
|
list($matcherId, $attributes, $channel) = $rule;
|
||||||
$requestMatcher = $container->getDefinition($matcherId);
|
$requestMatcher = $container->getDefinition($matcherId);
|
||||||
|
|
||||||
$this->assertFalse(isset($matcherIds[$matcherId]));
|
$this->assertFalse(isset($matcherIds[$matcherId]));
|
||||||
@ -141,19 +142,23 @@ abstract class CompleteConfigurationTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$i = count($matcherIds);
|
$i = count($matcherIds);
|
||||||
if (1 === $i) {
|
if (1 === $i) {
|
||||||
$this->assertEquals(array('ROLE_USER'), $roles);
|
$this->assertEquals(array('ROLE_USER'), $attributes);
|
||||||
$this->assertEquals('https', $channel);
|
$this->assertEquals('https', $channel);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
array('/blog/524', null, array('GET', 'POST')),
|
array('/blog/524', null, array('GET', 'POST')),
|
||||||
$requestMatcher->getArguments()
|
$requestMatcher->getArguments()
|
||||||
);
|
);
|
||||||
} elseif (2 === $i) {
|
} elseif (2 === $i) {
|
||||||
$this->assertEquals(array('IS_AUTHENTICATED_ANONYMOUSLY'), $roles);
|
$this->assertEquals(array('IS_AUTHENTICATED_ANONYMOUSLY'), $attributes);
|
||||||
$this->assertNull($channel);
|
$this->assertNull($channel);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
array('/blog/.*'),
|
array('/blog/.*'),
|
||||||
$requestMatcher->getArguments()
|
$requestMatcher->getArguments()
|
||||||
);
|
);
|
||||||
|
} elseif (3 === $i) {
|
||||||
|
$this->assertEquals('IS_AUTHENTICATED_ANONYMOUSLY', $attributes[0]);
|
||||||
|
$expression = $container->getDefinition($attributes[1])->getArgument(0);
|
||||||
|
$this->assertEquals("token.getUsername() =~ '/^admin/'", $expression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,7 @@ $container->loadFromExtension('security', array(
|
|||||||
'access_control' => array(
|
'access_control' => array(
|
||||||
array('path' => '/blog/524', 'role' => 'ROLE_USER', 'requires_channel' => 'https', 'methods' => array('get', 'POST')),
|
array('path' => '/blog/524', 'role' => 'ROLE_USER', 'requires_channel' => 'https', 'methods' => array('get', 'POST')),
|
||||||
array('path' => '/blog/.*', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY'),
|
array('path' => '/blog/.*', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY'),
|
||||||
|
array('path' => '/blog/524', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY', 'allow_if' => "token.getUsername() =~ '/^admin/'"),
|
||||||
),
|
),
|
||||||
|
|
||||||
'role_hierarchy' => array(
|
'role_hierarchy' => array(
|
||||||
|
@ -68,5 +68,6 @@
|
|||||||
|
|
||||||
<rule path="/blog/524" role="ROLE_USER" requires-channel="https" methods="get,POST" />
|
<rule path="/blog/524" role="ROLE_USER" requires-channel="https" methods="get,POST" />
|
||||||
<rule role='IS_AUTHENTICATED_ANONYMOUSLY' path="/blog/.*" />
|
<rule role='IS_AUTHENTICATED_ANONYMOUSLY' path="/blog/.*" />
|
||||||
|
<rule role='IS_AUTHENTICATED_ANONYMOUSLY' allow-if="token.getUsername() =~ '/^admin/'" path="/blog/524" />
|
||||||
</config>
|
</config>
|
||||||
</srv:container>
|
</srv:container>
|
||||||
|
@ -69,3 +69,4 @@ security:
|
|||||||
-
|
-
|
||||||
path: /blog/.*
|
path: /blog/.*
|
||||||
role: IS_AUTHENTICATED_ANONYMOUSLY
|
role: IS_AUTHENTICATED_ANONYMOUSLY
|
||||||
|
- { path: /blog/524, role: IS_AUTHENTICATED_ANONYMOUSLY, allow_if: "token.getUsername() =~ '/^admin/'" }
|
||||||
|
@ -37,3 +37,6 @@ form_logout:
|
|||||||
form_secure_action:
|
form_secure_action:
|
||||||
path: /secure-but-not-covered-by-access-control
|
path: /secure-but-not-covered-by-access-control
|
||||||
defaults: { _controller: FormLoginBundle:Login:secure }
|
defaults: { _controller: FormLoginBundle:Login:secure }
|
||||||
|
|
||||||
|
protected-via-expression:
|
||||||
|
path: /protected-via-expression
|
||||||
|
@ -91,6 +91,28 @@ class SecurityRoutingIntegrationTest extends WebTestCase
|
|||||||
$this->assertRestricted($barredClient, '/secured-by-two-ips');
|
$this->assertRestricted($barredClient, '/secured-by-two-ips');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider getConfigs
|
||||||
|
*/
|
||||||
|
public function testSecurityConfigurationForExpression($config)
|
||||||
|
{
|
||||||
|
$allowedClient = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config), array('HTTP_USER_AGENT' => 'Firefox 1.0'));
|
||||||
|
$this->assertAllowed($allowedClient, '/protected-via-expression');
|
||||||
|
|
||||||
|
$barredClient = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config), array());
|
||||||
|
$this->assertRestricted($barredClient, '/protected-via-expression');
|
||||||
|
|
||||||
|
$allowedClient = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config), array());
|
||||||
|
|
||||||
|
$allowedClient->request('GET', '/protected-via-expression');
|
||||||
|
$form = $allowedClient->followRedirect()->selectButton('login')->form();
|
||||||
|
$form['_username'] = 'johannes';
|
||||||
|
$form['_password'] = 'test';
|
||||||
|
$allowedClient->submit($form);
|
||||||
|
$this->assertRedirect($allowedClient->getResponse(), '/protected-via-expression');
|
||||||
|
$this->assertAllowed($allowedClient, '/protected-via-expression');
|
||||||
|
}
|
||||||
|
|
||||||
private function assertAllowed($client, $path)
|
private function assertAllowed($client, $path)
|
||||||
{
|
{
|
||||||
$client->request('GET', $path);
|
$client->request('GET', $path);
|
||||||
|
@ -31,4 +31,5 @@ security:
|
|||||||
- { path: ^/secured-by-one-ip$, ip: 10.10.10.10, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
- { path: ^/secured-by-one-ip$, ip: 10.10.10.10, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||||
- { path: ^/secured-by-two-ips$, ips: [1.1.1.1, 2.2.2.2], roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
- { path: ^/secured-by-two-ips$, ips: [1.1.1.1, 2.2.2.2], roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||||
- { path: ^/highly_protected_resource$, roles: IS_ADMIN }
|
- { path: ^/highly_protected_resource$, roles: IS_ADMIN }
|
||||||
|
- { path: ^/protected-via-expression$, allow_if: "(is_anonymous() and object.headers.get('user-agent') =~ '/Firefox/i') or has_role('ROLE_USER')" }
|
||||||
- { path: .*, roles: IS_AUTHENTICATED_FULLY }
|
- { path: .*, roles: IS_AUTHENTICATED_FULLY }
|
||||||
|
@ -25,7 +25,8 @@
|
|||||||
"symfony/twig-bundle": "~2.2",
|
"symfony/twig-bundle": "~2.2",
|
||||||
"symfony/form": "~2.1",
|
"symfony/form": "~2.1",
|
||||||
"symfony/validator": "~2.2",
|
"symfony/validator": "~2.2",
|
||||||
"symfony/yaml": "~2.0"
|
"symfony/yaml": "~2.0",
|
||||||
|
"symfony/expression-language": "~2.4"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-0": { "Symfony\\Bundle\\SecurityBundle\\": "" }
|
"psr-0": { "Symfony\\Bundle\\SecurityBundle\\": "" }
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\Security\Core\Authorization;
|
||||||
|
|
||||||
|
use Symfony\Component\ExpressionLanguage\ExpressionLanguage as BaseExpressionLanguage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds some function to the default ExpressionLanguage.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class ExpressionLanguage extends BaseExpressionLanguage
|
||||||
|
{
|
||||||
|
protected function registerFunctions()
|
||||||
|
{
|
||||||
|
parent::registerFunctions();
|
||||||
|
|
||||||
|
$this->addFunction('is_anonymous', function () {
|
||||||
|
return '$trust_resolver->isAnonymous($token)';
|
||||||
|
}, function (array $variables) {
|
||||||
|
return $variables['trust_resolver']->isAnonymous($variables['token']);
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->addFunction('is_authenticated', function () {
|
||||||
|
return '!$trust_resolver->isAnonymous($token)';
|
||||||
|
}, function (array $variables) {
|
||||||
|
return !$variables['trust_resolver']->isAnonymous($variables['token']);
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->addFunction('is_fully_authenticated', function () {
|
||||||
|
return '!$trust_resolver->isFullFledge($token)';
|
||||||
|
}, function (array $variables) {
|
||||||
|
return !$variables['trust_resolver']->isFullFledge($variables['token']);
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->addFunction('is_remember_me', function () {
|
||||||
|
return '!$trust_resolver->isRememberMe($token)';
|
||||||
|
}, function (array $variables) {
|
||||||
|
return !$variables['trust_resolver']->isRememberMe($variables['token']);
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->addFunction('has_role', function ($role) {
|
||||||
|
return sprintf('in_array(%s, $roles)', $role);
|
||||||
|
}, function (array $variables, $role) {
|
||||||
|
return in_array($role, $variables['roles']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\Security\Core\Authorization\Voter;
|
||||||
|
|
||||||
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||||
|
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
|
||||||
|
use Symfony\Component\Security\Core\Authorization\ExpressionLanguage;
|
||||||
|
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
|
||||||
|
use Symfony\Component\ExpressionLanguage\Expression;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ExpressionVoter votes based on the evaluation of an expression.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class ExpressionVoter implements VoterInterface
|
||||||
|
{
|
||||||
|
private $expressionLanguage;
|
||||||
|
private $trustResolver;
|
||||||
|
private $roleHierarchy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param ExpressionLanguage $expressionLanguage
|
||||||
|
*/
|
||||||
|
public function __construct(ExpressionLanguage $expressionLanguage, AuthenticationTrustResolverInterface $trustResolver, RoleHierarchyInterface $roleHierarchy = null)
|
||||||
|
{
|
||||||
|
$this->expressionLanguage = $expressionLanguage;
|
||||||
|
$this->trustResolver = $trustResolver;
|
||||||
|
$this->roleHierarchy = $roleHierarchy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function supportsAttribute($attribute)
|
||||||
|
{
|
||||||
|
return $attribute instanceof Expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function supportsClass($class)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function vote(TokenInterface $token, $object, array $attributes)
|
||||||
|
{
|
||||||
|
if (null !== $this->roleHierarchy) {
|
||||||
|
$roles = $this->roleHierarchy->getReachableRoles($token->getRoles());
|
||||||
|
} else {
|
||||||
|
$roles = $token->getRoles();
|
||||||
|
}
|
||||||
|
|
||||||
|
$variables = array(
|
||||||
|
'token' => $token,
|
||||||
|
'user' => $token->getUser(),
|
||||||
|
'object' => $object,
|
||||||
|
'roles' => array_map(function ($role) { return $role->getRole(); }, $roles),
|
||||||
|
'trust_resolver' => $this->trustResolver,
|
||||||
|
);
|
||||||
|
|
||||||
|
$result = VoterInterface::ACCESS_ABSTAIN;
|
||||||
|
foreach ($attributes as $attribute) {
|
||||||
|
if (!$this->supportsAttribute($attribute)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = VoterInterface::ACCESS_DENIED;
|
||||||
|
if ($this->expressionLanguage->evaluate($attribute, $variables)) {
|
||||||
|
return VoterInterface::ACCESS_GRANTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
@ -28,12 +28,12 @@ class AccessMap implements AccessMapInterface
|
|||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param RequestMatcherInterface $requestMatcher A RequestMatcherInterface instance
|
* @param RequestMatcherInterface $requestMatcher A RequestMatcherInterface instance
|
||||||
* @param array $roles An array of roles needed to access the resource
|
* @param array $attributes An array of attributes to pass to the access decision manager (like roles)
|
||||||
* @param string|null $channel The channel to enforce (http, https, or null)
|
* @param string|null $channel The channel to enforce (http, https, or null)
|
||||||
*/
|
*/
|
||||||
public function add(RequestMatcherInterface $requestMatcher, array $roles = array(), $channel = null)
|
public function add(RequestMatcherInterface $requestMatcher, array $attributes = array(), $channel = null)
|
||||||
{
|
{
|
||||||
$this->map[] = array($requestMatcher, $roles, $channel);
|
$this->map[] = array($requestMatcher, $attributes, $channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPatterns(Request $request)
|
public function getPatterns(Request $request)
|
||||||
|
@ -28,7 +28,8 @@
|
|||||||
"doctrine/common": "~2.2",
|
"doctrine/common": "~2.2",
|
||||||
"doctrine/dbal": "~2.2",
|
"doctrine/dbal": "~2.2",
|
||||||
"psr/log": "~1.0",
|
"psr/log": "~1.0",
|
||||||
"ircmaxell/password-compat": "1.0.*"
|
"ircmaxell/password-compat": "1.0.*",
|
||||||
|
"symfony/expression-language": "~2.4"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"symfony/class-loader": "",
|
"symfony/class-loader": "",
|
||||||
|
Reference in New Issue
Block a user