undeprecate the RoleHierarchyInterface

Instead of deprecating the interface it is sufficient to deprecate its
getReachableRoles() method and add a new getReachableRoleNames() method
in Symfony 5.
This commit is contained in:
Christian Flothmann 2019-02-26 19:23:16 +01:00
parent 522594a69d
commit 2d3f2b7a74
10 changed files with 52 additions and 60 deletions

View File

@ -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.

View File

@ -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.

View File

@ -23,7 +23,6 @@ use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface
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 @@ class SecurityDataCollector extends DataCollector implements LateDataCollectorIn
}
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)));

View File

@ -98,8 +98,6 @@
<argument>%security.role_hierarchy.roles%</argument>
</service>
<service id="Symfony\Component\Security\Core\Role\RoleHierarchyInterface" alias="security.role_hierarchy" />
<service id="Symfony\Component\Security\Core\Role\RoleHierarchy" alias="security.role_hierarchy" />
<!-- Security Voters -->
<service id="security.access.simple_role_voter" class="Symfony\Component\Security\Core\Authorization\Voter\RoleVoter">

View File

@ -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

View File

@ -19,7 +19,6 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
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 @@ class ExpressionVoter implements VoterInterface
@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 @@ class ExpressionVoter implements VoterInterface
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 @@ class ExpressionVoter implements VoterInterface
'object' => $subject,
'subject' => $subject,
'roles' => $roles,
'role_names' => $roleNames,
'trust_resolver' => $this->trustResolver,
'auth_checker' => $this->authChecker,
];

View File

@ -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 @@ class RoleHierarchyVoter extends RoleVoter
*/
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);

View File

@ -36,7 +36,9 @@ class RoleHierarchy implements RoleHierarchyInterface
*/
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 @@ class RoleHierarchy implements RoleHierarchyInterface
*/
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])) {

View File

@ -14,21 +14,13 @@ namespace Symfony\Component\Security\Core\Role;
/**
* 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 <fabien@symfony.com>
*
* @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);
}

View File

@ -13,9 +13,9 @@ namespace Symfony\Component\Workflow\EventListener;
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 @@ class GuardListener
}
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 @@ class GuardListener
'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