Skip to content

Commit a4991af

Browse files
author
Bertrand Dunogier
committed
Custom graphql/content_type_view policy
Allows to restrict which content types a user is allowed to see over graphql. ``` DomainGroupContent: type: object fields: articles: type: "[ArticleContent]" public: '@=service("ezplatform_graphql.can_user").viewContentType("article")' ```
1 parent c79ee81 commit a4991af

5 files changed

Lines changed: 124 additions & 2 deletions

File tree

BDEzPlatformGraphQLBundle.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,29 @@
11
<?php
2-
32
namespace BD\EzPlatformGraphQLBundle;
43

54
use BD\EzPlatformGraphQLBundle\DependencyInjection\Compiler;
5+
use BD\EzPlatformGraphQLBundle\DependencyInjection\Security\PolicyProvider;
66
use Symfony\Component\DependencyInjection\ContainerBuilder;
77
use Symfony\Component\HttpKernel\Bundle\Bundle;
88

99
class BDEzPlatformGraphQLBundle extends Bundle
1010
{
1111
public function build(ContainerBuilder $container)
1212
{
13-
parent::build($container); // TODO: Change the autogenerated stub
13+
parent::build($container);
1414

1515
$container->addCompilerPass(new Compiler\FieldValueTypesPass());
1616
$container->addCompilerPass(new Compiler\FieldValueBuildersPass());
1717
$container->addCompilerPass(new Compiler\SchemaWorkersPass());
1818
$container->addCompilerPass(new Compiler\SchemaBuildersPass());
19+
20+
$this->loadPolicyProviders($container);
21+
}
22+
23+
private function loadPolicyProviders(ContainerBuilder $container)
24+
{
25+
$extension = $container->getExtension('ezpublish');
26+
// Add the policy provider.
27+
$extension->addPolicyProvider(new PolicyProvider());
1928
}
2029
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
namespace BD\EzPlatformGraphQLBundle\DependencyInjection\Security;
3+
4+
use eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Security\PolicyProvider\YamlPolicyProvider;
5+
6+
class PolicyProvider extends YamlPolicyProvider
7+
{
8+
protected function getFiles()
9+
{
10+
return [__DIR__ . '/../../Resources/config/policies.yml'];
11+
}
12+
}

Resources/config/policies.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
graphql:
2+
content_type_view:
3+
- Class

Resources/config/services.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,7 @@ services:
2828

2929
BD\EzPlatformGraphQLBundle\GraphQL\ExpressionLanguage\Access\HasEzAccessToOneOfFunction:
3030
tags: ['overblog_graphql.expression_function']
31+
32+
ezplatform_graphql.can_user:
33+
autowire: true
34+
class: 'BD\EzPlatformGraphQLBundle\Security\CanUser'

Security/CanUser.php

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?php
2+
namespace BD\EzPlatformGraphQLBundle\Security;
3+
4+
use eZ\Publish\API\Repository\ContentTypeService;
5+
use eZ\Publish\API\Repository\Exceptions\BadStateException;
6+
use eZ\Publish\API\Repository\Exceptions\InvalidArgumentException;
7+
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
8+
use eZ\Publish\API\Repository\PermissionResolver;
9+
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
10+
use eZ\Publish\API\Repository\Values\User\Limitation\ContentTypeLimitation;
11+
use GraphQL\Error\UserError;
12+
13+
class CanUser
14+
{
15+
/**
16+
* @var PermissionResolver
17+
*/
18+
private $permissionResolver;
19+
20+
const MODULE = 'graphql';
21+
22+
const PERMISSION_CONTENT_TYPE_VIEW = 'content_type_view';
23+
/**
24+
* @var ContentTypeService
25+
*/
26+
private $contentTypeService;
27+
28+
public function __construct(ContentTypeService $contentTypeService, PermissionResolver $permissionResolver)
29+
{
30+
$this->permissionResolver = $permissionResolver;
31+
$this->contentTypeService = $contentTypeService;
32+
}
33+
34+
public function viewContentType($identifier)
35+
{
36+
try {
37+
$contentType = $this->contentTypeService->loadContentTypeByIdentifier($identifier);
38+
} catch (NotFoundException $e) {
39+
throw new UserError("Content type '$identifier' not found'");
40+
}
41+
42+
$contentInfo = new ContentInfo(['contentTypeId' => $contentType->id]);
43+
try {
44+
return $this->permissionResolver->canUser(self::MODULE, self::PERMISSION_CONTENT_TYPE_VIEW, $contentInfo);
45+
} catch (BadStateException $e) {;
46+
throw new UserError($e->getMessage(), 0, $e);
47+
} catch (InvalidArgumentException $e) {
48+
throw new UserError($e->getMessage(), 0, $e);
49+
}
50+
}
51+
52+
public function hasAccessToContentType($identifier)
53+
{
54+
try {
55+
$access = $this->permissionResolver->hasAccess(self::MODULE, self::PERMISSION_CONTENT_TYPE_VIEW);
56+
} catch (InvalidArgumentException $e) {
57+
throw new UserError("oops", 0, $e);
58+
}
59+
60+
if (is_bool($access)) {
61+
return $access;
62+
}
63+
64+
if (!is_array($access)) {
65+
throw new UserError("Invalid hasAccess() return type");
66+
}
67+
68+
try {
69+
$contentType = $this->contentTypeService->loadContentTypeByIdentifier($identifier);
70+
} catch (NotFoundException $e) {
71+
throw new UserError("Unknown content type $identifier");
72+
}
73+
74+
/** @var \eZ\Publish\API\Repository\Values\User\Policy $policy */
75+
foreach ($access as $limitation) {
76+
foreach ($limitation['policies'] as $policy) {
77+
if ($policy->module !== self::MODULE || $policy->function !== self::PERMISSION_CONTENT_TYPE_VIEW) {
78+
continue;
79+
}
80+
foreach ($policy->getLimitations() as $limitation) {
81+
if (!$limitation instanceof ContentTypeLimitation) {
82+
continue;
83+
}
84+
85+
if (in_array($contentType->identifier, $limitation->limitationValues)) {
86+
return true;
87+
}
88+
}
89+
}
90+
}
91+
92+
return false;
93+
}
94+
}

0 commit comments

Comments
 (0)