|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* @package midcom |
|
4
|
|
|
* @author The Midgard Project, http://www.midgard-project.org |
|
5
|
|
|
* @copyright The Midgard Project, http://www.midgard-project.org |
|
6
|
|
|
* @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License |
|
7
|
|
|
*/ |
|
8
|
|
|
|
|
9
|
|
|
/** |
|
10
|
|
|
* Privilege class, used to interact with the privilege system. It encapsulates the actual |
|
11
|
|
|
* Database Level Object. As usual with MidCOM DBA, you <i>must never access the DB layer |
|
12
|
|
|
* object.</i> |
|
13
|
|
|
* |
|
14
|
|
|
* The main area of expertise of this class is privilege IO (loading and storing), their |
|
15
|
|
|
* validation and privilege merging. |
|
16
|
|
|
* |
|
17
|
|
|
* It is important to understand that you must never load privilege records directly, or |
|
18
|
|
|
* access them by their IDs. Instead, use the DBA level interface functions to locate |
|
19
|
|
|
* existing privilege sets. The only time where you use this class directly is when |
|
20
|
|
|
* creating new privilege, using the default constructor of this class (although the |
|
21
|
|
|
* create_new_privilege_object DBA member methods are the preferred way of doing this). |
|
22
|
|
|
* |
|
23
|
|
|
* <b>Caching:</b> |
|
24
|
|
|
* |
|
25
|
|
|
* This class uses the memcache cache module to speed up ACL accesses. It caches the ACL |
|
26
|
|
|
* objects retrieved from the database, not any merged privilege set (at this time, that is). |
|
27
|
|
|
* This should speed up regular operations quite a bit (along with the parent guid cache, |
|
28
|
|
|
* which is a second important key). |
|
29
|
|
|
* |
|
30
|
|
|
* @property string $objectguid GUID of the object the privilege applies to |
|
31
|
|
|
* @property string $privilegename Name of the privilege (for example `midgard:create`) |
|
32
|
|
|
* @property string $assignee Assignee of the privilege, for instance user or group identifier |
|
33
|
|
|
* @property string $classname MgdSchema class the privilege applies to, in case of class-level privileges |
|
34
|
|
|
* @property integer $value |
|
35
|
|
|
Value of the privilege: |
|
36
|
|
|
|
|
37
|
|
|
- 1: MIDCOM_PRIVILEGE_ALLOW |
|
38
|
|
|
- 2: MIDCOM_PRIVILEGE_DENY |
|
39
|
|
|
- 3: MIDCOM_PRIVILEGE_INHERIT |
|
40
|
|
|
|
|
41
|
|
|
* @property string $guid |
|
42
|
|
|
* @package midcom |
|
43
|
|
|
*/ |
|
44
|
|
|
class midcom_core_privilege |
|
45
|
|
|
{ |
|
46
|
|
|
/** |
|
47
|
|
|
* Cached actual midcom_core_privilege_db data for this privilege. |
|
48
|
|
|
*/ |
|
49
|
|
|
private array $__privilege = [ |
|
50
|
|
|
'guid' => '', |
|
51
|
|
|
'objectguid' => '', |
|
52
|
|
|
'privilegename'=> '', |
|
53
|
|
|
'assignee' => null, |
|
54
|
|
|
'scope' => -1, |
|
55
|
|
|
'classname' => '', |
|
56
|
|
|
'value' => null |
|
57
|
|
|
]; |
|
58
|
|
|
|
|
59
|
|
|
/** |
|
60
|
|
|
* The actual object for this privilege. |
|
61
|
|
|
*/ |
|
62
|
|
|
private ?midcom_core_privilege_db $__privilege_object = null; |
|
63
|
|
|
|
|
64
|
|
|
/** |
|
65
|
|
|
* GUID of the midcom_core_privilege_db object, used when values are retrieved via collector instead of QB |
|
66
|
|
|
*/ |
|
67
|
|
|
private string $__guid = ''; |
|
68
|
|
|
|
|
69
|
|
|
/** |
|
70
|
|
|
* Cached content object, based on $objectguid. |
|
71
|
|
|
*/ |
|
72
|
|
|
private ?midcom_core_dbaobject $__cached_object = null; |
|
73
|
|
|
|
|
74
|
|
|
/** |
|
75
|
|
|
* The Default constructor creates an empty privilege, if you specify |
|
76
|
|
|
* another privilege object in the constructor, a copy is constructed. |
|
77
|
|
|
*/ |
|
78
|
134 |
|
public function __construct(midcom_core_privilege_db|array|string|null $src = null) |
|
79
|
|
|
{ |
|
80
|
134 |
|
if (is_array($src)) { |
|
81
|
|
|
// Store given values to our privilege array |
|
82
|
81 |
|
$this->__privilege = array_merge($this->__privilege, $src); |
|
83
|
|
|
} else { |
|
84
|
129 |
|
$this->_load($src); |
|
85
|
129 |
|
if ($src !== null) { |
|
|
|
|
|
|
86
|
25 |
|
$this->_sync_from_db_object(); |
|
87
|
|
|
} |
|
88
|
|
|
} |
|
89
|
|
|
} |
|
90
|
|
|
|
|
91
|
|
|
// Magic getter and setter for object property mapping |
|
92
|
139 |
|
public function __get($property) |
|
93
|
|
|
{ |
|
94
|
139 |
|
return $this->__privilege[$property] ?? null; |
|
95
|
|
|
} |
|
96
|
|
|
|
|
97
|
129 |
|
public function __set($property, $value) |
|
98
|
|
|
{ |
|
99
|
129 |
|
$this->__privilege[$property] = $value; |
|
100
|
|
|
} |
|
101
|
|
|
|
|
102
|
|
|
public function __isset($property) |
|
103
|
|
|
{ |
|
104
|
|
|
return isset($this->__privilege[$property]); |
|
105
|
|
|
} |
|
106
|
|
|
|
|
107
|
|
|
/** |
|
108
|
|
|
* Get the object referenced by the guid value of this privilege. |
|
109
|
|
|
*/ |
|
110
|
125 |
|
private function get_object() : ?midcom_core_dbaobject |
|
111
|
|
|
{ |
|
112
|
125 |
|
if ($this->__cached_object === null) { |
|
113
|
|
|
try { |
|
114
|
25 |
|
$this->__cached_object = midcom::get()->dbfactory->get_object_by_guid($this->objectguid); |
|
115
|
|
|
} catch (midcom_error) { |
|
116
|
|
|
return null; |
|
117
|
|
|
} |
|
118
|
|
|
} |
|
119
|
125 |
|
return $this->__cached_object; |
|
120
|
|
|
} |
|
121
|
|
|
|
|
122
|
|
|
/** |
|
123
|
|
|
* Set a privilege to a given content object. |
|
124
|
|
|
*/ |
|
125
|
129 |
|
public function set_object(midcom_core_dbaobject $object) |
|
126
|
|
|
{ |
|
127
|
129 |
|
$this->__cached_object = $object; |
|
128
|
129 |
|
$this->objectguid = $object->guid; |
|
129
|
|
|
} |
|
130
|
|
|
|
|
131
|
|
|
/** |
|
132
|
|
|
* Determine whether a given privilege applies for the given |
|
133
|
|
|
* user in content mode. This means, that all SELF privileges are skipped at this point, |
|
134
|
|
|
* EVERYONE privileges apply always, and all other privileges are checked against the |
|
135
|
|
|
* user. |
|
136
|
|
|
*/ |
|
137
|
81 |
|
public function does_privilege_apply(string $user_id) : bool |
|
138
|
|
|
{ |
|
139
|
81 |
|
switch ($this->__privilege['assignee']) { |
|
140
|
81 |
|
case 'EVERYONE': |
|
141
|
|
|
return true; |
|
142
|
81 |
|
case 'ANONYMOUS': |
|
143
|
|
|
return in_array($user_id, ['EVERYONE', 'ANONYMOUS']); |
|
144
|
81 |
|
case 'USERS': |
|
145
|
|
|
return !in_array($user_id, ['EVERYONE', 'ANONYMOUS']); |
|
146
|
|
|
default: |
|
147
|
81 |
|
if ($this->__privilege['assignee'] == $user_id) { |
|
148
|
51 |
|
return true; |
|
149
|
|
|
} |
|
150
|
36 |
|
if (str_starts_with($this->__privilege['assignee'], 'group:')) { |
|
151
|
1 |
|
if ($user = midcom::get()->auth->get_user($user_id)) { |
|
152
|
1 |
|
return $user->is_in_group($this->__privilege['assignee']); |
|
153
|
|
|
} |
|
154
|
|
|
} |
|
155
|
36 |
|
return false; |
|
156
|
|
|
} |
|
157
|
|
|
} |
|
158
|
|
|
|
|
159
|
|
|
/** |
|
160
|
|
|
* Returns the privilege's scope (or -1 for SELF and broken privileges) |
|
161
|
|
|
*/ |
|
162
|
81 |
|
public function get_scope() : int |
|
163
|
|
|
{ |
|
164
|
81 |
|
if (defined('MIDCOM_PRIVILEGE_SCOPE_' . $this->__privilege['assignee'])) { |
|
165
|
|
|
return constant('MIDCOM_PRIVILEGE_SCOPE_' . $this->__privilege['assignee']); |
|
166
|
|
|
} |
|
167
|
81 |
|
if ($assignee = $this->get_assignee()) { |
|
168
|
81 |
|
return $assignee->scope; |
|
169
|
|
|
} |
|
170
|
|
|
debug_print_r('Could not resolve the assignee of this privilege', $this); |
|
171
|
|
|
|
|
172
|
|
|
return -1; |
|
173
|
|
|
} |
|
174
|
|
|
|
|
175
|
|
|
/** |
|
176
|
|
|
* If the assignee has an object representation (at this time, only users and groups have), this call |
|
177
|
|
|
* will return the assignee object held by the authentication service. |
|
178
|
|
|
* |
|
179
|
|
|
* Use is_magic_assignee to determine if you have an assignee object. |
|
180
|
|
|
* |
|
181
|
|
|
* @see midcom_services_auth::get_assignee() |
|
182
|
|
|
* @return midcom_core_user|midcom_core_group|null object as returned by the auth service, null on failure. |
|
183
|
|
|
*/ |
|
184
|
131 |
|
public function get_assignee() : ?object |
|
185
|
|
|
{ |
|
186
|
131 |
|
if ($this->is_magic_assignee()) { |
|
187
|
|
|
return null; |
|
188
|
|
|
} |
|
189
|
|
|
|
|
190
|
131 |
|
return midcom::get()->auth->get_assignee($this->assignee); |
|
191
|
|
|
} |
|
192
|
|
|
|
|
193
|
|
|
/** |
|
194
|
|
|
* Checks whether the current assignee is a magic assignee or an object identifier. |
|
195
|
|
|
*/ |
|
196
|
136 |
|
public function is_magic_assignee(?string $assignee = null) : bool |
|
197
|
|
|
{ |
|
198
|
136 |
|
$assignee ??= $this->assignee; |
|
199
|
136 |
|
return in_array($assignee, ['SELF', 'EVERYONE', 'USERS', 'ANONYMOUS', 'OWNER']); |
|
200
|
|
|
} |
|
201
|
|
|
|
|
202
|
|
|
/** |
|
203
|
|
|
* Set the assignee member string to the correct value to represent the |
|
204
|
|
|
* object passed, in general, this resolves users and groups to their strings and |
|
205
|
|
|
* leaves magic assignees intact. |
|
206
|
|
|
* |
|
207
|
|
|
* Possible argument types: |
|
208
|
|
|
* |
|
209
|
|
|
* - Any one of the magic assignees SELF, EVERYONE, ANONYMOUS, USERS. |
|
210
|
|
|
* - Any midcom_core_user or midcom_core_group object or subtype thereof. |
|
211
|
|
|
* - Any string identifier which can be resolved using midcom_services_auth::get_assignee(). |
|
212
|
|
|
*/ |
|
213
|
129 |
|
public function set_assignee(midcom_core_group|midcom_core_user|string $assignee) : bool |
|
214
|
|
|
{ |
|
215
|
129 |
|
if (is_string($assignee)) { |
|
216
|
129 |
|
if ($this->is_magic_assignee($assignee)) { |
|
217
|
12 |
|
$this->assignee = $assignee; |
|
218
|
|
|
} else { |
|
219
|
126 |
|
$tmp = midcom::get()->auth->get_assignee($assignee); |
|
220
|
126 |
|
if (!$tmp) { |
|
221
|
|
|
debug_add("Could not resolve the assignee string '{$assignee}', see above for more information.", MIDCOM_LOG_INFO); |
|
222
|
|
|
return false; |
|
223
|
|
|
} |
|
224
|
129 |
|
$this->assignee = $tmp->id; |
|
225
|
|
|
} |
|
226
|
|
|
} else { |
|
227
|
1 |
|
$this->assignee = $assignee->id; |
|
228
|
|
|
} |
|
229
|
|
|
|
|
230
|
129 |
|
return true; |
|
231
|
|
|
} |
|
232
|
|
|
|
|
233
|
|
|
/** |
|
234
|
|
|
* Validate the privilege for correctness of all set options. This includes: |
|
235
|
|
|
* |
|
236
|
|
|
* - A check against the list of registered privileges to ensure the existence of the |
|
237
|
|
|
* privilege itself. |
|
238
|
|
|
* - A check for a valid and existing assignee, this includes a class existence check for classname restrictions |
|
239
|
|
|
* for SELF privileges. |
|
240
|
|
|
* - A check for an existing content object GUID (this implicitly checks for midgard:read as well). |
|
241
|
|
|
* - Enough privileges of the current user to update the object's privileges (the user |
|
242
|
|
|
* must have midgard:update and midgard:privileges for this to succeed). |
|
243
|
|
|
* - A valid privilege value. |
|
244
|
|
|
*/ |
|
245
|
125 |
|
public function validate() : bool |
|
246
|
|
|
{ |
|
247
|
125 |
|
if (!midcom::get()->auth->acl->privilege_exists($this->privilegename)) { |
|
248
|
|
|
debug_add("The privilege name '{$this->privilegename}' is unknown to the system. Perhaps the corresponding component is not loaded?", |
|
249
|
|
|
MIDCOM_LOG_INFO); |
|
250
|
|
|
return false; |
|
251
|
|
|
} |
|
252
|
|
|
|
|
253
|
125 |
|
if (!in_array($this->value, [MIDCOM_PRIVILEGE_ALLOW, MIDCOM_PRIVILEGE_DENY, MIDCOM_PRIVILEGE_INHERIT])) { |
|
254
|
|
|
debug_add("Invalid privilege value '{$this->value}'.", MIDCOM_LOG_INFO); |
|
255
|
|
|
return false; |
|
256
|
|
|
} |
|
257
|
|
|
|
|
258
|
125 |
|
if ($this->classname != '') { |
|
259
|
1 |
|
if ($this->assignee != 'SELF') { |
|
260
|
|
|
debug_add("The classname parameter was specified without having the magic assignee SELF set, this is invalid.", MIDCOM_LOG_INFO); |
|
261
|
|
|
return false; |
|
262
|
|
|
} |
|
263
|
1 |
|
if (!class_exists($this->classname)) { |
|
264
|
|
|
debug_add("The class '{$this->classname}' is not found, the SELF magic assignee with class restriction is invalid therefore.", MIDCOM_LOG_INFO); |
|
265
|
|
|
return false; |
|
266
|
|
|
} |
|
267
|
|
|
} |
|
268
|
|
|
|
|
269
|
125 |
|
if ( !$this->is_magic_assignee() |
|
270
|
125 |
|
&& !$this->get_assignee()) { |
|
271
|
|
|
debug_add("The assignee identifier '{$this->assignee}' is invalid.", MIDCOM_LOG_INFO); |
|
272
|
|
|
return false; |
|
273
|
|
|
} |
|
274
|
125 |
|
if ( $this->assignee == 'OWNER' |
|
275
|
125 |
|
&& $this->privilegename == 'midgard:owner') { |
|
276
|
|
|
debug_add("Tried to assign midgard:owner to the OWNER magic assignee, this is invalid.", MIDCOM_LOG_INFO); |
|
277
|
|
|
return false; |
|
278
|
|
|
} |
|
279
|
|
|
|
|
280
|
125 |
|
$object = $this->get_object(); |
|
281
|
125 |
|
if (!$object) { |
|
282
|
|
|
debug_add("Could not retrieve the content object with the GUID '{$this->objectguid}'; see the debug level log for more information.", |
|
283
|
|
|
MIDCOM_LOG_INFO); |
|
284
|
|
|
return false; |
|
285
|
|
|
} |
|
286
|
125 |
|
if ( !$object->can_do('midgard:update') |
|
287
|
125 |
|
|| !$object->can_do('midgard:privileges')) { |
|
288
|
|
|
debug_add("Insufficient privileges on the content object with the GUID '{$this->__guid}', midgard:update and midgard:privileges required.", |
|
289
|
|
|
MIDCOM_LOG_INFO); |
|
290
|
|
|
return false; |
|
291
|
|
|
} |
|
292
|
|
|
|
|
293
|
125 |
|
return true; |
|
294
|
|
|
} |
|
295
|
|
|
|
|
296
|
|
|
/** |
|
297
|
|
|
* List all content privileges assigned to a given object. |
|
298
|
|
|
* Essentially, this will exclude all SELF style assignees. |
|
299
|
|
|
* |
|
300
|
|
|
* This function is for use in the authentication framework only. |
|
301
|
|
|
* |
|
302
|
|
|
* @return midcom_core_privilege[] |
|
303
|
|
|
*/ |
|
304
|
133 |
|
public static function get_content_privileges(string $guid) : array |
|
305
|
|
|
{ |
|
306
|
133 |
|
return self::_get_privileges($guid, 'CONTENT'); |
|
307
|
|
|
} |
|
308
|
|
|
|
|
309
|
|
|
/** |
|
310
|
|
|
* List all privileges assigned directly to a user or group. |
|
311
|
|
|
* These are all SELF privileges. |
|
312
|
|
|
* |
|
313
|
|
|
* This function is for use in the authentication framework only. |
|
314
|
|
|
* |
|
315
|
|
|
* @return midcom_core_privilege[] |
|
316
|
|
|
*/ |
|
317
|
14 |
|
public static function get_self_privileges(string $guid) : array |
|
318
|
|
|
{ |
|
319
|
14 |
|
return self::_get_privileges($guid, 'SELF'); |
|
320
|
|
|
} |
|
321
|
|
|
|
|
322
|
|
|
/** |
|
323
|
|
|
* List all privileges assigned an object unfiltered. |
|
324
|
|
|
* |
|
325
|
|
|
* This function is for use in the authentication framework only |
|
326
|
|
|
* |
|
327
|
|
|
* @return midcom_core_privilege[] |
|
328
|
|
|
*/ |
|
329
|
1 |
|
public static function get_all_privileges(string $guid) : array |
|
330
|
|
|
{ |
|
331
|
1 |
|
return array_merge(self::get_content_privileges($guid), self::get_self_privileges($guid)); |
|
332
|
|
|
} |
|
333
|
|
|
|
|
334
|
|
|
/** |
|
335
|
|
|
* List all privileges assigned an object unfiltered. |
|
336
|
|
|
* |
|
337
|
|
|
* @return midcom_core_privilege[] |
|
338
|
|
|
*/ |
|
339
|
134 |
|
private static function _get_privileges(string $guid, string $type) : array |
|
340
|
|
|
{ |
|
341
|
134 |
|
static $cache = []; |
|
342
|
|
|
|
|
343
|
134 |
|
$cache_key = $type . '-' . $guid; |
|
344
|
|
|
|
|
345
|
134 |
|
if (!array_key_exists($cache_key, $cache)) { |
|
346
|
132 |
|
$return = midcom::get()->cache->memcache->get('ACL', $cache_key); |
|
347
|
|
|
|
|
348
|
132 |
|
if (!is_array($return)) { |
|
349
|
|
|
// Didn't get privileges from cache, get them from DB |
|
350
|
132 |
|
$return = self::_query_privileges($guid, $type); |
|
351
|
132 |
|
midcom::get()->cache->memcache->put('ACL', $cache_key, $return); |
|
352
|
|
|
} |
|
353
|
|
|
|
|
354
|
132 |
|
$cache[$cache_key] = $return; |
|
355
|
|
|
} |
|
356
|
|
|
|
|
357
|
134 |
|
return $cache[$cache_key]; |
|
358
|
|
|
} |
|
359
|
|
|
|
|
360
|
|
|
/** |
|
361
|
|
|
* Query the database for privileges and construct all necessary objects out of it. |
|
362
|
|
|
* |
|
363
|
|
|
* @param string $type SELF or CONTENT |
|
364
|
|
|
* @return midcom_core_privilege[] |
|
365
|
|
|
*/ |
|
366
|
132 |
|
protected static function _query_privileges(string $guid, string $type) : array |
|
367
|
|
|
{ |
|
368
|
132 |
|
$result = []; |
|
369
|
|
|
|
|
370
|
132 |
|
$mc = new midgard_collector('midcom_core_privilege_db', 'objectguid', $guid); |
|
371
|
132 |
|
$mc->add_constraint('value', '<>', MIDCOM_PRIVILEGE_INHERIT); |
|
372
|
|
|
|
|
373
|
132 |
|
if ($type == 'CONTENT') { |
|
374
|
128 |
|
$mc->add_constraint('assignee', 'NOT IN', ['SELF', '']); |
|
375
|
|
|
} else { |
|
376
|
14 |
|
$mc->add_constraint('assignee', '=', 'SELF'); |
|
377
|
|
|
} |
|
378
|
|
|
|
|
379
|
132 |
|
$mc->set_key_property('guid'); |
|
380
|
132 |
|
$mc->add_value_property('id'); |
|
381
|
132 |
|
$mc->add_value_property('privilegename'); |
|
382
|
132 |
|
$mc->add_value_property('assignee'); |
|
383
|
132 |
|
$mc->add_value_property('classname'); |
|
384
|
132 |
|
$mc->add_value_property('value'); |
|
385
|
132 |
|
$mc->execute(); |
|
386
|
132 |
|
$privileges = $mc->list_keys(); |
|
387
|
|
|
|
|
388
|
132 |
|
foreach (array_keys($privileges) as $privilege_guid) { |
|
389
|
80 |
|
$privilege = $mc->get($privilege_guid); |
|
390
|
80 |
|
$privilege['objectguid'] = $guid; |
|
391
|
80 |
|
$privilege['guid'] = $privilege_guid; |
|
392
|
80 |
|
$privilege_object = new static($privilege); |
|
393
|
80 |
|
$result[] = $privilege_object; |
|
394
|
|
|
} |
|
395
|
|
|
|
|
396
|
132 |
|
return $result; |
|
397
|
|
|
} |
|
398
|
|
|
|
|
399
|
|
|
/** |
|
400
|
|
|
* Retrieve a single given privilege at a content object, identified by |
|
401
|
|
|
* the combination of assignee and privilege name. |
|
402
|
|
|
* |
|
403
|
|
|
* This call will return an object even if the privilege is set to INHERITED at |
|
404
|
|
|
* the given object (i.e. does not exist) for consistency reasons. Errors are |
|
405
|
|
|
* thrown for example on database inconsistencies. |
|
406
|
|
|
* |
|
407
|
|
|
* This function is for use in the authentication framework only. |
|
408
|
|
|
* |
|
409
|
|
|
* @param string $classname The optional classname required only for class-limited SELF privileges. |
|
410
|
|
|
*/ |
|
411
|
129 |
|
public static function get_privilege(midcom_core_dbaobject $object, string $name, string $assignee, string $classname = '') : midcom_core_privilege |
|
412
|
|
|
{ |
|
413
|
129 |
|
$qb = new midgard_query_builder('midcom_core_privilege_db'); |
|
414
|
129 |
|
$qb->add_constraint('objectguid', '=', $object->guid); |
|
415
|
129 |
|
$qb->add_constraint('privilegename', '=', $name); |
|
416
|
129 |
|
$qb->add_constraint('assignee', '=', $assignee); |
|
417
|
129 |
|
$qb->add_constraint('classname', '=', $classname); |
|
418
|
129 |
|
$result = $qb->execute(); |
|
419
|
|
|
|
|
420
|
129 |
|
if (empty($result)) { |
|
421
|
|
|
// No such privilege stored, return non-persistent one |
|
422
|
121 |
|
$privilege = new self; |
|
423
|
121 |
|
$privilege->set_object($object); |
|
424
|
121 |
|
$privilege->set_assignee($assignee); |
|
425
|
121 |
|
$privilege->privilegename = $name; |
|
426
|
121 |
|
$privilege->classname = $classname; |
|
427
|
121 |
|
$privilege->value = MIDCOM_PRIVILEGE_INHERIT; |
|
428
|
121 |
|
return $privilege; |
|
429
|
|
|
} |
|
430
|
25 |
|
if (count($result) > 1) { |
|
431
|
|
|
debug_add('A DB inconsistency has been detected. There is more than one record for privilege specified. Deleting all excess records after the first one!', |
|
432
|
|
|
MIDCOM_LOG_ERROR); |
|
433
|
|
|
debug_print_r('Content Object:', $object); |
|
434
|
|
|
debug_add("Privilege {$name} for assignee {$assignee} with classname {$classname} was queried.", MIDCOM_LOG_INFO); |
|
435
|
|
|
debug_print_r('Resultset was:', $result); |
|
436
|
|
|
midcom::get()->auth->request_sudo('midcom.core'); |
|
437
|
|
|
while (count($result) > 1) { |
|
438
|
|
|
$privilege = array_pop($result); |
|
439
|
|
|
$privilege->purge(); |
|
440
|
|
|
} |
|
441
|
|
|
midcom::get()->auth->drop_sudo(); |
|
442
|
|
|
} |
|
443
|
|
|
|
|
444
|
25 |
|
return new midcom_core_privilege($result[0]); |
|
445
|
|
|
} |
|
446
|
|
|
|
|
447
|
129 |
|
private function _load(midcom_core_privilege_db|string|null $src = null) |
|
448
|
|
|
{ |
|
449
|
129 |
|
if ($src instanceof midcom_core_privilege_db) { |
|
450
|
|
|
// Got a privilege object as argument, use that |
|
451
|
25 |
|
$this->__guid = $src->guid; |
|
452
|
25 |
|
$this->__privilege_object = $src; |
|
453
|
129 |
|
} elseif (is_string($src) && mgd_is_guid($src)) { |
|
454
|
|
|
$this->__guid = $src; |
|
455
|
|
|
$this->__privilege_object = new midcom_core_privilege_db($src); |
|
456
|
|
|
} else { |
|
457
|
|
|
// Have a nonpersistent privilege |
|
458
|
129 |
|
$this->__privilege_object = new midcom_core_privilege_db(); |
|
459
|
|
|
} |
|
460
|
|
|
} |
|
461
|
|
|
|
|
462
|
125 |
|
private function _sync_to_db_object() |
|
463
|
|
|
{ |
|
464
|
125 |
|
if (!$this->__privilege_object) { |
|
465
|
1 |
|
$this->_load($this->guid); |
|
466
|
|
|
} |
|
467
|
125 |
|
$this->__privilege_object->objectguid = $this->objectguid; |
|
468
|
125 |
|
$this->__privilege_object->privilegename = $this->privilegename; |
|
469
|
125 |
|
$this->__privilege_object->assignee = $this->assignee; |
|
470
|
125 |
|
$this->__privilege_object->classname = $this->classname; |
|
471
|
125 |
|
$this->__privilege_object->value = $this->value; |
|
472
|
|
|
} |
|
473
|
|
|
|
|
474
|
25 |
|
private function _sync_from_db_object() |
|
475
|
|
|
{ |
|
476
|
25 |
|
$this->objectguid = $this->__privilege_object->objectguid; |
|
477
|
25 |
|
$this->privilegename = $this->__privilege_object->privilegename; |
|
478
|
25 |
|
$this->assignee = $this->__privilege_object->assignee; |
|
479
|
25 |
|
$this->classname = $this->__privilege_object->classname; |
|
480
|
25 |
|
$this->value = $this->__privilege_object->value; |
|
481
|
25 |
|
$this->guid = $this->__privilege_object->guid; |
|
482
|
|
|
} |
|
483
|
|
|
|
|
484
|
|
|
/** |
|
485
|
|
|
* Store the privilege. This will validate it first and then either |
|
486
|
|
|
* update an existing privilege record, or create a new one, depending on the |
|
487
|
|
|
* DB state. |
|
488
|
|
|
*/ |
|
489
|
125 |
|
public function store() : bool |
|
490
|
|
|
{ |
|
491
|
125 |
|
if (!$this->validate()) { |
|
492
|
|
|
debug_add('This privilege failed to validate, rejecting it, see the debug log for details.', MIDCOM_LOG_WARN); |
|
493
|
|
|
$this->__cached_object = null; |
|
494
|
|
|
debug_print_r('Privilege dump (w/o cached object):', $this); |
|
495
|
|
|
return false; |
|
496
|
|
|
} |
|
497
|
|
|
|
|
498
|
125 |
|
$this->_sync_to_db_object(); |
|
499
|
|
|
|
|
500
|
125 |
|
if ($this->value == MIDCOM_PRIVILEGE_INHERIT) { |
|
501
|
|
|
if ($this->__guid) { |
|
502
|
|
|
// Already a persistent record, drop it. |
|
503
|
|
|
return $this->drop(); |
|
504
|
|
|
} |
|
505
|
|
|
// This is a temporary object only, try to load the real object first. If it is not found, |
|
506
|
|
|
// exit silently, as this is the desired final state. |
|
507
|
|
|
$object = $this->get_object(); |
|
508
|
|
|
$privilege = self::get_privilege($object, $this->privilegename, $this->assignee, $this->classname); |
|
509
|
|
|
if (!empty($privilege->__guid)) { |
|
510
|
|
|
if (!$privilege->drop()) { |
|
511
|
|
|
return false; |
|
512
|
|
|
} |
|
513
|
|
|
$this->_invalidate_cache(); |
|
514
|
|
|
} |
|
515
|
|
|
return true; |
|
516
|
|
|
} |
|
517
|
|
|
|
|
518
|
125 |
|
if ($this->__guid) { |
|
519
|
20 |
|
if (!$this->__privilege_object->update()) { |
|
520
|
|
|
return false; |
|
521
|
|
|
} |
|
522
|
20 |
|
$this->_invalidate_cache(); |
|
523
|
20 |
|
return true; |
|
524
|
|
|
} |
|
525
|
|
|
|
|
526
|
125 |
|
$object = $this->get_object(); |
|
527
|
125 |
|
$privilege = self::get_privilege($object, $this->privilegename, $this->assignee, $this->classname); |
|
528
|
125 |
|
if (!empty($privilege->__guid)) { |
|
529
|
20 |
|
$privilege->value = $this->value; |
|
530
|
20 |
|
if (!$privilege->store()) { |
|
531
|
|
|
debug_add('Update of the existing privilege failed.', MIDCOM_LOG_WARN); |
|
532
|
|
|
return false; |
|
533
|
|
|
} |
|
534
|
20 |
|
$this->__guid = $privilege->__guid; |
|
535
|
20 |
|
$this->objectguid = $privilege->objectguid; |
|
536
|
20 |
|
$this->privilegename = $privilege->privilegename; |
|
537
|
20 |
|
$this->assignee = $privilege->assignee; |
|
538
|
20 |
|
$this->classname = $privilege->classname; |
|
539
|
20 |
|
$this->value = $privilege->value; |
|
540
|
|
|
|
|
541
|
20 |
|
$this->_invalidate_cache(); |
|
542
|
20 |
|
return true; |
|
543
|
|
|
} |
|
544
|
|
|
|
|
545
|
117 |
|
if (!$this->__privilege_object->create()) { |
|
546
|
|
|
debug_add('Creating new privilege failed: ' . midcom_connection::get_error_string(), MIDCOM_LOG_WARN); |
|
547
|
|
|
return false; |
|
548
|
|
|
} |
|
549
|
117 |
|
$this->__guid = $this->__privilege_object->guid; |
|
550
|
117 |
|
$this->_invalidate_cache(); |
|
551
|
117 |
|
return true; |
|
552
|
|
|
} |
|
553
|
|
|
|
|
554
|
|
|
/** |
|
555
|
|
|
* Invalidate the memcache after I/O operations |
|
556
|
|
|
*/ |
|
557
|
125 |
|
private function _invalidate_cache() |
|
558
|
|
|
{ |
|
559
|
125 |
|
midcom::get()->cache->invalidate($this->objectguid); |
|
560
|
|
|
} |
|
561
|
|
|
|
|
562
|
|
|
/** |
|
563
|
|
|
* Drop the privilege. If we are a known DB record, we delete us, otherwise |
|
564
|
|
|
* we return silently. |
|
565
|
|
|
*/ |
|
566
|
9 |
|
public function drop() : bool |
|
567
|
|
|
{ |
|
568
|
9 |
|
$this->_sync_to_db_object(); |
|
569
|
|
|
|
|
570
|
9 |
|
if (!$this->__guid) { |
|
571
|
3 |
|
debug_add('We are not stored, GUID is empty. Ignoring silently.'); |
|
572
|
3 |
|
return true; |
|
573
|
|
|
} |
|
574
|
|
|
|
|
575
|
7 |
|
if (!$this->validate()) { |
|
576
|
|
|
debug_add('This privilege failed to validate, rejecting to drop it, see the debug log for details.', MIDCOM_LOG_WARN); |
|
577
|
|
|
debug_print_r('Privilege dump:', $this); |
|
578
|
|
|
return false; |
|
579
|
|
|
} |
|
580
|
|
|
|
|
581
|
7 |
|
if (!$this->__privilege_object->guid) { |
|
582
|
|
|
// We created this via collector, instantiate a new one |
|
583
|
|
|
$privilege = new midcom_core_privilege($this->__guid); |
|
584
|
|
|
return $privilege->drop(); |
|
585
|
|
|
} |
|
586
|
|
|
|
|
587
|
7 |
|
if (!$this->__privilege_object->purge()) { |
|
588
|
|
|
debug_add('Failed to delete privilege record, aborting. Error: ' . midcom_connection::get_error_string(), MIDCOM_LOG_ERROR); |
|
589
|
|
|
return false; |
|
590
|
|
|
} |
|
591
|
|
|
|
|
592
|
7 |
|
debug_add("Deleted privilege record {$this->__guid} ({$this->__privilege_object->objectguid} {$this->__privilege_object->privilegename} {$this->__privilege_object->assignee} {$this->__privilege_object->value}"); |
|
593
|
|
|
|
|
594
|
7 |
|
$this->_invalidate_cache(); |
|
595
|
7 |
|
$this->value = MIDCOM_PRIVILEGE_INHERIT; |
|
596
|
|
|
|
|
597
|
7 |
|
return true; |
|
598
|
|
|
} |
|
599
|
|
|
} |
|
600
|
|
|
|