diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md
index 52165c10b539e..f91bdb8bf6b16 100644
--- a/UPGRADE-4.3.md
+++ b/UPGRADE-4.3.md
@@ -88,9 +88,8 @@ Security
* The `Role` and `SwitchUserRole` classes are deprecated and will be removed in 5.0. Use strings for roles
instead.
- * The `RoleHierarchyInterface` is deprecated and will be removed in 5.0.
- * The `getReachableRoles()` method of the `RoleHierarchy` class is deprecated and will be removed in 5.0.
- Use the `getReachableRoleNames()` method instead.
+ * The `getReachableRoles()` method of the `RoleHierarchyInterface` is deprecated and will be removed in 5.0.
+ Role hierarchies must implement the `getReachableRoleNames()` method instead and return roles as strings.
* The `getRoles()` method of the `TokenInterface` is deprecated. Tokens must implement the `getRoleNames()`
method instead and return roles as strings.
* The `ListenerInterface` is deprecated, turn your listeners into callables instead.
diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md
index 60b16b1c58df8..5757661bec94f 100644
--- a/UPGRADE-5.0.md
+++ b/UPGRADE-5.0.md
@@ -256,8 +256,8 @@ Security
--------
* The `Role` and `SwitchUserRole` classes have been removed.
- * The `RoleHierarchyInterface` has been removed.
- * The `getReachableRoles()` method of the `RoleHierarchy` class has been removed.
+ * The `getReachableRoles()` method of the `RoleHierarchy` class has been removed. It has been replaced by the new
+ `getReachableRoleNames()` method.
* The `getRoles()` method has been removed from the `TokenInterface`. It has been replaced by the new
`getRoleNames()` method.
* The `ContextListener::setLogoutOnUserChange()` method has been removed.
diff --git a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php
index d33d227ff137c..0d122efe7fd81 100644
--- a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php
+++ b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php
@@ -23,7 +23,6 @@
use Symfony\Component\Security\Core\Authorization\TraceableAccessDecisionManager;
use Symfony\Component\Security\Core\Authorization\Voter\TraceableVoter;
use Symfony\Component\Security\Core\Role\Role;
-use Symfony\Component\Security\Core\Role\RoleHierarchy;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
use Symfony\Component\Security\Core\Role\SwitchUserRole;
use Symfony\Component\Security\Http\Firewall\SwitchUserListener;
@@ -113,7 +112,7 @@ public function collect(Request $request, Response $response, \Exception $except
}
if (null !== $this->roleHierarchy) {
- if ($this->roleHierarchy instanceof RoleHierarchy) {
+ if (method_exists($this->roleHierarchy, 'getReachableRoleNames')) {
$allRoles = $this->roleHierarchy->getReachableRoleNames($assignedRoles);
} else {
$allRoles = array_map(function (Role $role) { return (string) $role; }, $this->roleHierarchy->getReachableRoles($token->getRoles(false)));
diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml
index d4d6f1a2e362d..1d2f0c4e503b3 100644
--- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml
+++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml
@@ -98,8 +98,6 @@
%security.role_hierarchy.roles%
-
-
diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md
index e29070f0cc4ca..fc6b60a3a1309 100644
--- a/src/Symfony/Component/Security/CHANGELOG.md
+++ b/src/Symfony/Component/Security/CHANGELOG.md
@@ -6,9 +6,8 @@ CHANGELOG
* The `Role` and `SwitchUserRole` classes are deprecated and will be removed in 5.0. Use strings for roles
instead.
- * The `RoleHierarchyInterface` is deprecated and will be removed in 5.0.
- * The `getReachableRoles()` method of the `RoleHierarchy` class is deprecated and will be removed in 5.0.
- Use the `getReachableRoleNames()` method instead.
+ * The `getReachableRoles()` method of the `RoleHierarchyInterface` is deprecated and will be removed in 5.0.
+ Role hierarchies must implement the `getReachableRoleNames()` method instead and return roles as strings.
* The `getRoles()` method of the `TokenInterface` is deprecated. Tokens must implement the `getRoleNames()`
method instead and return roles as strings.
* Made the `serialize()` and `unserialize()` methods of `AbstractToken` and
diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php
index c84fc5d9b43cc..e35583555d60e 100644
--- a/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php
+++ b/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php
@@ -19,7 +19,6 @@
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Authorization\ExpressionLanguage;
use Symfony\Component\Security\Core\Role\Role;
-use Symfony\Component\Security\Core\Role\RoleHierarchy;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
/**
@@ -43,6 +42,10 @@ public function __construct(ExpressionLanguage $expressionLanguage, Authenticati
@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;
+
+ if (!method_exists($roleHierarchy, 'getReachableRoleNames')) {
+ @trigger_error(sprintf('Not implementing the getReachableRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($this->roleHierarchy), RoleHierarchyInterface::class), E_USER_DEPRECATED);
+ }
} elseif (null === $authChecker) {
@trigger_error(sprintf('Argument 3 passed to "%s()" should be an instance of AuthorizationCheckerInterface, not passing it is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED);
} elseif (!$authChecker instanceof AuthorizationCheckerInterface) {
@@ -92,27 +95,23 @@ public function vote(TokenInterface $token, $subject, array $attributes)
private function getVariables(TokenInterface $token, $subject)
{
- if ($this->roleHierarchy instanceof RoleHierarchy) {
- if (method_exists($token, 'getRoleNames')) {
- $rolesFromToken = $token->getRoleNames();
- } else {
- @trigger_error(sprintf('Not implementing the getRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($token), TokenInterface::class), E_USER_DEPRECATED);
-
- $rolesFromToken = $token->getRoles(false);
- }
-
- $roles = $this->roleHierarchy->getReachableRoleNames($rolesFromToken);
- } elseif (null !== $this->roleHierarchy) {
- $roles = $this->roleHierarchy->getReachableRoles($token->getRoles(false));
- } elseif (method_exists($token, 'getRoleNames')) {
- $roles = $token->getRoleNames();
+ if (method_exists($token, 'getRoleNames')) {
+ $roleNames = $token->getRoleNames();
+ $roles = array_map(function (string $role) { return new Role($role, false); }, $roleNames);
} else {
@trigger_error(sprintf('Not implementing the getRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($token), TokenInterface::class), E_USER_DEPRECATED);
$roles = $token->getRoles(false);
+ $roleNames = array_map(function (Role $role) { return $role->getRole(); }, $roles);
}
- $roles = array_map(function ($role) { return $role instanceof Role ? $role->getRole() : $role; }, $roles);
+ if (null !== $this->roleHierarchy && method_exists($this->roleHierarchy, 'getReachableRoleNames')) {
+ $roleNames = $this->roleHierarchy->getReachableRoleNames($roleNames);
+ $roles = array_map(function (string $role) { return new Role($role, false); }, $roleNames);
+ } elseif (null !== $this->roleHierarchy) {
+ $roles = $this->roleHierarchy->getReachableRoles($roles);
+ $roleNames = array_map(function (Role $role) { return $role->getRole(); }, $roles);
+ }
$variables = [
'token' => $token,
@@ -120,6 +119,7 @@ private function getVariables(TokenInterface $token, $subject)
'object' => $subject,
'subject' => $subject,
'roles' => $roles,
+ 'role_names' => $roleNames,
'trust_resolver' => $this->trustResolver,
'auth_checker' => $this->authChecker,
];
diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/RoleHierarchyVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/RoleHierarchyVoter.php
index 4a1de12cf7fa8..d4524667c5715 100644
--- a/src/Symfony/Component/Security/Core/Authorization/Voter/RoleHierarchyVoter.php
+++ b/src/Symfony/Component/Security/Core/Authorization/Voter/RoleHierarchyVoter.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\Security\Core\Authorization\Voter;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Security\Core\Role\RoleHierarchy;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
@@ -27,8 +28,8 @@ class RoleHierarchyVoter extends RoleVoter
public function __construct(RoleHierarchyInterface $roleHierarchy, string $prefix = 'ROLE_')
{
- if (!$roleHierarchy instanceof RoleHierarchy) {
- @trigger_error(sprintf('Passing a role hierarchy to "%s" that is not an instance of "%s" is deprecated since Symfony 4.3 and support for it will be dropped in Symfony 5.0 ("%s" given).', __CLASS__, RoleHierarchy::class, \get_class($roleHierarchy)), E_USER_DEPRECATED);
+ if (!method_exists($roleHierarchy, 'getReachableRoleNames')) {
+ @trigger_error(sprintf('Not implementing the getReachableRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($roleHierarchy), RoleHierarchyInterface::class), E_USER_DEPRECATED);
}
$this->roleHierarchy = $roleHierarchy;
@@ -41,13 +42,13 @@ public function __construct(RoleHierarchyInterface $roleHierarchy, string $prefi
*/
protected function extractRoles(TokenInterface $token)
{
- if ($this->roleHierarchy instanceof RoleHierarchy) {
+ if (method_exists($this->roleHierarchy, 'getReachableRoleNames')) {
if (method_exists($token, 'getRoleNames')) {
$roles = $token->getRoleNames();
} else {
@trigger_error(sprintf('Not implementing the getRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($token), TokenInterface::class), E_USER_DEPRECATED);
- $roles = $token->getRoles(false);
+ $roles = array_map(function (Role $role) { return $role->getRole(); }, $token->getRoles(false));
}
return $this->roleHierarchy->getReachableRoleNames($roles);
diff --git a/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php b/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php
index d725000d1b826..c1116cd2c3d55 100644
--- a/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php
+++ b/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php
@@ -36,7 +36,9 @@ public function __construct(array $hierarchy)
*/
public function getReachableRoles(array $roles)
{
- @trigger_error(sprintf('The %s() method is deprecated since Symfony 4.3 and will be removed in 5.0. Use roles as strings and the getReachableRoleNames() method instead.', __METHOD__), E_USER_DEPRECATED);
+ if (0 === \func_num_args() || func_get_arg(0)) {
+ @trigger_error(sprintf('The %s() method is deprecated since Symfony 4.3 and will be removed in 5.0. Use roles as strings and the getReachableRoleNames() method instead.', __METHOD__), E_USER_DEPRECATED);
+ }
$reachableRoles = $roles;
foreach ($roles as $role) {
@@ -59,16 +61,7 @@ public function getReachableRoles(array $roles)
*/
public function getReachableRoleNames(array $roles): array
{
- $reachableRoles = $roles = array_map(
- function ($role) {
- if ($role instanceof Role) {
- return $role->getRole();
- }
-
- return $role;
- },
- $roles
- );
+ $reachableRoles = $roles;
foreach ($roles as $role) {
if (!isset($this->map[$role])) {
diff --git a/src/Symfony/Component/Security/Core/Role/RoleHierarchyInterface.php b/src/Symfony/Component/Security/Core/Role/RoleHierarchyInterface.php
index 3a5112f7e5b91..9f54042db0e4b 100644
--- a/src/Symfony/Component/Security/Core/Role/RoleHierarchyInterface.php
+++ b/src/Symfony/Component/Security/Core/Role/RoleHierarchyInterface.php
@@ -14,21 +14,13 @@
/**
* RoleHierarchyInterface is the interface for a role hierarchy.
*
+ * The getReachableRoles(Role[] $roles) method that returns an array of all reachable Role objects is deprecated
+ * since Symfony 4.3.
+ *
* @author Fabien Potencier
*
- * @deprecated since Symfony 4.3, to be removed in 5.0.
+ * @method string[] getReachableRoleNames(string[] $roles) The associated roles - not implementing it is deprecated since Symfony 4.3
*/
interface RoleHierarchyInterface
{
- /**
- * Returns an array of all reachable roles by the given ones.
- *
- * Reachable roles are the roles directly assigned but also all roles that
- * are transitively reachable from them in the role hierarchy.
- *
- * @param Role[] $roles An array of directly assigned roles
- *
- * @return Role[] An array of all reachable roles
- */
- public function getReachableRoles(array $roles);
}
diff --git a/src/Symfony/Component/Workflow/EventListener/GuardListener.php b/src/Symfony/Component/Workflow/EventListener/GuardListener.php
index 60cd00ed2084f..a1795b8f47b02 100644
--- a/src/Symfony/Component/Workflow/EventListener/GuardListener.php
+++ b/src/Symfony/Component/Workflow/EventListener/GuardListener.php
@@ -13,9 +13,9 @@
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Role\Role;
-use Symfony\Component\Security\Core\Role\RoleHierarchy;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Workflow\Event\GuardEvent;
@@ -37,6 +37,10 @@ class GuardListener
public function __construct(array $configuration, ExpressionLanguage $expressionLanguage, TokenStorageInterface $tokenStorage, AuthorizationCheckerInterface $authorizationChecker, AuthenticationTrustResolverInterface $trustResolver, RoleHierarchyInterface $roleHierarchy = null, ValidatorInterface $validator = null)
{
+ if (null !== $roleHierarchy && !method_exists($roleHierarchy, 'getReachableRoleNames')) {
+ @trigger_error(sprintf('Not implementing the getReachableRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($roleHierarchy), RoleHierarchyInterface::class), E_USER_DEPRECATED);
+ }
+
$this->configuration = $configuration;
$this->expressionLanguage = $expressionLanguage;
$this->tokenStorage = $tokenStorage;
@@ -83,15 +87,21 @@ private function getVariables(GuardEvent $event): array
}
if (method_exists($token, 'getRoleNames')) {
- $roles = $token->getRoleNames();
+ $roleNames = $token->getRoleNames();
+ $roles = array_map(function (string $role) { return new Role($role, false); }, $roleNames);
} else {
- $roles = array_map(function (Role $role) { return $role->getRole(); }, $token->getRoles(false));
+ @trigger_error(sprintf('Not implementing the getRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($token), TokenInterface::class), E_USER_DEPRECATED);
+
+ $roles = $token->getRoles(false);
+ $roleNames = array_map(function (Role $role) { return $role->getRole(); }, $roles);
}
- if ($this->roleHierarchy instanceof RoleHierarchy) {
- $roles = $this->roleHierarchy->getReachableRoleNames($roles);
+ if (null !== $this->roleHierarchy && method_exists($this->roleHierarchy, 'getReachableRoleNames')) {
+ $roleNames = $this->roleHierarchy->getReachableRoleNames($roles);
+ $roles = array_map(function (string $role) { return new Role($role, false); }, $roleNames);
} elseif (null !== $this->roleHierarchy) {
$roles = $this->roleHierarchy->getReachableRoles($token->getRoles(false));
+ $roleNames = array_map(function (Role $role) { return $role->getRole(); }, $roles);
}
$variables = [
@@ -99,6 +109,7 @@ private function getVariables(GuardEvent $event): array
'user' => $token->getUser(),
'subject' => $event->getSubject(),
'roles' => $roles,
+ 'role_names' => $roleNames,
// needed for the is_granted expression function
'auth_checker' => $this->authorizationChecker,
// needed for the is_* expression function