AuthorizationHelper: compare center and scope based on id, not on equality

For an unknown reason, in some circumstances, the use of the `===` comparator does not work when comparing Center instances and Scope instances. Then, we compare them based on the id.
This commit is contained in:
Julien Fastré 2023-09-13 10:08:44 +02:00
parent 2ce29f36ff
commit d3b68f8f8f
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
3 changed files with 53 additions and 31 deletions

View File

@ -33,7 +33,13 @@ use function get_class;
*/ */
class AuthorizationHelper implements AuthorizationHelperInterface class AuthorizationHelper implements AuthorizationHelperInterface
{ {
public function __construct(private readonly CenterResolverManagerInterface $centerResolverManager, private readonly LoggerInterface $logger, private readonly ScopeResolverDispatcher $scopeResolverDispatcher, private readonly UserACLAwareRepositoryInterface $userACLAwareRepository, private readonly ParentRoleHelper $parentRoleHelper) {} public function __construct(
private readonly CenterResolverManagerInterface $centerResolverManager,
private readonly LoggerInterface $logger,
private readonly ScopeResolverDispatcher $scopeResolverDispatcher,
private readonly UserACLAwareRepositoryInterface $userACLAwareRepository,
private readonly ParentRoleHelper $parentRoleHelper
) {}
/** /**
* Filter an array of centers, return only center which are reachable. * Filter an array of centers, return only center which are reachable.
@ -233,7 +239,7 @@ class AuthorizationHelper implements AuthorizationHelperInterface
return $this->parentRoleHelper->isRoleReached($childRole, $parentRole); return $this->parentRoleHelper->isRoleReached($childRole, $parentRole);
} }
private function userHasAccessForCenter(User $user, Center $center, $entity, $attribute): bool private function userHasAccessForCenter(User $user, Center $center, mixed $entity, $attribute): bool
{ {
if (!$this->userCanReachCenter($user, $center)) { if (!$this->userCanReachCenter($user, $center)) {
$this->logger->debug('user cannot reach center of entity', [ $this->logger->debug('user cannot reach center of entity', [
@ -243,10 +249,11 @@ class AuthorizationHelper implements AuthorizationHelperInterface
return false; return false;
} }
foreach ($user->getGroupCenters() as $groupCenter) { foreach ($user->getGroupCenters() as $groupCenter) {
//filter on center // filter on center
if ($groupCenter->getCenter() === $center) { // in some case, the center can be the same, but have different object hashes,
// we cannot compare the objects: we must compare the ids here
if ($groupCenter->getCenter()->getId() === $center->getId()) {
$permissionGroup = $groupCenter->getPermissionsGroup(); $permissionGroup = $groupCenter->getPermissionsGroup();
//iterate on roleScopes //iterate on roleScopes
foreach ($permissionGroup->getRoleScopes() as $roleScope) { foreach ($permissionGroup->getRoleScopes() as $roleScope) {
@ -263,7 +270,7 @@ class AuthorizationHelper implements AuthorizationHelperInterface
if (is_iterable($scope)) { if (is_iterable($scope)) {
foreach ($scope as $s) { foreach ($scope as $s) {
if ($roleScope->getScope() === $s) { if ($roleScope->getScope()->getId() === $s->getId()) {
return true; return true;
} }
} }

View File

@ -11,6 +11,8 @@ declare(strict_types=1);
namespace Chill\MainBundle\Test; namespace Chill\MainBundle\Test;
use Chill\MainBundle\Entity\Center;
/** /**
* A trait to prepare center. * A trait to prepare center.
* *
@ -25,23 +27,17 @@ trait PrepareCenterTrait
/** /**
* prepare a mocked center, with and id and name given. * prepare a mocked center, with and id and name given.
*
* @param int $id
* @param string $name
*
* @return \Chill\MainBundle\Entity\Center
*/ */
protected function prepareCenter($id, $name) protected function prepareCenter(int $id, string $name): Center
{ {
if (null === $this->centerProphet) { $center = new Center();
$this->centerProphet = new \Prophecy\Prophet(); $center->setName($name);
}
$center = $this->centerProphet->prophesize(); $reflectionClass = new \ReflectionClass($center);
$center->willExtend('\\' . \Chill\MainBundle\Entity\Center::class); $reflectionId = $reflectionClass->getProperty('id');
$center->getId()->willReturn($id); $reflectionId->setAccessible(true);
$center->getName()->willReturn($name); $reflectionId->setValue($center, $id);
return $center->reveal(); return $center;
} }
} }

View File

@ -47,7 +47,8 @@ final class AuthorizationHelperTest extends KernelTestCase
public function dataProvider_getReachableCenters() public function dataProvider_getReachableCenters()
{ {
$this->setUp(); self::bootKernel();
$centerA = $this->prepareCenter(1, 'center A'); $centerA = $this->prepareCenter(1, 'center A');
$centerB = $this->prepareCenter(2, 'center B'); $centerB = $this->prepareCenter(2, 'center B');
$scopeA = $this->prepareScope(1, 'scope default'); $scopeA = $this->prepareScope(1, 'scope default');
@ -311,9 +312,9 @@ final class AuthorizationHelperTest extends KernelTestCase
public function testUserHasAccessEntityMultiScope() public function testUserHasAccessEntityMultiScope()
{ {
$centerA = $this->prepareCenter(1, 'center'); $centerA = $this->prepareCenter(1, 'center');
$centerB = $this->prepareCenter(1, 'centerB'); $centerB = $this->prepareCenter(2, 'centerB');
$scopeA = $this->prepareScope(2, 'other'); //the user will be granted this scope $scopeA = $this->prepareScope(3, 'other'); //the user will be granted this scope
$scopeB = $this->prepareScope(2, 'other'); //the user will be granted this scope $scopeB = $this->prepareScope(4, 'other'); //the user will be granted this scope
$user = $this->prepareUser([ $user = $this->prepareUser([
[ [
'center' => $centerA, 'permissionsGroup' => [ 'center' => $centerA, 'permissionsGroup' => [
@ -331,6 +332,24 @@ final class AuthorizationHelperTest extends KernelTestCase
$this->assertTrue($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); $this->assertTrue($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE'));
} }
public function testUserHasAccessEntityIsCenter()
{
$centerA = $this->prepareCenter(1, 'center');
$centerB = $this->prepareCenter(2, 'centerB');
$user = $this->prepareUser([
[
'center' => $centerA, 'permissionsGroup' => [
['scope' => null, 'role' => 'CHILL_ROLE'],
],
],
]);
$helper = $this->getAuthorizationHelper();
$this->assertFalse($helper->userHasAccess($user, $centerB, 'CHILL_ROLE'));
$this->assertTrue($helper->userHasAccess($user, $centerA, 'CHILL_ROLE'));
}
public function testUserHasAccessMultiCenterEntityWithoutScope() public function testUserHasAccessMultiCenterEntityWithoutScope()
{ {
$center = $this->prepareCenter(1, 'center'); $center = $this->prepareCenter(1, 'center');
@ -515,10 +534,10 @@ final class AuthorizationHelperTest extends KernelTestCase
public function testUserHasNoAccessEntityMultiScope() public function testUserHasNoAccessEntityMultiScope()
{ {
$centerA = $this->prepareCenter(1, 'center'); $centerA = $this->prepareCenter(1, 'center');
$centerB = $this->prepareCenter(1, 'centerB'); $centerB = $this->prepareCenter(2, 'centerB');
$scopeA = $this->prepareScope(2, 'other'); //the user will be granted this scope $scopeA = $this->prepareScope(3, 'other'); //the user will be granted this scope
$scopeB = $this->prepareScope(2, 'other'); //the user will be granted this scope $scopeB = $this->prepareScope(4, 'other'); //the user will be granted this scope
$scopeC = $this->prepareScope(2, 'other'); //the user will be granted this scope $scopeC = $this->prepareScope(5, 'other'); //the user will be granted this scope
$user = $this->prepareUser([ $user = $this->prepareUser([
[ [
'center' => $centerA, 'permissionsGroup' => [ 'center' => $centerA, 'permissionsGroup' => [
@ -539,9 +558,9 @@ final class AuthorizationHelperTest extends KernelTestCase
public function testUserHasNoAccessMultiCenterEntityWithoutScope() public function testUserHasNoAccessMultiCenterEntityWithoutScope()
{ {
$center = $this->prepareCenter(1, 'center'); $center = $this->prepareCenter(1, 'center');
$centerB = $this->prepareCenter(1, 'centerB'); $centerB = $this->prepareCenter(2, 'centerB');
$centerC = $this->prepareCenter(1, 'centerC'); $centerC = $this->prepareCenter(3, 'centerC');
$scopeB = $this->prepareScope(2, 'other'); //the user will be granted this scope $scopeB = $this->prepareScope(4, 'other'); //the user will be granted this scope
$user = $this->prepareUser([ $user = $this->prepareUser([
[ [
'center' => $center, 'permissionsGroup' => [ 'center' => $center, 'permissionsGroup' => [