VYPR
High severityNVD Advisory· Published Mar 12, 2023· Updated Mar 4, 2025

CVE-2022-48365

CVE-2022-48365

Description

An issue was discovered in eZ Platform Ibexa Kernel before 1.3.26. The Company admin role gives excessive privileges.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

The Company admin role in eZ Platform Ibexa Kernel before 1.3.26 grants excessive privileges, allowing unintended actions.

Vulnerability

Details

CVE-2022-48365 is a privilege escalation vulnerability found in eZ Platform Ibexa Kernel, specifically in the Company admin role. The issue arises because the role is granted excessive permissions, potentially enabling users with this role to perform actions beyond what is intended [1]. This affects versions prior to 1.3.26, as identified in the Ibexa security advisory [4].

Exploitation

The vulnerability can be exploited by any user assigned the Company admin role. No special authentication or network position is required beyond having that role. An attacker with this role can leverage the excessive privileges to conduct unauthorized operations within the system [4].

Impact

If exploited, an attacker with the Company admin role could gain elevated privileges, potentially allowing them to access or modify sensitive data, disrupt system functionality, or perform other administrative actions without proper authorization [4]. The severity is rated as high, as the role could be abused to compromise the integrity and confidentiality of the system.

Mitigation

A patch is available in Ibexa DXP v3.3.28, v4.2.3, and eZ Platform v2.5.31, corresponding to the fix in Ibexa Kernel 1.3.26. Users are strongly advised to upgrade immediately [4]. No workarounds are documented; updating to the patched version is the only effective mitigation.

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
ezsystems/ezpublish-kernelPackagist
>= 7.5.0, < 7.5.307.5.30
ezsystems/ezplatform-kernelPackagist
>= 1.3.0, < 1.3.261.3.26

Affected products

4

Patches

1
957e67a08af2

Merge pull request from GHSA-99r3-xmmq-7q7g

https://github.com/ezsystems/ezpublish-kernelDawid ParafińskiNov 10, 2022via ghsa
13 files changed · +1383 1
  • eZ/Publish/Core/settings/policies.yml+1 1 modified
    @@ -30,7 +30,7 @@ parameters:
                 administrate: ~
     
             role:
    -            assign: ~
    +            assign: { MemberOf: true, Role: true }
                 update: ~
                 create: ~
                 delete: ~
    
  • eZ/Publish/Core/settings/roles.yml+12 0 modified
    @@ -146,3 +146,15 @@ services:
             class: "%ezpublish.api.role.limitation_type.blocking.class%"
             arguments: ['AntiSpam']
             tags: [{name: ezpublish.limitationType, alias: AntiSpam}]
    +
    +    Ibexa\Core\Limitation\MemberOfLimitationType:
    +        arguments:
    +            $persistence: '@ezpublish.api.persistence_handler'
    +        tags:
    +            - { name: ezpublish.limitationType, alias: MemberOf }
    +
    +    Ibexa\Core\Limitation\RoleLimitationType:
    +        arguments:
    +            $persistence: '@ezpublish.api.persistence_handler'
    +        tags:
    +            - { name: ezpublish.limitationType, alias: Role }
    
  • phpunit-integration-legacy.xml+3 0 modified
    @@ -73,6 +73,9 @@
             <testsuite name="gateway-integration">
                 <file>eZ/Publish/SPI/Tests/Search/Content/IndexerGatewayTest.php</file>
             </testsuite>
    +        <testsuite name="Ibexa\Tests\Integration\">
    +            <directory>tests/integration</directory>
    +        </testsuite>
         </testsuites>
         <filter>
             <whitelist>
    
  • phpunit.xml+3 0 modified
    @@ -73,6 +73,9 @@
         <testsuite name="eZ\Publish\API\Repository\Values\Content">
           <directory>eZ/Publish/API/Repository/Tests/Values/Content</directory>
         </testsuite>
    +    <testsuite name="Ibexa\Tests\Core\">
    +        <directory>tests/lib</directory>
    +    </testsuite>
       </testsuites>
       <filter>
         <whitelist>
    
  • src/contracts/Repository/Values/User/Limitation/MemberOfLimitation.php+21 0 added
    @@ -0,0 +1,21 @@
    +<?php
    +
    +/**
    + * @copyright Copyright (C) eZ Systems AS. All rights reserved.
    + * @license For full copyright and license information view LICENSE file distributed with this source code.
    + */
    +declare(strict_types=1);
    +
    +namespace Ibexa\Contracts\Core\Repository\Values\User\Limitation;
    +
    +use eZ\Publish\API\Repository\Values\User\Limitation;
    +
    +final class MemberOfLimitation extends Limitation
    +{
    +    public const IDENTIFIER = 'MemberOf';
    +
    +    public function getIdentifier(): string
    +    {
    +        return self::IDENTIFIER;
    +    }
    +}
    
  • src/contracts/Repository/Values/User/Limitation/RoleLimitation.php+21 0 added
    @@ -0,0 +1,21 @@
    +<?php
    +
    +/**
    + * @copyright Copyright (C) eZ Systems AS. All rights reserved.
    + * @license For full copyright and license information view LICENSE file distributed with this source code.
    + */
    +declare(strict_types=1);
    +
    +namespace Ibexa\Contracts\Core\Repository\Values\User\Limitation;
    +
    +use eZ\Publish\API\Repository\Values\User\Limitation;
    +
    +final class RoleLimitation extends Limitation
    +{
    +    public const IDENTIFIER = 'Role';
    +
    +    public function getIdentifier(): string
    +    {
    +        return self::IDENTIFIER;
    +    }
    +}
    
  • src/lib/Limitation/MemberOfLimitationType.php+201 0 added
    @@ -0,0 +1,201 @@
    +<?php
    +
    +/**
    + * @copyright Copyright (C) eZ Systems AS. All rights reserved.
    + * @license For full copyright and license information view LICENSE file distributed with this source code.
    + */
    +declare(strict_types=1);
    +
    +namespace Ibexa\Core\Limitation;
    +
    +use eZ\Publish\API\Repository\Exceptions\NotImplementedException;
    +use eZ\Publish\API\Repository\Values\User\User;
    +use eZ\Publish\API\Repository\Values\User\UserGroup;
    +use eZ\Publish\API\Repository\Values\User\UserGroupRoleAssignment;
    +use eZ\Publish\API\Repository\Values\User\UserReference as APIUserReference;
    +use eZ\Publish\API\Repository\Exceptions\NotFoundException;
    +use eZ\Publish\API\Repository\Values\User\UserRoleAssignment;
    +use eZ\Publish\API\Repository\Values\ValueObject;
    +use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException;
    +use eZ\Publish\Core\Base\Exceptions\InvalidArgumentType;
    +use eZ\Publish\Core\FieldType\ValidationError;
    +use eZ\Publish\Core\Limitation\AbstractPersistenceLimitationType;
    +use eZ\Publish\SPI\Limitation\Type as SPILimitationTypeInterface;
    +use eZ\Publish\API\Repository\Values\User\Limitation as APILimitationValue;
    +use Ibexa\Contracts\Core\Repository\Values\User\Limitation\MemberOfLimitation;
    +
    +final class MemberOfLimitationType extends AbstractPersistenceLimitationType implements SPILimitationTypeInterface
    +{
    +    public const SELF_USER_GROUP = -1;
    +
    +    /**
    +     * @throws \eZ\Publish\Core\Base\Exceptions\InvalidArgumentType
    +     */
    +    public function acceptValue(APILimitationValue $limitationValue): void
    +    {
    +        if (!$limitationValue instanceof MemberOfLimitation) {
    +            throw new InvalidArgumentType(
    +                '$limitationValue',
    +                MemberOfLimitation::class,
    +                $limitationValue
    +            );
    +        }
    +
    +        if (!is_array($limitationValue->limitationValues)) {
    +            throw new InvalidArgumentType(
    +                '$limitationValue->limitationValues',
    +                'array',
    +                $limitationValue->limitationValues
    +            );
    +        }
    +
    +        foreach ($limitationValue->limitationValues as $key => $id) {
    +            if (!is_int($id)) {
    +                throw new InvalidArgumentType("\$limitationValue->limitationValues[{$key}]", 'int|string', $id);
    +            }
    +        }
    +    }
    +
    +    public function validate(APILimitationValue $limitationValue)
    +    {
    +        $validationErrors = [];
    +
    +        foreach ($limitationValue->limitationValues as $key => $id) {
    +            if ($id === self::SELF_USER_GROUP) {
    +                continue;
    +            }
    +            try {
    +                $this->persistence->contentHandler()->loadContentInfo($id);
    +            } catch (NotFoundException $e) {
    +                $validationErrors[] = new ValidationError(
    +                    "limitationValues[%key%] => '%value%' does not exist in the backend",
    +                    null,
    +                    [
    +                        'value' => $id,
    +                        'key' => $key,
    +                    ]
    +                );
    +            }
    +        }
    +
    +        return $validationErrors;
    +    }
    +
    +    /**
    +     * @param mixed[] $limitationValues
    +     *
    +     * @return \eZ\Publish\API\Repository\Values\User\Limitation
    +     */
    +    public function buildValue(array $limitationValues): APILimitationValue
    +    {
    +        return new MemberOfLimitation(['limitationValues' => $limitationValues]);
    +    }
    +
    +    public function evaluate(APILimitationValue $value, APIUserReference $currentUser, ValueObject $object, array $targets = null)
    +    {
    +        if (!$value instanceof MemberOfLimitation) {
    +            throw new InvalidArgumentException(
    +                '$value',
    +                sprintf('Must be of type: %s', MemberOfLimitation::class)
    +            );
    +        }
    +
    +        if (!$object instanceof User
    +            && !$object instanceof UserGroup
    +            && !$object instanceof UserRoleAssignment
    +            && !$object instanceof UserGroupRoleAssignment
    +        ) {
    +            return self::ACCESS_ABSTAIN;
    +        }
    +
    +        if ($object instanceof User) {
    +            return $this->evaluateUser($value, $object, $currentUser);
    +        }
    +
    +        if ($object instanceof UserGroup) {
    +            return $this->evaluateUserGroup($value, $object, $currentUser);
    +        }
    +
    +        if ($object instanceof UserRoleAssignment) {
    +            return $this->evaluateUser($value, $object->getUser(), $currentUser);
    +        }
    +
    +        if ($object instanceof UserGroupRoleAssignment) {
    +            return $this->evaluateUserGroup($value, $object->getUserGroup(), $currentUser);
    +        }
    +
    +        return self::ACCESS_DENIED;
    +    }
    +
    +    public function getCriterion(APILimitationValue $value, APIUserReference $currentUser)
    +    {
    +        throw new NotImplementedException('Member of Limitation Criterion');
    +    }
    +
    +    public function valueSchema()
    +    {
    +        throw new NotImplementedException(__METHOD__);
    +    }
    +
    +    private function evaluateUser(MemberOfLimitation $value, User $object, APIUserReference $currentUser): bool
    +    {
    +        if (empty($value->limitationValues)) {
    +            return self::ACCESS_DENIED;
    +        }
    +
    +        $userLocations = $this->persistence->locationHandler()->loadLocationsByContent($object->getUserId());
    +
    +        $userGroups = [];
    +        foreach ($userLocations as $userLocation) {
    +            $userGroups[] = $this->persistence->locationHandler()->load($userLocation->parentId);
    +        }
    +        $userGroupsIdList = array_column($userGroups, 'contentId');
    +        $limitationValuesUserGroupsIdList = $value->limitationValues;
    +
    +        if (in_array(self::SELF_USER_GROUP, $limitationValuesUserGroupsIdList)) {
    +            $currentUserGroupsIdList = $this->getCurrentUserGroupsIdList($currentUser);
    +
    +            // Granted, if current user is in exactly those same groups
    +            if (count(array_intersect($userGroupsIdList, $currentUserGroupsIdList)) === count($userGroupsIdList)) {
    +                return self::ACCESS_GRANTED;
    +            }
    +
    +            // Unset SELF value, for next check
    +            $key = array_search(self::SELF_USER_GROUP, $limitationValuesUserGroupsIdList);
    +            unset($limitationValuesUserGroupsIdList[$key]);
    +        }
    +
    +        // Granted, if limitationValues matched user groups 1:1
    +        if (!empty($limitationValuesUserGroupsIdList)
    +            && empty(array_diff($userGroupsIdList, $limitationValuesUserGroupsIdList))
    +        ) {
    +            return self::ACCESS_GRANTED;
    +        }
    +
    +        return self::ACCESS_DENIED;
    +    }
    +
    +    private function evaluateUserGroup(MemberOfLimitation $value, UserGroup $userGroup, APIUserReference $currentUser): bool
    +    {
    +        $limitationValuesUserGroupsIdList = $value->limitationValues;
    +        if (in_array(self::SELF_USER_GROUP, $limitationValuesUserGroupsIdList)) {
    +            $limitationValuesUserGroupsIdList = $this->getCurrentUserGroupsIdList($currentUser);
    +        }
    +
    +        return in_array($userGroup->id, $limitationValuesUserGroupsIdList);
    +    }
    +
    +    private function getCurrentUserGroupsIdList(APIUserReference $currentUser): array
    +    {
    +        $currentUserLocations = $this->persistence->locationHandler()->loadLocationsByContent($currentUser->getUserId());
    +        $currentUserGroups = [];
    +        foreach ($currentUserLocations as $currentUserLocation) {
    +            $currentUserGroups[] = $this->persistence->locationHandler()->load($currentUserLocation->parentId);
    +        }
    +
    +        return array_column(
    +            $currentUserGroups,
    +            'contentId'
    +        );
    +    }
    +}
    
  • src/lib/Limitation/RoleLimitationType.php+143 0 added
    @@ -0,0 +1,143 @@
    +<?php
    +
    +/**
    + * @copyright Copyright (C) eZ Systems AS. All rights reserved.
    + * @license For full copyright and license information view LICENSE file distributed with this source code.
    + */
    +declare(strict_types=1);
    +
    +namespace Ibexa\Core\Limitation;
    +
    +use eZ\Publish\API\Repository\Exceptions\NotImplementedException;
    +use eZ\Publish\API\Repository\Values\User\Role;
    +use eZ\Publish\API\Repository\Values\User\User;
    +use eZ\Publish\API\Repository\Values\User\UserGroup;
    +use eZ\Publish\API\Repository\Values\User\UserGroupRoleAssignment;
    +use eZ\Publish\API\Repository\Values\User\UserReference as APIUserReference;
    +use eZ\Publish\API\Repository\Exceptions\NotFoundException;
    +use eZ\Publish\API\Repository\Values\User\UserRoleAssignment;
    +use eZ\Publish\API\Repository\Values\ValueObject;
    +use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException;
    +use eZ\Publish\Core\Base\Exceptions\InvalidArgumentType;
    +use eZ\Publish\Core\FieldType\ValidationError;
    +use eZ\Publish\Core\Limitation\AbstractPersistenceLimitationType;
    +use eZ\Publish\SPI\Limitation\Type as SPILimitationTypeInterface;
    +use eZ\Publish\API\Repository\Values\User\Limitation as APILimitationValue;
    +use Ibexa\Contracts\Core\Repository\Values\User\Limitation\RoleLimitation;
    +
    +final class RoleLimitationType extends AbstractPersistenceLimitationType implements SPILimitationTypeInterface
    +{
    +    /**
    +     * @throws \eZ\Publish\Core\Base\Exceptions\InvalidArgumentType
    +     */
    +    public function acceptValue(APILimitationValue $limitationValue): void
    +    {
    +        if (!$limitationValue instanceof RoleLimitation) {
    +            throw new InvalidArgumentType(
    +                '$limitationValue',
    +                RoleLimitation::class,
    +                $limitationValue
    +            );
    +        }
    +
    +        if (!is_array($limitationValue->limitationValues)) {
    +            throw new InvalidArgumentType(
    +                '$limitationValue->limitationValues',
    +                'array',
    +                $limitationValue->limitationValues
    +            );
    +        }
    +
    +        foreach ($limitationValue->limitationValues as $key => $id) {
    +            if (!is_int($id)) {
    +                throw new InvalidArgumentType("\$limitationValue->limitationValues[{$key}]", 'int|string', $id);
    +            }
    +        }
    +    }
    +
    +    public function validate(APILimitationValue $limitationValue)
    +    {
    +        $validationErrors = [];
    +
    +        foreach ($limitationValue->limitationValues as $key => $id) {
    +            try {
    +                $this->persistence->userHandler()->loadRole($id);
    +            } catch (NotFoundException $e) {
    +                $validationErrors[] = new ValidationError(
    +                    "limitationValues[%key%] => '%value%' does not exist in the backend",
    +                    null,
    +                    [
    +                        'value' => $id,
    +                        'key' => $key,
    +                    ]
    +                );
    +            }
    +        }
    +
    +        return $validationErrors;
    +    }
    +
    +    /**
    +     * @param mixed[] $limitationValues
    +     *
    +     * @return \eZ\Publish\API\Repository\Values\User\Limitation
    +     */
    +    public function buildValue(array $limitationValues): APILimitationValue
    +    {
    +        return new RoleLimitation(['limitationValues' => $limitationValues]);
    +    }
    +
    +    public function evaluate(APILimitationValue $value, APIUserReference $currentUser, ValueObject $object, array $targets = null)
    +    {
    +        if (!$value instanceof RoleLimitation) {
    +            throw new InvalidArgumentException(
    +                '$value',
    +                sprintf('Must be of type: %s', RoleLimitation::class)
    +            );
    +        }
    +
    +        if (
    +            !$object instanceof Role
    +            && !$object instanceof UserRoleAssignment
    +            && !$object instanceof UserGroupRoleAssignment
    +            && ($targets === null && ($object instanceof User || $object instanceof UserGroup))
    +        ) {
    +            return self::ACCESS_ABSTAIN;
    +        }
    +
    +        if ($targets !== null) {
    +            foreach ($targets as $target) {
    +                if ($target instanceof Role && !$this->evaluateRole($value, $target)) {
    +                    return self::ACCESS_DENIED;
    +                }
    +
    +                return self::ACCESS_GRANTED;
    +            }
    +        }
    +
    +        if ($object instanceof Role) {
    +            return $this->evaluateRole($value, $object);
    +        }
    +
    +        if ($object instanceof UserRoleAssignment || $object instanceof UserGroupRoleAssignment) {
    +            return $this->evaluateRole($value, $object->getRole());
    +        }
    +
    +        return self::ACCESS_DENIED;
    +    }
    +
    +    public function getCriterion(APILimitationValue $value, APIUserReference $currentUser)
    +    {
    +        throw new NotImplementedException('Role Limitation Criterion');
    +    }
    +
    +    public function valueSchema()
    +    {
    +        throw new NotImplementedException(__METHOD__);
    +    }
    +
    +    private function evaluateRole(RoleLimitation $value, Role $role): bool
    +    {
    +        return in_array($role->id, $value->limitationValues);
    +    }
    +}
    
  • tests/integration/Core/.gitkeep+0 0 removed
  • tests/integration/Core/Limitation/MemberOfLimitationTest.php+74 0 added
    @@ -0,0 +1,74 @@
    +<?php
    +
    +/**
    + * @copyright Copyright (C) eZ Systems AS. All rights reserved.
    + * @license For full copyright and license information view LICENSE file distributed with this source code.
    + */
    +declare(strict_types=1);
    +
    +namespace Ibexa\Tests\Integration\Core\Limitation;
    +
    +use eZ\Publish\API\Repository\Repository;
    +use eZ\Publish\API\Repository\Tests\Limitation\PermissionResolver\BaseLimitationIntegrationTest;
    +use Ibexa\Contracts\Core\Repository\Values\User\Limitation\MemberOfLimitation;
    +use Ibexa\Core\Limitation\MemberOfLimitationType;
    +
    +class MemberOfLimitationTest extends BaseLimitationIntegrationTest
    +{
    +    private const ADMIN_GROUP_ID = 14;
    +    private const USERS_GROUP_ID = 4;
    +
    +    public function userPermissionLimitationProvider(): array
    +    {
    +        $allowInAdministratorsLimitation = new MemberOfLimitation();
    +        $allowInAdministratorsLimitation->limitationValues[] = self::ADMIN_GROUP_ID;
    +
    +        $allowInUsersLimitation = new MemberOfLimitation();
    +        $allowInUsersLimitation->limitationValues[] = self::USERS_GROUP_ID;
    +
    +        $allowInSelfGroupLimitation = new MemberOfLimitation();
    +        $allowInSelfGroupLimitation->limitationValues[] = MemberOfLimitationType::SELF_USER_GROUP;
    +
    +        return [
    +            [[$allowInAdministratorsLimitation], false],
    +            [[$allowInUsersLimitation], true],
    +            [[$allowInSelfGroupLimitation], true],
    +        ];
    +    }
    +
    +    /**
    +     * @dataProvider userPermissionLimitationProvider
    +     */
    +    public function testCanUserAssignRoleToUser(array $limitations, bool $expectedResult): void
    +    {
    +        $repository = $this->getRepository();
    +        $roleService = $repository->getRoleService();
    +        $userService = $repository->getUserService();
    +
    +        $adminRoleThatWillBeSet = $roleService->loadRoleByIdentifier('Administrator');
    +        $this->loginAsEditorUserWithLimitations('role', 'assign', $limitations);
    +
    +        $this->assertCanUser(
    +            $expectedResult,
    +            'role',
    +            'assign',
    +            $limitations,
    +            $userService->loadUser($this->permissionResolver->getCurrentUserReference()->getUserId()),
    +            [$adminRoleThatWillBeSet]
    +        );
    +
    +        $this->assertCanUser(
    +            $expectedResult,
    +            'role',
    +            'assign',
    +            $limitations,
    +            $repository->sudo(
    +                static function (Repository $repository) {
    +                    return $repository->getUserService()->loadUserGroup(self::USERS_GROUP_ID);
    +                },
    +                $repository
    +            ),
    +            [$adminRoleThatWillBeSet]
    +        );
    +    }
    +}
    
  • tests/integration/Core/Limitation/RoleLimitationTest.php+69 0 added
    @@ -0,0 +1,69 @@
    +<?php
    +
    +/**
    + * @copyright Copyright (C) eZ Systems AS. All rights reserved.
    + * @license For full copyright and license information view LICENSE file distributed with this source code.
    + */
    +declare(strict_types=1);
    +
    +namespace Ibexa\Tests\Integration\Core\Limitation;
    +
    +use eZ\Publish\API\Repository\Repository;
    +use eZ\Publish\API\Repository\Tests\Limitation\PermissionResolver\BaseLimitationIntegrationTest;
    +use Ibexa\Contracts\Core\Repository\Values\User\Limitation\RoleLimitation;
    +
    +class RoleLimitationTest extends BaseLimitationIntegrationTest
    +{
    +    private const USERS_GROUP_ID = 4;
    +
    +    public function userPermissionLimitationProvider(): array
    +    {
    +        $allowEditorLimitation = new RoleLimitation();
    +        $roleService = $this->getRepository()->getRoleService();
    +        $allowEditorLimitation->limitationValues[] = $roleService->loadRoleByIdentifier('Editor')->id;
    +
    +        $allowAdministratorLimitation = new RoleLimitation();
    +        $allowAdministratorLimitation->limitationValues[] = $roleService->loadRoleByIdentifier('Administrator')->id;
    +
    +        return [
    +            [[$allowEditorLimitation], false],
    +            [[$allowAdministratorLimitation], true],
    +        ];
    +    }
    +
    +    /**
    +     * @dataProvider userPermissionLimitationProvider
    +     */
    +    public function testCanUserAssignRole(array $limitations, bool $expectedResult): void
    +    {
    +        $repository = $this->getRepository();
    +        $roleService = $repository->getRoleService();
    +        $userService = $repository->getUserService();
    +
    +        $adminRoleThatWillBeSet = $roleService->loadRoleByIdentifier('Administrator');
    +        $this->loginAsEditorUserWithLimitations('role', 'assign', $limitations);
    +
    +        $this->assertCanUser(
    +            $expectedResult,
    +            'role',
    +            'assign',
    +            $limitations,
    +            $userService->loadUser($this->permissionResolver->getCurrentUserReference()->getUserId()),
    +            [$adminRoleThatWillBeSet]
    +        );
    +
    +        $this->assertCanUser(
    +            $expectedResult,
    +            'role',
    +            'assign',
    +            $limitations,
    +            $repository->sudo(
    +                static function (Repository $repository) {
    +                    return $repository->getUserService()->loadUserGroup(self::USERS_GROUP_ID);
    +                },
    +                $repository
    +            ),
    +            [$adminRoleThatWillBeSet]
    +        );
    +    }
    +}
    
  • tests/lib/Limitation/MemberOfLimitationTypeTest.php+517 0 added
    @@ -0,0 +1,517 @@
    +<?php
    +
    +/**
    + * @copyright Copyright (C) eZ Systems AS. All rights reserved.
    + * @license For full copyright and license information view LICENSE file distributed with this source code.
    + */
    +declare(strict_types=1);
    +
    +namespace Ibexa\Tests\Core\Limitation;
    +
    +use eZ\Publish\API\Repository\Values\Content\ContentInfo;
    +use eZ\Publish\API\Repository\Values\ValueObject;
    +use eZ\Publish\Core\Base\Exceptions\InvalidArgumentType;
    +use eZ\Publish\Core\Base\Exceptions\NotFoundException;
    +use eZ\Publish\Core\Limitation\Tests\Base;
    +use eZ\Publish\Core\Persistence\Legacy\Content\Handler as ContentHandlerInterface;
    +use eZ\Publish\Core\Repository\Values\User\UserGroupRoleAssignment;
    +use eZ\Publish\SPI\Persistence\Content\Location;
    +use eZ\Publish\SPI\Persistence\Content\Location\Handler as LocationHandlerInterface;
    +use eZ\Publish\Core\Repository\Values\Content\Content;
    +use eZ\Publish\Core\Repository\Values\Content\VersionInfo;
    +use eZ\Publish\Core\Repository\Values\User\Role;
    +use eZ\Publish\Core\Repository\Values\User\User;
    +use eZ\Publish\Core\Repository\Values\User\UserGroup;
    +use eZ\Publish\Core\Repository\Values\User\UserRoleAssignment;
    +use Ibexa\Contracts\Core\Repository\Values\User\Limitation\MemberOfLimitation;
    +use Ibexa\Core\Limitation\MemberOfLimitationType;
    +
    +class MemberOfLimitationTypeTest extends Base
    +{
    +    /** @var \Ibexa\Core\Limitation\MemberOfLimitationType */
    +    private $limitationType;
    +
    +    protected function setUp(): void
    +    {
    +        parent::setUp();
    +
    +        $this->limitationType = new MemberOfLimitationType(
    +            $this->getPersistenceMock()
    +        );
    +    }
    +
    +    /**
    +     * @dataProvider providerForTestAcceptValue
    +     */
    +    public function testAcceptValue(MemberOfLimitation $limitation): void
    +    {
    +        $this->expectNotToPerformAssertions();
    +        $this->limitationType->acceptValue($limitation);
    +    }
    +
    +    public function providerForTestAcceptValue(): array
    +    {
    +        return [
    +            [
    +                new MemberOfLimitation([
    +                    'limitationValues' => [],
    +                ]),
    +            ],
    +            [
    +                new MemberOfLimitation([
    +                    'limitationValues' => [MemberOfLimitationType::SELF_USER_GROUP, 8],
    +                ]),
    +            ],
    +        ];
    +    }
    +
    +    /**
    +     * @dataProvider providerForTestAcceptValueException
    +     */
    +    public function testAcceptValueException(MemberOfLimitation $limitation): void
    +    {
    +        $this->expectException(InvalidArgumentType::class);
    +        $this->limitationType->acceptValue($limitation);
    +    }
    +
    +    public function providerForTestAcceptValueException(): array
    +    {
    +        return [
    +            [
    +                new MemberOfLimitation([
    +                    'limitationValues' => 1,
    +                ]),
    +            ],
    +            [
    +                new MemberOfLimitation([
    +                    'limitationValues' => null,
    +                ]),
    +            ],
    +            [
    +                new MemberOfLimitation([
    +                    'limitationValues' => 'string',
    +                ]),
    +            ],
    +            [
    +                new MemberOfLimitation([
    +                    'limitationValues' => ['string'],
    +                ]),
    +            ],
    +        ];
    +    }
    +
    +    /**
    +     * @dataProvider providerForTestAcceptValue
    +     */
    +    public function testValidatePass(MemberOfLimitation $limitation): void
    +    {
    +        $contentHandlerMock = $this->createMock(ContentHandlerInterface::class);
    +
    +        $contentHandlerMock
    +            ->method('loadContentInfo')
    +            ->with(8);
    +
    +        $this->getPersistenceMock()
    +            ->method('contentHandler')
    +            ->willReturn($contentHandlerMock);
    +
    +        $validationErrors = $this->limitationType->validate($limitation);
    +
    +        self::assertEmpty($validationErrors);
    +    }
    +
    +    /**
    +     * @dataProvider providerForTestValidateError
    +     */
    +    public function testValidateError(MemberOfLimitation $limitation, int $errorCount): void
    +    {
    +        $contentHandlerMock = $this->createMock(ContentHandlerInterface::class);
    +
    +        if ($limitation->limitationValues !== null) {
    +            $contentHandlerMock
    +                ->method('loadContentInfo')
    +                ->withConsecutive([14], [18])
    +                ->willReturnOnConsecutiveCalls(
    +                    $this->throwException(new NotFoundException('UserGroup', 18)),
    +                    new ContentInfo()
    +                );
    +
    +            $this->getPersistenceMock()
    +                ->method('contentHandler')
    +                ->willReturn($contentHandlerMock);
    +        }
    +
    +        $validationErrors = $this->limitationType->validate($limitation);
    +        self::assertCount($errorCount, $validationErrors);
    +    }
    +
    +    public function providerForTestValidateError()
    +    {
    +        return [
    +            [
    +                new MemberOfLimitation([
    +                    'limitationValues' => [14, 18],
    +                ]),
    +                1,
    +            ],
    +        ];
    +    }
    +
    +    /**
    +     * @dataProvider providerForTestEvaluate
    +     */
    +    public function testEvaluate(
    +        MemberOfLimitation $limitation,
    +        ValueObject $object,
    +        ?bool $expected
    +    ): void {
    +        $locationHandlerMock = $this->createMock(LocationHandlerInterface::class);
    +
    +        if ($object instanceof User || $object instanceof UserRoleAssignment) {
    +            $locationHandlerMock
    +                ->method('loadLocationsByContent')
    +                ->with($object instanceof User ? $object->getUserId() : $object->getUser()->getUserId())
    +                ->willReturn([
    +                    new Location(['parentId' => 13]),
    +                    new Location(['parentId' => 14]),
    +                ]);
    +
    +            $locationHandlerMock
    +                ->method('load')
    +                ->withConsecutive(
    +                    [13], [14]
    +                )
    +                ->willReturnOnConsecutiveCalls(
    +                    new Location(['contentId' => 14]),
    +                    new Location(['contentId' => 25])
    +                );
    +
    +            $this->getPersistenceMock()
    +                ->method('locationHandler')
    +                ->willReturn($locationHandlerMock);
    +        }
    +
    +        $value = (new MemberOfLimitationType($this->getPersistenceMock()))->evaluate(
    +            $limitation,
    +            $this->getUserMock(),
    +            $object
    +        );
    +
    +        self::assertEquals($expected, $value);
    +    }
    +
    +    public function providerForTestEvaluate()
    +    {
    +        return [
    +            'valid_group_limitation' => [
    +                'limitation' => new MemberOfLimitation([
    +                    'limitationValues' => [14, 18],
    +                ]),
    +                'object' => new UserGroup([
    +                    'content' => new Content([
    +                        'versionInfo' => new VersionInfo([
    +                            'contentInfo' => new ContentInfo([
    +                                'id' => 14,
    +                            ]),
    +                        ]),
    +                    ]),
    +                ]),
    +                'expected' => true,
    +            ],
    +            'allow_non_user_groups_limitation' => [
    +                'limitation' => new MemberOfLimitation([
    +                    'limitationValues' => [],
    +                ]),
    +                'object' => new UserGroup([
    +                    'content' => new Content([
    +                        'versionInfo' => new VersionInfo([
    +                            'contentInfo' => new ContentInfo([
    +                                'id' => 14,
    +                            ]),
    +                        ]),
    +                    ]),
    +                ]),
    +                'expected' => false,
    +            ],
    +            'pass_to_next_limitation' => [
    +                'limitation' => new MemberOfLimitation([
    +                    'limitationValues' => [14, 18],
    +                ]),
    +                'object' => new VersionInfo([
    +                    'contentInfo' => new ContentInfo([
    +                        'id' => 14,
    +                    ]),
    +                ]),
    +                'expected' => null,
    +            ],
    +            'invalid_user_must_have_permission_to_every_group_user_is_in' => [
    +                'limitation' => new MemberOfLimitation([
    +                    'limitationValues' => [25, 10],
    +                ]),
    +                'object' => new User([
    +                    'content' => new Content([
    +                        'versionInfo' => new VersionInfo([
    +                            'contentInfo' => new ContentInfo([
    +                                'id' => 66,
    +                            ]),
    +                        ]),
    +                    ]),
    +                ]),
    +                'expected' => false,
    +            ],
    +            'user_must_have_permission_to_every_group_user_is_in' => [
    +                'limitation' => new MemberOfLimitation([
    +                    'limitationValues' => [14, 25],
    +                ]),
    +                'object' => new User([
    +                    'content' => new Content([
    +                        'versionInfo' => new VersionInfo([
    +                            'contentInfo' => new ContentInfo([
    +                                'id' => 66,
    +                            ]),
    +                        ]),
    +                    ]),
    +                ]),
    +                'expected' => true,
    +            ],
    +            'user_role_assigment_valid' => [
    +                'limitation' => new MemberOfLimitation([
    +                    'limitationValues' => [14, 25],
    +                ]),
    +                'object' => new UserRoleAssignment([
    +                    'user' => new User([
    +                        'content' => new Content([
    +                            'versionInfo' => new VersionInfo([
    +                                'contentInfo' => new ContentInfo([
    +                                    'id' => 66,
    +                                ]),
    +                            ]),
    +                        ]),
    +                    ]),
    +                ]),
    +                'expected' => true,
    +            ],
    +            'user_role_assigment_invalid_user' => [
    +                'limitation' => new MemberOfLimitation([
    +                    'limitationValues' => [25, 10],
    +                ]),
    +                'object' => new UserRoleAssignment([
    +                    'user' => new User([
    +                        'content' => new Content([
    +                            'versionInfo' => new VersionInfo([
    +                                'contentInfo' => new ContentInfo([
    +                                    'id' => 66,
    +                                ]),
    +                            ]),
    +                        ]),
    +                    ]),
    +                    'role' => new Role(['id' => 7]),
    +                ]),
    +                'expected' => false,
    +            ],
    +            'user_group_role_assigment_valid' => [
    +                'limitation' => new MemberOfLimitation([
    +                    'limitationValues' => [14, 18],
    +                ]),
    +                'object' => new UserGroupRoleAssignment([
    +                    'userGroup' => new UserGroup([
    +                        'content' => new Content([
    +                            'versionInfo' => new VersionInfo([
    +                                'contentInfo' => new ContentInfo([
    +                                    'id' => 14,
    +                                ]),
    +                            ]),
    +                        ]),
    +                    ]),
    +                    'role' => new Role(['id' => 7]),
    +                ]),
    +                'expected' => true,
    +            ],
    +            'user_group_role_assigment_invalid_user_group' => [
    +                'limitation' => new MemberOfLimitation([
    +                    'limitationValues' => [18],
    +                ]),
    +                'object' => new UserGroupRoleAssignment([
    +                    'userGroup' => new UserGroup([
    +                        'content' => new Content([
    +                            'versionInfo' => new VersionInfo([
    +                                'contentInfo' => new ContentInfo([
    +                                    'id' => 14,
    +                                ]),
    +                            ]),
    +                        ]),
    +                    ]),
    +                    'role' => new Role(['id' => 7]),
    +                ]),
    +                'expected' => false,
    +            ],
    +        ];
    +    }
    +
    +    /**
    +     * @param \eZ\Publish\API\Repository\Values\User\User|\eZ\Publish\API\Repository\Values\User\UserRoleAssignment $object
    +     * @dataProvider providerForTestEvaluateSelfGroup
    +     */
    +    public function testEvaluateSelfGroup(
    +        MemberOfLimitation $limitation,
    +        ValueObject $object,
    +        array $currentUserGroupLocations,
    +        ?bool $expected
    +    ): void {
    +        $locationHandlerMock = $this->createMock(LocationHandlerInterface::class);
    +
    +        $currentUserLocation = [];
    +
    +        foreach ($currentUserGroupLocations as $groupLocation) {
    +            $currentUserLocation[] = new Location(['parentId' => $groupLocation->contentId - 1]);
    +        }
    +        $locationHandlerMock
    +            ->method('loadLocationsByContent')
    +            ->withConsecutive(
    +                [$object instanceof User ? $object->getUserId() : $object->getUser()->getUserId()],
    +                [$this->getUserMock()->getUserId()]
    +            )
    +            ->willReturnOnConsecutiveCalls(
    +                [
    +                    new Location(['parentId' => 13]),
    +                    new Location(['parentId' => 43]),
    +                ],
    +                $currentUserLocation
    +            );
    +
    +        $locationHandlerMock
    +            ->method('load')
    +            ->withConsecutive(
    +                [13], [43]
    +            )
    +            ->willReturnOnConsecutiveCalls(
    +                new Location(['contentId' => 14]),
    +                new Location(['contentId' => 44]),
    +                ...$currentUserGroupLocations
    +            );
    +
    +        $this->getPersistenceMock()
    +            ->method('locationHandler')
    +            ->willReturn($locationHandlerMock);
    +
    +        $this->getPersistenceMock()
    +            ->method('locationHandler')
    +            ->willReturn($locationHandlerMock);
    +
    +        $value = (new MemberOfLimitationType($this->getPersistenceMock()))->evaluate(
    +            $limitation,
    +            $this->getUserMock(),
    +            $object
    +        );
    +
    +        self::assertEquals($expected, $value);
    +    }
    +
    +    public function providerForTestEvaluateSelfGroup(): array
    +    {
    +        return [
    +            'role_assign_to_user_in_same_group' => [
    +                'limitation' => new MemberOfLimitation([
    +                    'limitationValues' => [MemberOfLimitationType::SELF_USER_GROUP],
    +                ]),
    +                'object' => new User([
    +                    'content' => new Content([
    +                        'versionInfo' => new VersionInfo([
    +                            'contentInfo' => new ContentInfo([
    +                                'id' => 66,
    +                            ]),
    +                        ]),
    +                    ]),
    +                ]),
    +                'currentUserGroupLocations' => [
    +                    new Location(['contentId' => 14]),
    +                    new Location(['contentId' => 44]),
    +                    new Location(['contentId' => 55]),
    +                ],
    +                'expected' => true,
    +            ],
    +            'role_assign_to_user_in_other_group' => [
    +                'limitation' => new MemberOfLimitation([
    +                    'limitationValues' => [MemberOfLimitationType::SELF_USER_GROUP],
    +                ]),
    +                'object' => new User([
    +                    'content' => new Content([
    +                        'versionInfo' => new VersionInfo([
    +                            'contentInfo' => new ContentInfo([
    +                                'id' => 66,
    +                            ]),
    +                        ]),
    +                    ]),
    +                ]),
    +                'currentUserGroupLocations' => [
    +                    new Location(['contentId' => 11]),
    +                    new Location(['contentId' => 14]),
    +                ],
    +                'expected' => false,
    +            ],
    +            'role_assign_to_user_in_overlapped_groups' => [
    +                'limitation' => new MemberOfLimitation([
    +                    'limitationValues' => [MemberOfLimitationType::SELF_USER_GROUP, 14, 44],
    +                ]),
    +                'object' => new User([
    +                    'content' => new Content([
    +                        'versionInfo' => new VersionInfo([
    +                            'contentInfo' => new ContentInfo([
    +                                'id' => 66,
    +                            ]),
    +                        ]),
    +                    ]),
    +                ]),
    +                'currentUserGroupLocations' => [
    +                    new Location(['contentId' => 1]),
    +                ],
    +                'expected' => true,
    +            ],
    +            'user_role_assigment_to_user_in_same_group' => [
    +                'limitation' => new MemberOfLimitation([
    +                    'limitationValues' => [MemberOfLimitationType::SELF_USER_GROUP],
    +                ]),
    +                'object' => new UserRoleAssignment([
    +                    'user' => new User([
    +                        'content' => new Content([
    +                            'versionInfo' => new VersionInfo([
    +                                'contentInfo' => new ContentInfo([
    +                                    'id' => 66,
    +                                ]),
    +                            ]),
    +                        ]),
    +                    ]),
    +                    'role' => new Role(['id' => 4]),
    +                ]),
    +                'currentUserGroupLocations' => [
    +                    new Location(['contentId' => 14]),
    +                    new Location(['contentId' => 44]),
    +                    new Location(['contentId' => 55]),
    +                ],
    +                'expected' => true,
    +            ],
    +            'user_role_assigment_to_user_in_other_group' => [
    +                'limitation' => new MemberOfLimitation([
    +                    'limitationValues' => [MemberOfLimitationType::SELF_USER_GROUP],
    +                ]),
    +                'object' => new UserRoleAssignment([
    +                    'user' => new User([
    +                        'content' => new Content([
    +                            'versionInfo' => new VersionInfo([
    +                                'contentInfo' => new ContentInfo([
    +                                    'id' => 66,
    +                                ]),
    +                            ]),
    +                        ]),
    +                    ]),
    +                    'role' => new Role(['id' => 4]),
    +                ]),
    +                'currentUserGroupLocations' => [
    +                    new Location(['contentId' => 11]),
    +                    new Location(['contentId' => 14]),
    +                ],
    +                'expected' => false,
    +            ],
    +        ];
    +    }
    +}
    
  • tests/lib/Limitation/RoleLimitationTypeTest.php+318 0 added
    @@ -0,0 +1,318 @@
    +<?php
    +
    +/**
    + * @copyright Copyright (C) eZ Systems AS. All rights reserved.
    + * @license For full copyright and license information view LICENSE file distributed with this source code.
    + */
    +declare(strict_types=1);
    +
    +namespace Ibexa\Tests\Core\Limitation;
    +
    +use eZ\Publish\API\Repository\Values\Content\ContentInfo;
    +use eZ\Publish\API\Repository\Values\ValueObject;
    +use eZ\Publish\Core\Base\Exceptions\InvalidArgumentType;
    +use eZ\Publish\Core\Base\Exceptions\NotFoundException;
    +use eZ\Publish\Core\Limitation\Tests\Base;
    +use eZ\Publish\Core\Persistence\Legacy\User\Handler as UserHandlerInterface;
    +use eZ\Publish\Core\Persistence\Legacy\Content\Handler as ContentHandlerInterface;
    +use eZ\Publish\Core\Repository\Values\User\UserGroup;
    +use eZ\Publish\Core\Repository\Values\User\UserGroupRoleAssignment;
    +use eZ\Publish\SPI\Persistence\Content\Location;
    +use eZ\Publish\SPI\Persistence\Content\Location\Handler as LocationHandlerInterface;
    +use eZ\Publish\Core\Repository\Values\Content\Content;
    +use eZ\Publish\Core\Repository\Values\Content\VersionInfo;
    +use eZ\Publish\Core\Repository\Values\User\Role;
    +use eZ\Publish\Core\Repository\Values\User\User;
    +use eZ\Publish\Core\Repository\Values\User\UserRoleAssignment;
    +use Ibexa\Contracts\Core\Repository\Values\User\Limitation\RoleLimitation;
    +use Ibexa\Core\Limitation\RoleLimitationType;
    +
    +class RoleLimitationTypeTest extends Base
    +{
    +    /** @var \Ibexa\Core\Limitation\RoleLimitationType */
    +    private $limitationType;
    +
    +    protected function setUp(): void
    +    {
    +        parent::setUp();
    +
    +        $this->limitationType = new RoleLimitationType(
    +            $this->getPersistenceMock()
    +        );
    +    }
    +
    +    /**
    +     * @dataProvider providerForTestAcceptValue
    +     */
    +    public function testAcceptValue(RoleLimitation $limitation): void
    +    {
    +        $this->expectNotToPerformAssertions();
    +        $this->limitationType->acceptValue($limitation);
    +    }
    +
    +    public function providerForTestAcceptValue(): array
    +    {
    +        return [
    +            [
    +                new RoleLimitation([
    +                    'limitationValues' => [],
    +                ]),
    +            ],
    +            [
    +                new RoleLimitation([
    +                    'limitationValues' => [4, 8],
    +                ]),
    +            ],
    +        ];
    +    }
    +
    +    /**
    +     * @dataProvider providerForTestAcceptValueException
    +     */
    +    public function testAcceptValueException(RoleLimitation $limitation): void
    +    {
    +        $this->expectException(InvalidArgumentType::class);
    +        $this->limitationType->acceptValue($limitation);
    +    }
    +
    +    public function providerForTestAcceptValueException(): array
    +    {
    +        return [
    +            [
    +                new RoleLimitation([
    +                    'limitationValues' => 1,
    +                ]),
    +            ],
    +            [
    +                new RoleLimitation([
    +                    'limitationValues' => null,
    +                ]),
    +            ],
    +            [
    +                new RoleLimitation([
    +                    'limitationValues' => 'string',
    +                ]),
    +            ],
    +            [
    +                new RoleLimitation([
    +                    'limitationValues' => ['string'],
    +                ]),
    +            ],
    +        ];
    +    }
    +
    +    /**
    +     * @dataProvider providerForTestAcceptValue
    +     */
    +    public function testValidatePass(RoleLimitation $limitation): void
    +    {
    +        $userHandlerMock = $this->createMock(UserHandlerInterface::class);
    +        $contentHandlerMock = $this->createMock(ContentHandlerInterface::class);
    +
    +        if ($limitation->limitationValues !== null) {
    +            $userHandlerMock
    +                ->method('loadRole')
    +                ->withConsecutive([4, Role::STATUS_DEFINED], [8, Role::STATUS_DEFINED]);
    +
    +            $this->getPersistenceMock()
    +                ->method('userHandler')
    +                ->willReturn($userHandlerMock);
    +        }
    +
    +        if ($limitation->limitationValues !== null) {
    +            $contentHandlerMock
    +                ->method('loadContentInfo')
    +                ->withConsecutive([14], [21]);
    +
    +            $this->getPersistenceMock()
    +                ->method('contentHandler')
    +                ->willReturn($contentHandlerMock);
    +        }
    +
    +        $validationErrors = $this->limitationType->validate($limitation);
    +
    +        self::assertEmpty($validationErrors);
    +    }
    +
    +    /**
    +     * @dataProvider providerForTestValidateError
    +     */
    +    public function testValidateError(RoleLimitation $limitation, int $errorCount): void
    +    {
    +        $userHandlerMock = $this->createMock(UserHandlerInterface::class);
    +
    +        if ($limitation->limitationValues !== null) {
    +            $userHandlerMock
    +                ->method('loadRole')
    +                ->withConsecutive([4, Role::STATUS_DEFINED], [8, Role::STATUS_DEFINED])
    +                ->willReturnOnConsecutiveCalls(
    +                    $this->throwException(new NotFoundException('Role', 4)),
    +                    new Role()
    +                );
    +
    +            $this->getPersistenceMock()
    +                ->method('userHandler')
    +                ->willReturn($userHandlerMock);
    +        }
    +
    +        $validationErrors = $this->limitationType->validate($limitation);
    +        self::assertCount($errorCount, $validationErrors);
    +    }
    +
    +    public function providerForTestValidateError()
    +    {
    +        return [
    +            [
    +                new RoleLimitation([
    +                    'limitationValues' => [4, 8],
    +                ]),
    +                1,
    +            ],
    +        ];
    +    }
    +
    +    /**
    +     * @dataProvider providerForTestEvaluate
    +     */
    +    public function testEvaluate(
    +        RoleLimitation $limitation,
    +        ValueObject $object,
    +        ?array $targets,
    +        ?bool $expected
    +    ): void {
    +        $locationHandlerMock = $this->createMock(LocationHandlerInterface::class);
    +
    +        if ($object instanceof UserRoleAssignment) {
    +            $locationHandlerMock
    +                ->method('loadLocationsByContent')
    +                ->with($object instanceof User ? $object->getUserId() : $object->getUser()->getUserId())
    +                ->willReturn([
    +                    new Location(['contentId' => 14]),
    +                    new Location(['contentId' => 25]),
    +                ]);
    +
    +            $this->getPersistenceMock()
    +                ->method('locationHandler')
    +                ->willReturn($locationHandlerMock);
    +        }
    +
    +        $value = (new RoleLimitationType($this->getPersistenceMock()))->evaluate(
    +            $limitation,
    +            $this->getUserMock(),
    +            $object,
    +            $targets
    +        );
    +
    +        self::assertEquals($expected, $value);
    +    }
    +
    +    public function providerForTestEvaluate()
    +    {
    +        return [
    +            'valid_role_limitation' => [
    +                'limitation' => new RoleLimitation([
    +                    'limitationValues' => [4, 8],
    +                ]),
    +                'object' => new Role(['id' => 4]),
    +                'targets' => null,
    +                'expected' => true,
    +            ],
    +            'allow_non_role_limitation' => [
    +                'limitation' => new RoleLimitation([
    +                    'limitationValues' => [],
    +                ]),
    +                'object' => new Role(['id' => 4]),
    +                'targets' => null,
    +                'expected' => false,
    +            ],
    +            'pass_to_next_limitation' => [
    +                'limitation' => new RoleLimitation([
    +                    'limitationValues' => [4, 8],
    +                ]),
    +                'object' => new VersionInfo([
    +                    'contentInfo' => new ContentInfo([
    +                        'id' => 14,
    +                    ]),
    +                ]),
    +                'targets' => null,
    +                'expected' => null,
    +            ],
    +            'user_role_assigment_valid' => [
    +                'limitation' => new RoleLimitation([
    +                    'limitationValues' => [4, 8],
    +                ]),
    +                'object' => new UserRoleAssignment([
    +                    'user' => new User([
    +                        'content' => new Content([
    +                            'versionInfo' => new VersionInfo([
    +                                'contentInfo' => new ContentInfo([
    +                                    'id' => 66,
    +                                ]),
    +                            ]),
    +                        ]),
    +                    ]),
    +                    'role' => new Role(['id' => 4]),
    +                ]),
    +                'targets' => null,
    +                'expected' => true,
    +            ],
    +            'user_role_assigment_invalid_role' => [
    +                'limitation' => new RoleLimitation([
    +                    'limitationValues' => [4, 8],
    +                ]),
    +                'object' => new UserRoleAssignment([
    +                    'user' => new User([
    +                        'content' => new Content([
    +                            'versionInfo' => new VersionInfo([
    +                                'contentInfo' => new ContentInfo([
    +                                    'id' => 66,
    +                                ]),
    +                            ]),
    +                        ]),
    +                    ]),
    +                    'role' => new Role(['id' => 7]),
    +                ]),
    +                'targets' => null,
    +                'expected' => false,
    +            ],
    +            'user_group_role_assigment_valid' => [
    +                'limitation' => new RoleLimitation([
    +                    'limitationValues' => [4, 8],
    +                ]),
    +                'object' => new UserGroupRoleAssignment([
    +                    'userGroup' => new UserGroup([
    +                        'content' => new Content([
    +                            'versionInfo' => new VersionInfo([
    +                                'contentInfo' => new ContentInfo([
    +                                    'id' => 66,
    +                                ]),
    +                            ]),
    +                        ]),
    +                    ]),
    +                    'role' => new Role(['id' => 4]),
    +                ]),
    +                'targets' => null,
    +                'expected' => true,
    +            ],
    +            'user_group_role_assigment_invalid_role' => [
    +                'limitation' => new RoleLimitation([
    +                    'limitationValues' => [4, 8],
    +                ]),
    +                'object' => new UserGroupRoleAssignment([
    +                    'userGroup' => new UserGroup([
    +                        'content' => new Content([
    +                            'versionInfo' => new VersionInfo([
    +                                'contentInfo' => new ContentInfo([
    +                                    'id' => 66,
    +                                ]),
    +                            ]),
    +                        ]),
    +                    ]),
    +                    'role' => new Role(['id' => 7]),
    +                ]),
    +                'targets' => null,
    +                'expected' => false,
    +            ],
    +        ];
    +    }
    +}
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.