diff --git a/UPGRADE-4.2.md b/UPGRADE-4.2.md
new file mode 100644
index 0000000000000..23982ef159b36
--- /dev/null
+++ b/UPGRADE-4.2.md
@@ -0,0 +1,7 @@
+UPGRADE FROM 4.1 to 4.2
+=======================
+
+Security
+--------
+
+ * Using the `has_role()` function in security expressions is deprecated, use the `is_granted()` function instead.
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
index ce65f52bef128..9f0e07fd149d6 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
@@ -370,7 +370,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode)
->scalarNode('guard')
->cannotBeEmpty()
->info('An expression to block the transition')
- ->example('is_fully_authenticated() and has_role(\'ROLE_JOURNALIST\') and subject.getTitle() == \'My first article\'')
+ ->example('is_fully_authenticated() and is_granted(\'ROLE_JOURNALIST\') and subject.getTitle() == \'My first article\'')
->end()
->arrayNode('from')
->beforeNormalization()
diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml
index 9cbdd2061e119..65c48e0855cb7 100644
--- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml
+++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml
@@ -119,6 +119,7 @@
+
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml
index 19b9d8952ec5e..d7c73aa0b6dc0 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml
@@ -40,5 +40,5 @@ security:
- { 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: ^/highly_protected_resource$, roles: IS_ADMIN }
- - { path: ^/protected-via-expression$, allow_if: "(is_anonymous() and request.headers.get('user-agent') matches '/Firefox/i') or has_role('ROLE_USER')" }
+ - { path: ^/protected-via-expression$, allow_if: "(is_anonymous() and request.headers.get('user-agent') matches '/Firefox/i') or is_granted('ROLE_USER')" }
- { path: .*, roles: IS_AUTHENTICATED_FULLY }
diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json
index 5dd550ec3b84d..e95f3430a94b7 100644
--- a/src/Symfony/Bundle/SecurityBundle/composer.json
+++ b/src/Symfony/Bundle/SecurityBundle/composer.json
@@ -18,7 +18,7 @@
"require": {
"php": "^7.1.3",
"ext-xml": "*",
- "symfony/security": "~4.1",
+ "symfony/security": "~4.2",
"symfony/dependency-injection": "^3.4.3|^4.0.3",
"symfony/http-kernel": "^4.1"
},
diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md
index ec33a7af97a4b..87939e3a26388 100644
--- a/src/Symfony/Component/Security/CHANGELOG.md
+++ b/src/Symfony/Component/Security/CHANGELOG.md
@@ -1,6 +1,12 @@
CHANGELOG
=========
+4.2.0
+-----
+
+* added the `is_granted()` function in security expressions
+* deprecated the `has_role()` function in security expressions, use `is_granted()` instead
+
4.1.0
-----
diff --git a/src/Symfony/Component/Security/Core/Authorization/ExpressionLanguageProvider.php b/src/Symfony/Component/Security/Core/Authorization/ExpressionLanguageProvider.php
index 9293ba7e39d4e..9e551115837cb 100644
--- a/src/Symfony/Component/Security/Core/Authorization/ExpressionLanguageProvider.php
+++ b/src/Symfony/Component/Security/Core/Authorization/ExpressionLanguageProvider.php
@@ -42,6 +42,12 @@ public function getFunctions()
return $variables['trust_resolver']->isFullFledged($variables['token']);
}),
+ new ExpressionFunction('is_granted', function ($attributes, $object = 'null') {
+ return sprintf('$auth_checker->isGranted(%s, %s)', $attributes, $object);
+ }, function (array $variables, $attributes, $object = null) {
+ return $variables['auth_checker']->isGranted($attributes, $object);
+ }),
+
new ExpressionFunction('is_remember_me', function () {
return '$trust_resolver->isRememberMe($token)';
}, function (array $variables) {
@@ -49,8 +55,12 @@ public function getFunctions()
}),
new ExpressionFunction('has_role', function ($role) {
+ @trigger_error('Using the "has_role()" function in security expressions is deprecated since Symfony 4.2, use "is_granted()" instead.', E_USER_DEPRECATED);
+
return sprintf('in_array(%s, $roles)', $role);
}, function (array $variables, $role) {
+ @trigger_error('Using the "has_role()" function in security expressions is deprecated since Symfony 4.2, use "is_granted()" instead.', E_USER_DEPRECATED);
+
return in_array($role, $variables['roles']);
}),
);
diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php
index cbee938667789..726313c69d910 100644
--- a/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php
+++ b/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php
@@ -13,6 +13,7 @@
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
+use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Authorization\ExpressionLanguage;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
@@ -28,12 +29,27 @@ class ExpressionVoter implements VoterInterface
{
private $expressionLanguage;
private $trustResolver;
+ private $authChecker;
private $roleHierarchy;
- public function __construct(ExpressionLanguage $expressionLanguage, AuthenticationTrustResolverInterface $trustResolver, RoleHierarchyInterface $roleHierarchy = null)
+ /**
+ * @param AuthorizationCheckerInterface $authChecker
+ */
+ public function __construct(ExpressionLanguage $expressionLanguage, AuthenticationTrustResolverInterface $trustResolver, $authChecker = null, RoleHierarchyInterface $roleHierarchy = null)
{
+ if ($authChecker instanceof RoleHierarchyInterface) {
+ @trigger_error(sprintf('Passing a RoleHierarchyInterface to "%s()" is deprecated since Symfony 4.2. Pass an AuthorizationCheckerInterface instead.', __METHOD__), E_USER_DEPRECATED);
+ $roleHierarchy = $authChecker;
+ $authChecker = null;
+ } elseif (null === $authChecker) {
+ @trigger_error(sprintf('Argument 3 passed to "%s()" should be an instanceof AuthorizationCheckerInterface, not passing it is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED);
+ } elseif (!$authChecker instanceof AuthorizationCheckerInterface) {
+ throw new \InvalidArgumentException(sprintf('Argument 3 passed to %s() must be an instance of %s or null, %s given.', __METHOD__, AuthorizationCheckerInterface::class, is_object($authChecker) ? get_class($authChecker) : gettype($authChecker)));
+ }
+
$this->expressionLanguage = $expressionLanguage;
$this->trustResolver = $trustResolver;
+ $this->authChecker = $authChecker;
$this->roleHierarchy = $roleHierarchy;
}
@@ -87,6 +103,7 @@ private function getVariables(TokenInterface $token, $subject)
'subject' => $subject,
'roles' => array_map(function ($role) { return $role->getRole(); }, $roles),
'trust_resolver' => $this->trustResolver,
+ 'auth_checker' => $this->authChecker,
);
// this is mainly to propose a better experience when the expression is used
diff --git a/src/Symfony/Component/Security/Core/Tests/Authorization/ExpressionLanguageTest.php b/src/Symfony/Component/Security/Core/Tests/Authorization/ExpressionLanguageTest.php
index 1565d1c865256..6c05ecfab506a 100644
--- a/src/Symfony/Component/Security/Core/Tests/Authorization/ExpressionLanguageTest.php
+++ b/src/Symfony/Component/Security/Core/Tests/Authorization/ExpressionLanguageTest.php
@@ -12,10 +12,15 @@
namespace Symfony\Component\Security\Core\Tests\Authorization;
use PHPUnit\Framework\TestCase;
+use Symfony\Component\Security\Core\Authorization\AccessDecisionManager;
+use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
use Symfony\Component\Security\Core\Authorization\ExpressionLanguage;
+use Symfony\Component\Security\Core\Authorization\Voter\RoleVoter;
+use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver;
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
+use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\User\User;
@@ -24,17 +29,21 @@ class ExpressionLanguageTest extends TestCase
/**
* @dataProvider provider
*/
- public function testIsAuthenticated($token, $expression, $result, array $roles = array())
+ public function testIsAuthenticated($token, $expression, $result)
{
$anonymousTokenClass = 'Symfony\\Component\\Security\\Core\\Authentication\\Token\\AnonymousToken';
$rememberMeTokenClass = 'Symfony\\Component\\Security\\Core\\Authentication\\Token\\RememberMeToken';
$expressionLanguage = new ExpressionLanguage();
$trustResolver = new AuthenticationTrustResolver($anonymousTokenClass, $rememberMeTokenClass);
+ $tokenStorage = new TokenStorage();
+ $tokenStorage->setToken($token);
+ $accessDecisionManager = new AccessDecisionManager(array(new RoleVoter()));
+ $authChecker = new AuthorizationChecker($tokenStorage, $this->getMockBuilder(AuthenticationManagerInterface::class)->getMock(), $accessDecisionManager);
$context = array();
$context['trust_resolver'] = $trustResolver;
+ $context['auth_checker'] = $authChecker;
$context['token'] = $token;
- $context['roles'] = $roles;
$this->assertEquals($result, $expressionLanguage->evaluate($expression, $context));
}
@@ -54,27 +63,52 @@ public function provider()
array($noToken, 'is_authenticated()', false),
array($noToken, 'is_fully_authenticated()', false),
array($noToken, 'is_remember_me()', false),
- array($noToken, "has_role('ROLE_USER')", false),
array($anonymousToken, 'is_anonymous()', true),
array($anonymousToken, 'is_authenticated()', false),
array($anonymousToken, 'is_fully_authenticated()', false),
array($anonymousToken, 'is_remember_me()', false),
- array($anonymousToken, "has_role('ROLE_USER')", false),
+ array($anonymousToken, "is_granted('ROLE_USER')", false),
array($rememberMeToken, 'is_anonymous()', false),
array($rememberMeToken, 'is_authenticated()', true),
array($rememberMeToken, 'is_fully_authenticated()', false),
array($rememberMeToken, 'is_remember_me()', true),
- array($rememberMeToken, "has_role('ROLE_FOO')", false, $roles),
- array($rememberMeToken, "has_role('ROLE_USER')", true, $roles),
+ array($rememberMeToken, "is_granted('ROLE_FOO')", false),
+ array($rememberMeToken, "is_granted('ROLE_USER')", true),
array($usernamePasswordToken, 'is_anonymous()', false),
array($usernamePasswordToken, 'is_authenticated()', true),
array($usernamePasswordToken, 'is_fully_authenticated()', true),
array($usernamePasswordToken, 'is_remember_me()', false),
- array($usernamePasswordToken, "has_role('ROLE_FOO')", false, $roles),
- array($usernamePasswordToken, "has_role('ROLE_USER')", true, $roles),
+ array($usernamePasswordToken, "is_granted('ROLE_FOO')", false),
+ array($usernamePasswordToken, "is_granted('ROLE_USER')", true),
+ );
+ }
+
+ /**
+ * @dataProvider provideLegacyHasRole
+ * @group legacy
+ */
+ public function testLegacyHasRole($expression, $result, $roles = array())
+ {
+ $expressionLanguage = new ExpressionLanguage();
+ $context = array('roles' => $roles);
+
+ $this->assertEquals($result, $expressionLanguage->evaluate($expression, $context));
+ }
+
+ public function provideLegacyHasRole()
+ {
+ $roles = array('ROLE_USER', 'ROLE_ADMIN');
+
+ return array(
+ array("has_role('ROLE_FOO')", false),
+ array("has_role('ROLE_USER')", false),
+ array("has_role('ROLE_ADMIN')", false),
+ array("has_role('ROLE_FOO')", false, $roles),
+ array("has_role('ROLE_USER')", true, $roles),
+ array("has_role('ROLE_ADMIN')", true, $roles),
);
}
}
diff --git a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/ExpressionVoterTest.php b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/ExpressionVoterTest.php
index 79626835264ab..9b7bf67709ce0 100644
--- a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/ExpressionVoterTest.php
+++ b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/ExpressionVoterTest.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\Security\Core\Tests\Authorization\Voter;
use PHPUnit\Framework\TestCase;
+use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Authorization\Voter\ExpressionVoter;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
use Symfony\Component\Security\Core\Role\Role;
@@ -23,7 +24,7 @@ class ExpressionVoterTest extends TestCase
*/
public function testVote($roles, $attributes, $expected, $tokenExpectsGetRoles = true, $expressionLanguageExpectsEvaluate = true)
{
- $voter = new ExpressionVoter($this->createExpressionLanguage($expressionLanguageExpectsEvaluate), $this->createTrustResolver());
+ $voter = new ExpressionVoter($this->createExpressionLanguage($expressionLanguageExpectsEvaluate), $this->createTrustResolver(), $this->createAuthorizationChecker());
$this->assertSame($expected, $voter->vote($this->getToken($roles, $tokenExpectsGetRoles), null, $attributes));
}
@@ -75,9 +76,9 @@ protected function createTrustResolver()
return $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface')->getMock();
}
- protected function createRoleHierarchy()
+ protected function createAuthorizationChecker()
{
- return $this->getMockBuilder('Symfony\Component\Security\Core\Role\RoleHierarchyInterface')->getMock();
+ return $this->getMockBuilder(AuthorizationCheckerInterface::class)->getMock();
}
protected function createExpression()
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy