Skip to content

Commit 6cd2cb8

Browse files
authored
IBX-5026: Fixed subtree op. perm. checks for Content with multiple Locations
For more details see https://issues.ibexa.co/browse/IBX-5026 and #365 * Allowed user to move subtree if he doesn't have access to second content's location
1 parent ab38cbc commit 6cd2cb8

File tree

3 files changed

+84
-4
lines changed

3 files changed

+84
-4
lines changed

eZ/Publish/API/Repository/Tests/LocationServiceTest.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use eZ\Publish\API\Repository\Values\Content\Query;
2323
use eZ\Publish\API\Repository\Values\Content\Search\SearchHit;
2424
use eZ\Publish\API\Repository\Values\Content\URLAlias;
25+
use eZ\Publish\API\Repository\Values\User\Limitation\SubtreeLimitation;
2526
use eZ\Publish\Core\Repository\Values\Content\ContentUpdateStruct;
2627

2728
/**
@@ -3471,6 +3472,69 @@ public function testMoveSubtreeKeepsContentHiddenOnChildren(): void
34713472
}
34723473
}
34733474

3475+
/**
3476+
* Test validating whether content that is being moved is still allowed to be moved when one of its locations
3477+
* is inaccessible by a current user, however, when moved location is accessible.
3478+
*
3479+
* @covers \eZ\Publish\API\Repository\LocationService::moveSubtree
3480+
*
3481+
* @throws \eZ\Publish\API\Repository\Exceptions\Exception
3482+
*/
3483+
public function testMoveSubtreeContentWithMultipleLocationsAndOneOfThemInaccessible(): void
3484+
{
3485+
$repository = $this->getRepository();
3486+
$locationService = $repository->getLocationService();
3487+
$permissionResolver = $repository->getPermissionResolver();
3488+
3489+
$folder = $this->publishContentWithParentLocation('Parent folder', 2);
3490+
$accessibleFolder = $this->publishContentWithParentLocation('Accessible folder', 2);
3491+
$subFolder = $this->publishContentWithParentLocation(
3492+
'Sub folder',
3493+
$folder->contentInfo->mainLocationId
3494+
);
3495+
$contentToBeMoved = $this->publishContentWithParentLocation(
3496+
'Target folder',
3497+
$subFolder->contentInfo->mainLocationId
3498+
);
3499+
$forbiddenContent = $this->publishContentWithParentLocation('Forbidden folder', 2);
3500+
3501+
// Add second location (parent 'Forbidden folder') to 'Target content' in folder that user won't have access to
3502+
$locationService->createLocation(
3503+
$contentToBeMoved->contentInfo,
3504+
$locationService->newLocationCreateStruct($forbiddenContent->contentInfo->mainLocationId)
3505+
);
3506+
3507+
$folderLocation = $locationService->loadLocation($folder->contentInfo->mainLocationId);
3508+
$accessibleFolderLocation = $locationService->loadLocation($accessibleFolder->contentInfo->mainLocationId);
3509+
3510+
// Set user that cannot access 'Forbidden folder'
3511+
$user = $this->createUserWithPolicies(
3512+
'user',
3513+
[
3514+
['module' => 'content', 'function' => 'read'],
3515+
['module' => 'content', 'function' => 'create'],
3516+
],
3517+
new SubtreeLimitation(
3518+
['limitationValues' => [
3519+
$folderLocation->getPathString(),
3520+
$accessibleFolderLocation->getPathString(),
3521+
],
3522+
]
3523+
)
3524+
);
3525+
$permissionResolver->setCurrentUserReference($user);
3526+
3527+
// Move Parent folder/Sub folder/Target folder to location of ID = 2
3528+
$locationService->moveSubtree(
3529+
$contentToBeMoved->contentInfo->getMainLocation(),
3530+
$accessibleFolderLocation
3531+
);
3532+
3533+
$targetContentMainLocation = $locationService->loadLocation($contentToBeMoved->contentInfo->mainLocationId);
3534+
3535+
self::assertSame($targetContentMainLocation->parentLocationId, $accessibleFolderLocation->id);
3536+
}
3537+
34743538
public function testGetSubtreeSize(): Location
34753539
{
34763540
$repository = $this->getRepository();

eZ/Publish/API/Repository/Values/Content/ContentInfo.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
/**
1616
* This class provides all version independent information of the Content object.
1717
*
18-
* @property-read int $id The unique id of the Content object
18+
* @property-read int $id @deprecated Use {@see ContentInfo::getId} instead. The unique id of the Content object
1919
* @property-read int $contentTypeId The unique id of the Content Type object the Content object is an instance of
2020
* @property-read string $name the computed name (via name schema) in the main language of the Content object
2121
* @property-read int $sectionId the section to which the Content object is assigned
@@ -214,4 +214,9 @@ public function getOwner(): User
214214
{
215215
return $this->owner;
216216
}
217+
218+
public function getId(): int
219+
{
220+
return $this->id;
221+
}
217222
}

eZ/Publish/Core/Repository/LocationService.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -966,8 +966,17 @@ public function count(Filter $filter, ?array $languages = null): int
966966
return $this->locationFilteringHandler->count($filter);
967967
}
968968

969-
private function checkCreatePermissionOnSubtreeTarget(APILocation $targetParentLocation, APILocation $loadedSubtree, APILocation $loadedTargetLocation): void
970-
{
969+
/**
970+
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
971+
* @throws \eZ\Publish\API\Repository\Exceptions\BadStateException
972+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidCriterionArgumentException
973+
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
974+
*/
975+
private function checkCreatePermissionOnSubtreeTarget(
976+
APILocation $targetParentLocation,
977+
APILocation $loadedSubtree,
978+
APILocation $loadedTargetLocation
979+
): void {
971980
$locationTarget = (new DestinationLocationTarget($targetParentLocation->id, $loadedSubtree->contentInfo));
972981
if (!$this->permissionResolver->canUser(
973982
'content',
@@ -998,8 +1007,10 @@ private function checkCreatePermissionOnSubtreeTarget(APILocation $targetParentL
9981007
'limit' => 0,
9991008
'filter' => new CriterionLogicalAnd(
10001009
[
1001-
new CriterionSubtree($loadedSubtree->pathString),
1010+
new CriterionSubtree($loadedSubtree->getPathString()),
10021011
new CriterionLogicalNot($contentReadCriterion),
1012+
// Do not take the same content into consideration as it can have more than one location
1013+
new CriterionLogicalNot(new Criterion\ContentId($loadedSubtree->getContentInfo()->getId())),
10031014
]
10041015
),
10051016
]

0 commit comments

Comments
 (0)