Completed
Push — master ( 2d5a91...5e6a60 )
by André
72:09 queued 53:20
created

PermissionCriterionResolver::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 2
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
5
 * @license For full copyright and license information view LICENSE file distributed with this source code.
6
 */
7
namespace eZ\Publish\Core\Repository\Permission;
8
9
use eZ\Publish\API\Repository\PermissionCriterionResolver as APIPermissionCriterionResolver;
10
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\LogicalAnd;
11
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\LogicalOr;
12
use eZ\Publish\API\Repository\Values\User\Limitation;
13
use eZ\Publish\API\Repository\PermissionResolver as PermissionResolverInterface;
14
use eZ\Publish\Core\Repository\Helper\LimitationService;
15
use RuntimeException;
16
17
/**
18
 * Implementation of Permissions Criterion Resolver.
19
 */
20
class PermissionCriterionResolver implements APIPermissionCriterionResolver
21
{
22
    /**
23
     * @var \eZ\Publish\API\Repository\PermissionResolver
24
     */
25
    private $permissionResolver;
26
27
    /**
28
     * @var \eZ\Publish\Core\Repository\Helper\LimitationService
29
     */
30
    private $limitationService;
31
32
    /**
33
     * Constructor.
34
     *
35
     * @param \eZ\Publish\API\Repository\PermissionResolver $permissionResolver
36
     * @param \eZ\Publish\Core\Repository\Helper\LimitationService $limitationService
37
     */
38
    public function __construct(
39
        PermissionResolverInterface $permissionResolver,
40
        LimitationService $limitationService
41
    ) {
42
        $this->permissionResolver = $permissionResolver;
43
        $this->limitationService = $limitationService;
44
    }
45
46
    /**
47
     * Get content-read Permission criteria if needed and return false if no access at all.
48
     *
49
     * @uses \eZ\Publish\API\Repository\PermissionResolver::getCurrentUserReference()
50
     * @uses \eZ\Publish\API\Repository\PermissionResolver::hasAccess()
51
     *
52
     * @throws \RuntimeException If empty array of limitations are provided from hasAccess()
53
     *
54
     * @param string $module
55
     * @param string $function
56
     *
57
     * @return bool|\eZ\Publish\API\Repository\Values\Content\Query\Criterion
58
     */
59
    public function getPermissionsCriterion($module = 'content', $function = 'read')
60
    {
61
        $permissionSets = $this->permissionResolver->hasAccess($module, $function);
62
        if (is_bool($permissionSets)) {
63
            return $permissionSets;
64
        }
65
66
        if (empty($permissionSets)) {
67
            throw new RuntimeException("Got an empty array of limitations from hasAccess( '{$module}', '{$function}' )");
68
        }
69
70
        /*
71
         * RoleAssignment is a OR condition, so is policy, while limitations is a AND condition
72
         *
73
         * If RoleAssignment has limitation then policy OR conditions are wrapped in a AND condition with the
74
         * role limitation, otherwise it will be merged into RoleAssignment's OR condition.
75
         */
76
        $currentUserRef = $this->permissionResolver->getCurrentUserReference();
77
        $roleAssignmentOrCriteria = [];
78
        foreach ($permissionSets as $permissionSet) {
79
            // $permissionSet is a RoleAssignment, but in the form of role limitation & role policies hash
80
            $policyOrCriteria = [];
81
            /**
82
             * @var \eZ\Publish\API\Repository\Values\User\Policy
83
             */
84
            foreach ($permissionSet['policies'] as $policy) {
85
                $limitations = $policy->getLimitations();
86
                if ($limitations === '*' || empty($limitations)) {
87
                    // Given policy gives full access, optimize away all role policies (but not role limitation if any)
88
                    // This should be optimized on create/update of Roles, however we keep this here for bc with older data
89
                    $policyOrCriteria = [];
90
                    break;
91
                }
92
93
                $limitationsAndCriteria = [];
94
                foreach ($limitations as $limitation) {
95
                    $type = $this->limitationService->getLimitationType($limitation->getIdentifier());
96
                    $limitationsAndCriteria[] = $type->getCriterion($limitation, $currentUserRef);
97
                }
98
99
                $policyOrCriteria[] = isset($limitationsAndCriteria[1]) ?
100
                    new LogicalAnd($limitationsAndCriteria) :
101
                    $limitationsAndCriteria[0];
102
            }
103
104
            /**
105
             * Apply role limitations if there is one.
106
             *
107
             * @var \eZ\Publish\API\Repository\Values\User\Limitation[]
108
             */
109
            if ($permissionSet['limitation'] instanceof Limitation) {
110
                // We need to match both the limitation AND *one* of the policies, aka; roleLimit AND policies(OR)
111
                $type = $this->limitationService->getLimitationType($permissionSet['limitation']->getIdentifier());
112
                if (!empty($policyOrCriteria)) {
113
                    $roleAssignmentOrCriteria[] = new LogicalAnd(
114
                        [
115
                            $type->getCriterion($permissionSet['limitation'], $currentUserRef),
116
                            isset($policyOrCriteria[1]) ? new LogicalOr($policyOrCriteria) : $policyOrCriteria[0],
117
                        ]
118
                    );
119
                } else {
120
                    $roleAssignmentOrCriteria[] = $type->getCriterion($permissionSet['limitation'], $currentUserRef);
121
                }
122
            } elseif (!empty($policyOrCriteria)) {
123
                // Otherwise merge $policyOrCriteria into $roleAssignmentOrCriteria
124
                // There is no role limitation, so any of the policies can globally match in the returned OR criteria
125
                $roleAssignmentOrCriteria = empty($roleAssignmentOrCriteria) ?
126
                    $policyOrCriteria :
127
                    array_merge($roleAssignmentOrCriteria, $policyOrCriteria);
128
            }
129
        }
130
131
        if (empty($roleAssignmentOrCriteria)) {
132
            return false;
133
        }
134
135
        return isset($roleAssignmentOrCriteria[1]) ?
136
            new LogicalOr($roleAssignmentOrCriteria) :
137
            $roleAssignmentOrCriteria[0];
138
    }
139
}
140