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\PermissionResolver; |
8
|
|
|
|
9
|
|
|
use eZ\Publish\API\Repository\Values\ValueObject; |
10
|
|
|
use eZ\Publish\API\Repository\Values\User\UserReference; |
11
|
|
|
use eZ\Publish\Core\Repository\Helper\LimitationService; |
12
|
|
|
use eZ\Publish\SPI\Limitation\Type as LimitationType; |
13
|
|
|
use eZ\Publish\API\Repository\Values\User\Limitation; |
14
|
|
|
use eZ\Publish\SPI\Persistence\User\Handler as UserHandler; |
15
|
|
|
use eZ\Publish\Core\Repository\Helper\RoleDomainMapper; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* todo |
19
|
|
|
*/ |
20
|
|
|
class PermissionResolver |
21
|
|
|
{ |
22
|
|
|
/** |
23
|
|
|
* @var \eZ\Publish\Core\Repository\Helper\RoleDomainMapper |
24
|
|
|
*/ |
25
|
|
|
private $roleDomainMapper; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* @var \eZ\Publish\Core\Repository\Helper\LimitationService |
29
|
|
|
*/ |
30
|
|
|
private $limitationService; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* @var \eZ\Publish\SPI\Persistence\User\Handler |
34
|
|
|
*/ |
35
|
|
|
private $userHandler; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* @param \eZ\Publish\Core\Repository\Helper\RoleDomainMapper $roleDomainMapper |
39
|
|
|
* @param \eZ\Publish\Core\Repository\Helper\LimitationService $limitationService |
40
|
|
|
* @param \eZ\Publish\SPI\Persistence\User\Handler $userHandler |
41
|
|
|
*/ |
42
|
|
|
public function __construct( |
43
|
|
|
RoleDomainMapper $roleDomainMapper, |
44
|
|
|
LimitationService $limitationService, |
45
|
|
|
UserHandler $userHandler |
46
|
|
|
) { |
47
|
|
|
$this->roleDomainMapper = $roleDomainMapper; |
48
|
|
|
$this->limitationService = $limitationService; |
49
|
|
|
$this->userHandler = $userHandler; |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* todo |
54
|
|
|
* |
55
|
|
|
* @param string $module |
56
|
|
|
* @param string $function |
57
|
|
|
* @param \eZ\Publish\Core\Repository\PermissionResolver\Permission[] $permissions |
58
|
|
|
* @param \eZ\Publish\API\Repository\Values\ValueObject $object |
59
|
|
|
* @param \eZ\Publish\API\Repository\Values\User\UserReference $userReference |
60
|
|
|
* @param array $targets |
61
|
|
|
* |
62
|
|
|
* @return bool |
63
|
|
|
*/ |
64
|
|
|
public function resolvePermissions( |
65
|
|
|
$module, |
66
|
|
|
$function, |
67
|
|
|
$permissions, |
68
|
|
|
ValueObject $object, |
69
|
|
|
UserReference $userReference, |
70
|
|
|
array $targets = [] |
71
|
|
|
) { |
72
|
|
|
foreach ($permissions as $permission) { |
73
|
|
|
$access = $this->resolvePermission( |
74
|
|
|
$module, |
75
|
|
|
$function, |
76
|
|
|
$permission, |
77
|
|
|
$object, |
78
|
|
|
$userReference, |
79
|
|
|
$targets |
80
|
|
|
); |
81
|
|
|
|
82
|
|
|
if ($access === true) { |
83
|
|
|
return true; |
84
|
|
|
} |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
return false; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* @param string $module |
92
|
|
|
* @param string $function |
93
|
|
|
* @param \eZ\Publish\Core\Repository\PermissionResolver\Permission $permission |
94
|
|
|
* @param \eZ\Publish\API\Repository\Values\ValueObject $object |
95
|
|
|
* @param \eZ\Publish\API\Repository\Values\User\UserReference $userReference |
96
|
|
|
* @param array $targets |
97
|
|
|
* |
98
|
|
|
* @return bool |
99
|
|
|
*/ |
100
|
|
|
public function resolvePermission( |
101
|
|
|
$module, |
102
|
|
|
$function, |
103
|
|
|
Permission $permission, |
104
|
|
|
ValueObject $object, |
105
|
|
|
UserReference $userReference, |
106
|
|
|
array $targets = [] |
107
|
|
|
) { |
108
|
|
|
if (empty($targets)) { |
109
|
|
|
$targets = null; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* First deal with Role limitation if any. |
114
|
|
|
* |
115
|
|
|
* Here we accept ACCESS_GRANTED and ACCESS_ABSTAIN, the latter in cases where $object and $targets |
116
|
|
|
* are not supported by limitation. |
117
|
|
|
* |
118
|
|
|
* @var \eZ\Publish\API\Repository\Values\User\Limitation[] |
119
|
|
|
*/ |
120
|
|
|
if ($permission->limitation instanceof Limitation) { |
121
|
|
|
$type = $this->limitationService->getLimitationType($permission->limitation->getIdentifier()); |
122
|
|
|
$accessVote = $type->evaluate($permission->limitation, $userReference, $object, $targets); |
|
|
|
|
123
|
|
|
if ($accessVote === LimitationType::ACCESS_DENIED) { |
124
|
|
|
return false; |
125
|
|
|
} |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* Loop over all policies. |
130
|
|
|
* |
131
|
|
|
* These are already filtered by hasAccess and given hasAccess did not return boolean |
132
|
|
|
* there must be some, so only return true if one of them says yes. |
133
|
|
|
* |
134
|
|
|
* @var \eZ\Publish\API\Repository\Values\User\Policy $policy |
135
|
|
|
*/ |
136
|
|
|
foreach ($permission->policies as $policy) { |
137
|
|
|
if (!($policy->module === $module || $policy->module === '*')) { |
138
|
|
|
continue; |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
if (!($policy->function === $function || $policy->function === '*')) { |
142
|
|
|
continue; |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
$limitations = $policy->getLimitations(); |
146
|
|
|
|
147
|
|
|
/* |
148
|
|
|
* Return true if policy gives full access (aka no limitations) |
149
|
|
|
*/ |
150
|
|
|
if ($limitations === '*') { |
151
|
|
|
return true; |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
/* |
155
|
|
|
* Loop over limitations, all must return ACCESS_GRANTED for policy to pass. |
156
|
|
|
* If limitations was empty array this means same as '*' |
157
|
|
|
*/ |
158
|
|
|
$limitationsPass = true; |
159
|
|
View Code Duplication |
foreach ($limitations as $limitation) { |
|
|
|
|
160
|
|
|
$type = $this->limitationService->getLimitationType($limitation->getIdentifier()); |
161
|
|
|
$accessVote = $type->evaluate($limitation, $userReference, $object, $targets); |
|
|
|
|
162
|
|
|
/* |
163
|
|
|
* For policy limitation atm only support ACCESS_GRANTED |
164
|
|
|
* |
165
|
|
|
* Reasoning: Right now, use of a policy limitation not valid for a policy is per definition a |
166
|
|
|
* BadState. To reach this you would have to configure the "policyMap" wrongly, like using |
167
|
|
|
* Node (Location) limitation on state/assign. So in this case Role Limitations will return |
168
|
|
|
* ACCESS_ABSTAIN (== no access here), and other limitations will throw InvalidArgument above, |
169
|
|
|
* both cases forcing dev to investigate to find miss configuration. This might be relaxed in |
170
|
|
|
* the future if valid use cases for ACCESS_ABSTAIN on policy limitations becomes known. |
171
|
|
|
*/ |
172
|
|
|
if ($accessVote !== LimitationType::ACCESS_GRANTED) { |
173
|
|
|
$limitationsPass = false; |
174
|
|
|
break;// Break to next policy, all limitations must pass |
175
|
|
|
} |
176
|
|
|
} |
177
|
|
|
if ($limitationsPass) { |
178
|
|
|
return true; |
179
|
|
|
} |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
return false; |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* todo |
187
|
|
|
* |
188
|
|
|
* @param \eZ\Publish\API\Repository\Values\User\UserReference $userReference |
189
|
|
|
* @param string $module |
190
|
|
|
* @param string $function |
191
|
|
|
* |
192
|
|
|
* @return \eZ\Publish\Core\Repository\PermissionResolver\Permission[] |
193
|
|
|
*/ |
194
|
|
|
public function getPermissions(UserReference $userReference, $module = '*', $function = '*') |
195
|
|
|
{ |
196
|
|
|
// Uses SPI to avoid triggering permission checks in Role/User service |
197
|
|
|
$permissionSets = []; |
198
|
|
|
$spiRoleAssignments = $this->userHandler->loadRoleAssignmentsByGroupId($userReference->getUserId(), true); |
199
|
|
|
foreach ($spiRoleAssignments as $spiRoleAssignment) { |
200
|
|
|
$permissionSet = ['limitation' => null, 'policies' => []]; |
201
|
|
|
|
202
|
|
|
$spiRole = $this->userHandler->loadRole($spiRoleAssignment->roleId); |
203
|
|
|
foreach ($spiRole->policies as $spiPolicy) { |
204
|
|
|
if (!($spiPolicy->module === $module || $spiPolicy->module === '*' || $module === '*')) { |
205
|
|
|
continue; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
if (!($spiPolicy->function === $function || $spiPolicy->function === '*' || $function === '*')) { |
209
|
|
|
continue; |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
$permissionSet['policies'][] = $this->roleDomainMapper->buildDomainPolicyObject($spiPolicy); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
View Code Duplication |
if (!empty($permissionSet['policies'])) { |
|
|
|
|
216
|
|
|
if ($spiRoleAssignment->limitationIdentifier !== null) { |
217
|
|
|
$permissionSet['limitation'] = $this->limitationService |
218
|
|
|
->getLimitationType($spiRoleAssignment->limitationIdentifier) |
219
|
|
|
->buildValue($spiRoleAssignment->values); |
|
|
|
|
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
$permissionSets[] = new Permission($permissionSet); |
223
|
|
|
} |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
return $permissionSets; |
227
|
|
|
} |
228
|
|
|
} |
229
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.