PluginProbe ʕ •ᴥ•ʔ
Advanced Access Manager – Access Governance for WordPress / 5.8.2
Advanced Access Manager – Access Governance for WordPress v5.8.2
6.8.4 6.8.5 6.9.0 6.9.1 6.9.10 6.9.11 6.9.12 6.9.13 6.9.14 6.9.15 6.9.16 6.9.17 6.9.18 6.9.19 6.9.2 6.9.20 6.9.21 6.9.22 6.9.23 6.9.24 6.9.25 6.9.26 6.9.27 6.9.28 6.9.29 6.9.3 6.9.30 6.9.31 6.9.32 6.9.33 6.9.34 6.9.35 6.9.36 6.9.37 6.9.38 6.9.39 6.9.4 6.9.41 6.9.42 6.9.43 6.9.44 6.9.45 6.9.46 6.9.47 6.9.48 6.9.49 6.9.5 6.9.51 6.9.6 6.9.7 6.9.8 6.9.9 7.0.0 7.0.0-alpha.6 7.0.0-alpha.7 7.0.0-beta.1 7.0.0-rc1 7.0.0-rc2 7.0.0-rc3 7.0.1 7.0.10 7.0.11 7.0.2 7.0.3 7.0.4 7.0.5 7.0.6 7.0.7 7.0.8 7.0.9 7.1.0 7.1.1 trunk 3.0 4.0 4.0.1 4.1 4.2 4.3 4.4 4.4.1 4.5 4.6 4.6.1 4.6.2 4.7 4.7.1 4.7.2 4.7.5 4.7.6 4.8 4.8.1 4.9 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 4.9.5.1 4.9.5.2 5.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1 5.1.1 5.10 5.11 5.2 5.2.1 5.2.5 5.2.6 5.2.7 5.3 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.4 5.4.1 5.4.2 5.4.3 5.4.3.1 5.4.3.2 5.5 5.5.1 5.5.2 5.6 5.6.1 5.6.1.1 5.7 5.7.1 5.7.2 5.7.3 5.8 5.8.1 5.8.2 5.8.3 5.9 5.9.1 5.9.1.1 5.9.2 5.9.2.1 5.9.3 5.9.4 5.9.5 5.9.6 5.9.6.1 5.9.6.2 5.9.6.3 5.9.7 5.9.7.1 5.9.7.2 5.9.7.3 5.9.8 5.9.8.1 5.9.9 5.9.9.1 6.0.0 6.0.1 6.0.2 6.0.3 6.0.4 6.0.5 6.1.0 6.1.1 6.2.0 6.2.1 6.2.2 6.3.0 6.3.1 6.3.2 6.3.3 6.4.0 6.4.1 6.4.2 6.4.3 6.5.0 6.5.1 6.5.2 6.5.3 6.5.4 6.6.0 6.6.1 6.6.2 6.6.3 6.6.4 6.7.0 6.7.1 6.7.2 6.7.3 6.7.4 6.7.5 6.7.6 6.7.7 6.7.8 6.7.9 6.8.0 6.8.1 6.8.2 6.8.3
advanced-access-manager / Application / Core / Object / Policy.php
advanced-access-manager / Application / Core / Object Last commit date
Cache.php 7 years ago Capability.php 7 years ago LoginRedirect.php 7 years ago LogoutRedirect.php 7 years ago Menu.php 7 years ago Metabox.php 7 years ago Policy.php 7 years ago Post.php 7 years ago Redirect.php 7 years ago Route.php 7 years ago Toolbar.php 7 years ago Uri.php 7 years ago Visibility.php 7 years ago
Policy.php
468 lines
1 <?php
2
3 /**
4 * ======================================================================
5 * LICENSE: This file is subject to the terms and conditions defined in *
6 * file 'license.txt', which is part of this source code package. *
7 * ======================================================================
8 */
9
10 /**
11 * Policy object
12 *
13 * @package AAM
14 * @author Vasyl Martyniuk <vasyl@vasyltech.com>
15 */
16 class AAM_Core_Object_Policy extends AAM_Core_Object {
17
18 /**
19 * Resource tree
20 *
21 * Shared resource tree across all the policy instances
22 *
23 * @var array
24 *
25 * @access protected
26 * @static
27 */
28 protected static $resources = array();
29
30 /**
31 * Feature tree
32 *
33 * Shared features tree across all the policy instances
34 *
35 * @var array
36 *
37 * @access protected
38 * @static
39 */
40 protected static $features = array();
41
42 /**
43 * Constructor
44 *
45 * @param AAM_Core_Subject $subject
46 *
47 * @return void
48 *
49 * @access public
50 */
51 public function __construct(AAM_Core_Subject $subject) {
52 parent::__construct($subject);
53
54 $this->initialize();
55 }
56
57 /**
58 * Initialize the policy rules for current subject
59 *
60 * @return void
61 *
62 * @access public
63 */
64 public function initialize() {
65 $subject = $this->getSubject();
66 $parent = $subject->inheritFromParent('policy');
67
68 if(empty($parent)) {
69 $parent = array();
70 }
71
72 $option = $subject->readOption('policy');
73 if (empty($option)) {
74 $option = array();
75 } else {
76 $this->setOverwritten(true);
77 }
78
79 foreach($option as $key => $value) {
80 $parent[$key] = $value; //override
81 }
82
83 $this->setOption($parent);
84
85 // Load statements for policies
86 $subjectId = $subject->getUID();
87 $subjectId .= ($subject->getId() ? ".{$subject->getId()}" : '');
88
89 $this->load($subjectId, $option);
90 }
91
92 /**
93 * Load all defined policies for specified subject
94 *
95 * @param string $subjectId
96 * @param array $policies
97 *
98 * @return void
99 *
100 * @access public
101 */
102 public function load($subjectId, $policies) {
103 $resources = array();
104 $features = array();
105 $list = $this->parsePolicy($subjectId, $policies);
106
107 // Evaluate all Statements first
108 foreach($list['Statements'] as $statement) {
109 if (isset($statement['Resource']) && $this->applicable($statement)) {
110 $this->evaluateStatement($statement, $resources);
111 }
112 }
113 self::$resources[$subjectId] = $resources;
114
115 // Evaluate all Features then
116 foreach($list['Features'] as $feature) {
117 if ($this->applicable($feature)) {
118 $this->evaluateFeature($feature, $features);
119 }
120 }
121
122 self::$features[$subjectId] = $features;
123 }
124
125 /**
126 *
127 * @return type
128 */
129 protected function parsePolicy($subjectId, $policies) {
130 $cache = AAM::api()->getUser()->getObject('cache');
131 $list = AAM_Core_Compatibility::preparePolicyList(
132 $cache->get('policy', $subjectId, null)
133 );
134
135 if (is_null($list)) {
136 $list = array(
137 'Statements' => array(),
138 'Features' => array()
139 );
140
141 foreach($policies as $id => $effect) {
142 $policy = get_post($id);
143
144 if (is_a($policy, 'WP_Post')) {
145 $obj = json_decode($policy->post_content, true);
146 if (json_last_error() === JSON_ERROR_NONE) {
147 $list['Statements'] = array_merge(
148 $list['Statements'], $this->extractStatements($obj, empty($effect))
149 );
150 $list['Features'] = array_merge(
151 $list['Features'], $this->extractFeatures($obj, empty($effect))
152 );
153 }
154 }
155 }
156 $cache->add('policy', $subjectId, $list);
157 }
158
159 return $list;
160 }
161
162 /**
163 *
164 * @param type $policy
165 * @return type
166 */
167 protected function extractStatements($policy, $unset = false) {
168 $statements = array();
169
170 if (isset($policy['Statement'])) {
171 if (is_array($policy['Statement'])) {
172 $statements = $policy['Statement'];
173 } else {
174 $statements = array($policy['Statement']);
175 }
176 }
177
178 // normalize each statement
179 foreach(array('Action', 'Condition') as $prop) {
180 foreach($statements as $i => $statement) {
181 if (isset($statement[$prop])) {
182 $statements[$i][$prop] = (array) $statement[$prop];
183 }
184 }
185 }
186
187 if ($unset === true) {
188 foreach($statements as &$statement) {
189 $statement['Unset'] = true;
190 }
191 }
192
193 return $statements;
194 }
195
196 /**
197 * Extract list of policy features
198 *
199 * @param array $policy
200 *
201 * @return array
202 *
203 * @access protected
204 * @since v5.7.3
205 */
206 protected function extractFeatures($policy, $unset = false) {
207 $features = array();
208
209 if (isset($policy['Feature'])) {
210 if (is_array($policy['Feature'])) {
211 $features = $policy['Feature'];
212 } else {
213 $features = array($policy['Feature']);
214 }
215 }
216
217 if ($unset === true) {
218 foreach($features as &$feature) {
219 $feature['Unset'] = true;
220 }
221 }
222
223 return $features;
224 }
225
226 /**
227 *
228 * @param type $statement
229 * @param type $resources
230 */
231 protected function evaluateStatement($statement, &$resources) {
232 $actions = (array)(!empty($statement['Action']) ? $statement['Action'] : '');
233
234 foreach((array)$statement['Resource'] as $resource) {
235 foreach($actions as $action) {
236 $id = strtolower($resource . (!empty($action) ? ":{$action}" : ''));
237
238 // Add new statement
239 if (!isset($resources[$id])) {
240 $resources[$id] = $statement;
241 // Merge statement unless the first one is marked as Enforced
242 } elseif (empty($resources[$id]['Enforce'])) {
243 $resources[$id] = $this->mergeStatements(
244 $resources[$id], $statement
245 );
246 }
247
248 $this->normalizeResource($resources, $id);
249 }
250 }
251 }
252
253 /**
254 *
255 * @param type $feature
256 * @param type $features
257 */
258 protected function evaluateFeature($feature, &$features) {
259 $id = strtolower("{$feature['Plugin']}:{$feature['Feature']}");
260
261 // Add new statement
262 if (!isset($features[$id])) {
263 $features[$id] = $feature;
264 // Override feature unless the first one is marked as Enforced
265 } elseif (empty($features[$id]['Enforce'])) {
266 $features[$id] = $feature;
267 }
268 }
269
270 /**
271 *
272 * @param type $resources
273 * @param type $id
274 */
275 protected function normalizeResource(&$resources, $id) {
276 // cleanup fields
277 foreach(array('Resource', 'Action', 'Condition') as $field) {
278 if (isset($resources[$id][$field])) {
279 unset($resources[$id][$field]);
280 }
281 }
282 }
283
284 /**
285 *
286 * @param type $statement
287 * @return boolean
288 */
289 protected function applicable($statement) {
290 $result = true;
291
292 if (!empty($statement['Condition']) && !is_scalar($statement['Condition'])) {
293 $result = AAM_Core_Policy_Condition::getInstance()->evaluate(
294 $statement['Condition']
295 );
296 }
297
298 return $result;
299 }
300
301 /**
302 *
303 * @param type $left
304 * @param type $right
305 * @return type
306 */
307 protected function mergeStatements($left, $right) {
308 if (isset($right['Resource'])) {
309 unset($right['Resource']);
310 }
311
312 $merged = array_merge($left, $right);
313
314 if (!isset($merged['Effect'])) {
315 $merged['Effect'] = 'deny';
316 }
317
318 return $merged;
319 }
320
321 /**
322 * Save menu option
323 *
324 * @return bool
325 *
326 * @access public
327 */
328 public function save($id, $effect) {
329 $option = $this->getOption();
330 $option[$id] = intval($effect);
331
332 $this->setOption($option);
333
334 return $this->getSubject()->updateOption($this->getOption(), 'policy');
335 }
336
337 /**
338 *
339 * @param type $id
340 */
341 public function has($id) {
342 $option = $this->getOption();
343
344 return !empty($option[$id]);
345 }
346
347 /**
348 *
349 * @param type $resource
350 * @return type
351 */
352 public function isAllowed($resource, $action = null) {
353 $allowed = null;
354
355 $id = strtolower($resource . (!empty($action) ? ":{$action}" : ''));
356 $res = $this->getResources();
357
358 if (isset($res[$id])) {
359 $allowed = ($res[$id]['Effect'] === 'allow');
360 }
361
362 return $allowed;
363 }
364
365 /**
366 *
367 * @param type $feature
368 * @param type $plugin
369 * @return type
370 */
371 public function isEnabled($feature, $plugin) {
372 $enabled = null;
373
374 $id = strtolower("{$plugin}:{$feature}");
375 $res = $this->getFeatures();
376
377 if (isset($res[$id])) {
378 $enabled = in_array($res[$id]['Effect'], array('allow', 'enable'), true);
379 }
380
381 return $enabled;
382 }
383
384 /**
385 *
386 * @param type $id
387 *
388 * @return type
389 */
390 public function delete($id) {
391 $option = $this->getOption();
392 if (isset($option[$id])) {
393 unset($option[$id]);
394 }
395 $this->setOption($option);
396
397 return $this->getSubject()->updateOption($this->getOption(), 'policy');
398 }
399
400 /**
401 *
402 * @param type $external
403 * @return type
404 */
405 public function mergeOption($external) {
406 return AAM::api()->mergeSettings($external, $this->getOption(), 'policy');
407 }
408
409 /**
410 *
411 * @return type
412 */
413 public function getResources(AAM_Core_Subject $subject = null) {
414 return $this->getList(self::$resources, $subject);
415 }
416
417 /**
418 *
419 * @return type
420 */
421 public function getFeatures(AAM_Core_Subject $subject = null) {
422 return $this->getList(self::$features, $subject);
423 }
424
425 /**
426 * Get list from source
427 *
428 * @param array $source
429 * @param AAM_Core_Subject $subject
430 *
431 * @return array
432 *
433 * @access protected
434 * @since v5.8.2
435 */
436 protected function getList(&$source, AAM_Core_Subject $subject = null) {
437 $response = array();
438
439 if (is_null($subject)) {
440 if (!isset($source['__combined'])) {
441 foreach($source as $resources) {
442 foreach ($resources as $id => $props) {
443 if (!empty($props['Unset'])) {
444 if (isset($response[$id])) { // Clear the entire chain
445 unset($response[$id]);
446 }
447 } else {
448 $response[$id] = $props;
449 }
450 }
451 }
452 $source['__combined'] = $response;
453 } else {
454 $response = $source['__combined'];
455 }
456 } else {
457 $subjectId = $subject->getUID();
458 $subjectId .= ($subject->getId() ? ".{$subject->getId()}" : '');
459
460 if (isset($source[$subjectId])) {
461 $response = $source[$subjectId];
462 }
463 }
464
465 return $response;
466 }
467
468 }