diff --git a/composer.json b/composer.json index d07e5dce3..67871f897 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "minimum-stability": "dev", "require": { "php": "~8.2", - "pimcore/static-resolver-bundle": "^1.3", + "pimcore/static-resolver-bundle": "1.x-dev", "pimcore/generic-data-index-bundle": "1.x-dev", "pimcore/pimcore": "^11.0", "zircote/swagger-php": "^4.8" diff --git a/config/security.yaml b/config/security.yaml index 1db5f1e3d..cfcee010e 100644 --- a/config/security.yaml +++ b/config/security.yaml @@ -9,6 +9,10 @@ services: tags: - { name: security.voter } + Pimcore\Bundle\StudioBackendBundle\Security\Voter\UserPermissionVoter: + tags: + - { name: security.voter } + Pimcore\Bundle\StudioBackendBundle\Security\Voter\PublicAuthorizationVoter: arguments: [ '@request_stack' ] tags: diff --git a/src/Asset/Controller/CollectionController.php b/src/Asset/Controller/CollectionController.php index 83b976b65..b4458b0af 100644 --- a/src/Asset/Controller/CollectionController.php +++ b/src/Asset/Controller/CollectionController.php @@ -67,7 +67,8 @@ public function __construct( */ #[Route('/assets', name: 'pimcore_studio_api_assets', methods: ['GET'])] //#[IsGranted('STUDIO_API')] - #[GET( + //#[IsGranted(UserPermissions::ASSETS->value)] + #[Get( path: self::API_PATH . '/assets', operationId: 'getAssets', description: 'Get paginated assets', diff --git a/src/Asset/Controller/GetController.php b/src/Asset/Controller/GetController.php index 92df9bccb..617c4477b 100644 --- a/src/Asset/Controller/GetController.php +++ b/src/Asset/Controller/GetController.php @@ -46,7 +46,8 @@ public function __construct( #[Route('/assets/{id}', name: 'pimcore_studio_api_get_asset', methods: ['GET'])] //#[IsGranted('STUDIO_API')] - #[GET( + //#[IsGranted(UserPermissions::ASSETS->value)] + #[Get( path: self::API_PATH . '/assets/{id}', operationId: 'getAssetById', description: 'Get assets by id by path parameter', diff --git a/src/Authorization/Controller/AuthorizationController.php b/src/Authorization/Controller/AuthorizationController.php index 851e0cb5d..506263842 100644 --- a/src/Authorization/Controller/AuthorizationController.php +++ b/src/Authorization/Controller/AuthorizationController.php @@ -57,7 +57,7 @@ public function __construct( * @throws AccessDeniedException */ #[Route('/login', name: 'pimcore_studio_api_login', methods: ['POST'])] - #[POST( + #[Post( path: self::API_PATH . '/login', operationId: 'login', summary: 'Login with user credentials and get access token', diff --git a/src/DataObject/Controller/CollectionController.php b/src/DataObject/Controller/CollectionController.php index 83d08586e..dff3c981d 100644 --- a/src/DataObject/Controller/CollectionController.php +++ b/src/DataObject/Controller/CollectionController.php @@ -64,7 +64,7 @@ public function __construct( */ #[Route('/data-objects', name: 'pimcore_studio_api_data_objects', methods: ['GET'])] //#[IsGranted(self::VOTER_STUDIO_API)] - #[GET( + #[Get( path: self::API_PATH . '/data-objects', operationId: 'getDataObjects', description: 'Get paginated data objects', diff --git a/src/DataObject/Controller/GetController.php b/src/DataObject/Controller/GetController.php index 009d69083..8c71cd1c8 100644 --- a/src/DataObject/Controller/GetController.php +++ b/src/DataObject/Controller/GetController.php @@ -47,7 +47,7 @@ public function __construct( #[Route('/data-objects/{id}', name: 'pimcore_studio_api_get_data_object', methods: ['GET'])] //#[IsGranted('STUDIO_API')] - #[GET( + #[Get( path: self::API_PATH . '/data-objects/{id}', operationId: 'getDataObjectById', description: 'Get data object by id by path parameter', diff --git a/src/Security/Voter/UserPermissionVoter.php b/src/Security/Voter/UserPermissionVoter.php new file mode 100644 index 000000000..e26469736 --- /dev/null +++ b/src/Security/Voter/UserPermissionVoter.php @@ -0,0 +1,95 @@ +getUserPermissions(); + } + + /** + * @inheritDoc + */ + protected function supports(string $attribute, mixed $subject): bool + { + return in_array($attribute, $this->userPermissions, true); + } + + protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool + { + if (!$this->securityService->getCurrentUser()->isAllowed($attribute)) { + throw new AccessDeniedException(sprintf('User does not have permission: %s', $attribute)); + } + + return true; + } + + /** + * @throws AccessDeniedException + */ + private function getUserPermissions(): void + { + $userPermissions = $this->cacheResolver->load(self::USER_PERMISSIONS_CACHE_KEY); + + if($userPermissions !== false && is_array($userPermissions)) { + $this->userPermissions = $userPermissions; + return; + } + + $userPermissions = $this->getUserPermissionsFromDataBase(); + + $this->cacheResolver->save( + $userPermissions, + self::USER_PERMISSIONS_CACHE_KEY + ); + + $this->userPermissions = $userPermissions; + } + + private function getUserPermissionsFromDataBase(): array + { + try { + $userPermissions = $this->dbResolver->getConnection()->fetchFirstColumn( + 'SELECT `key` FROM users_permission_definitions' + ); + } catch (Exception) { + throw new AccessDeniedException('Cannot resolve user permissions'); + } + return $userPermissions; + } +} diff --git a/src/Util/Constants/Permissions.php b/src/Util/Constants/ElementPermissions.php similarity index 96% rename from src/Util/Constants/Permissions.php rename to src/Util/Constants/ElementPermissions.php index 4c759edf3..0e5399c6d 100644 --- a/src/Util/Constants/Permissions.php +++ b/src/Util/Constants/ElementPermissions.php @@ -19,7 +19,7 @@ /** * @internal */ -final class Permissions +final class ElementPermissions { public const LIST_PERMISSION = 'list'; diff --git a/src/Util/Constants/UserPermissions.php b/src/Util/Constants/UserPermissions.php new file mode 100644 index 000000000..03e57c617 --- /dev/null +++ b/src/Util/Constants/UserPermissions.php @@ -0,0 +1,27 @@ +securityService->hasElementPermission( $version->getData(), $user, - Permissions::VERSIONS_PERMISSION + ElementPermissions::VERSIONS_PERMISSION ); $version->delete(); diff --git a/src/Version/Controller/GetController.php b/src/Version/Controller/GetController.php index 670705488..8031ad1f4 100644 --- a/src/Version/Controller/GetController.php +++ b/src/Version/Controller/GetController.php @@ -48,7 +48,7 @@ public function __construct( #[Route('/versions/{id}', name: 'pimcore_studio_api_get_version', methods: ['GET'])] //#[IsGranted('STUDIO_API')] - #[GET( + #[Get( path: self::API_PATH . '/versions/{id}', operationId: 'getVersionById', description: 'Get version based on the version ID', diff --git a/src/Version/Controller/PublishController.php b/src/Version/Controller/PublishController.php index b39092150..b5419e18e 100644 --- a/src/Version/Controller/PublishController.php +++ b/src/Version/Controller/PublishController.php @@ -48,7 +48,7 @@ public function __construct( #[Route('/versions/{id}', name: 'pimcore_studio_api_publish_version', methods: ['POST'])] //#[IsGranted('STUDIO_API')] - #[POST( + #[Post( path: self::API_PATH . '/versions/{id}', operationId: 'publishVersion', description: 'Publish element based on the version ID', diff --git a/src/Version/Publisher/VersionPublisherService.php b/src/Version/Publisher/VersionPublisherService.php index a61fb3aec..01306436c 100644 --- a/src/Version/Publisher/VersionPublisherService.php +++ b/src/Version/Publisher/VersionPublisherService.php @@ -20,7 +20,7 @@ use Pimcore\Bundle\StudioBackendBundle\Exception\ElementPublishingFailedException; use Pimcore\Bundle\StudioBackendBundle\Exception\InvalidElementTypeException; use Pimcore\Bundle\StudioBackendBundle\Security\Service\SecurityServiceInterface; -use Pimcore\Bundle\StudioBackendBundle\Util\Constants\Permissions; +use Pimcore\Bundle\StudioBackendBundle\Util\Constants\ElementPermissions; use Pimcore\Bundle\StudioBackendBundle\Util\Traits\ElementProviderTrait; use Pimcore\Bundle\StudioBackendBundle\Version\RepositoryInterface; use Pimcore\Model\UserInterface; @@ -61,7 +61,7 @@ public function publishVersion( $this->securityService->hasElementPermission( $currentElement, $user, - Permissions::PUBLISH_PERMISSION + ElementPermissions::PUBLISH_PERMISSION ); $class = $this->getElementClass($currentElement); diff --git a/src/Version/Repository.php b/src/Version/Repository.php index c216bb379..8407ae3fb 100644 --- a/src/Version/Repository.php +++ b/src/Version/Repository.php @@ -19,7 +19,7 @@ use Pimcore\Bundle\StaticResolverBundle\Models\Version\VersionResolver; use Pimcore\Bundle\StudioBackendBundle\Exception\ElementNotFoundException; use Pimcore\Bundle\StudioBackendBundle\Security\Service\SecurityServiceInterface; -use Pimcore\Bundle\StudioBackendBundle\Util\Constants\Permissions; +use Pimcore\Bundle\StudioBackendBundle\Util\Constants\ElementPermissions; use Pimcore\Bundle\StudioBackendBundle\Util\Traits\ElementProviderTrait; use Pimcore\Bundle\StudioBackendBundle\Version\Request\VersionCleanupParameters; use Pimcore\Bundle\StudioBackendBundle\Version\Request\VersionParameters; @@ -50,7 +50,7 @@ public function listVersions( $this->securityService->hasElementPermission( $element, $user, - Permissions::VERSIONS_PERMISSION + ElementPermissions::VERSIONS_PERMISSION ); $limit = $parameters->getPageSize(); @@ -95,7 +95,7 @@ public function getElementFromVersion( $this->securityService->hasElementPermission( $element, $user, - Permissions::VERSIONS_PERMISSION + ElementPermissions::VERSIONS_PERMISSION ); return $element;