PluginProbe
Advanced Access Manager – Access Governance for WordPress / 6.9.0
Advanced Access Manager – Access Governance for WordPress v6.9.0
7.1.4 7.1.2 7.1.3 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 All 210 releases
advanced-access-manager / application / Core / Policy / Token.php
Token.php
569 lines 14.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 * AAM core policy token evaluator
12 *
13 * @since 6.8.3 https://github.com/aamplugin/advanced-access-manager/issues/205
14 * @since 6.3.0 Fixed bug that was causing fatal error policies that have conditions
15 * defined for Capability & Role resources
16 * @since 6.2.1 Added POLICY_META token
17 * @since 6.2.0 Enhanced access policy with more tokens. DATETIME now returns time in
18 * UTC timezone
19 * @since 6.1.0 Added support for the new token `AAM_CONFIG`
20 * @since 6.0.0 Initial implementation of the class
21 *
22 * @package AAM
23 * @version 6.8.3
24 */
25 class AAM_Core_Policy_Token
26 {
27
28 /**
29 * Literal map token's type to the executable method that returns actual value
30 *
31 * @var array
32 *
33 * @since 6.8.5 https://github.com/aamplugin/advanced-access-manager/issues/216
34 * @since 6.8.3 https://github.com/aamplugin/advanced-access-manager/issues/205
35 * @since 6.3.0 Added PHP_GLOBAL, WP_NETWORK_OPTION token and changed
36 * WP_OPTION callback
37 * @since 6.2.1 Added `POLICY_META` token
38 * @since 6.2.0 Added `POLICY_PARAM`, `WP_SITE` token & changed the
39 * DATETIME callback
40 * @since 6.1.0 Added `AAM_CONFIG` token
41 * @since 6.0.0 Initial implementation of the property
42 *
43 * @access protected
44 * @version 6.8.5
45 */
46 protected static $map = array(
47 'USER' => 'AAM_Core_Policy_Token::getUserValue',
48 'USER_OPTION' => 'AAM_Core_Policy_Token::getUserOptionValue',
49 'USER_META' => 'AAM_Core_Policy_Token::getUserMetaValue',
50 'DATETIME' => 'AAM_Core_Policy_Token::getDatetime',
51 'HTTP_GET' => 'AAM_Core_Request::get',
52 'HTTP_QUERY' => 'AAM_Core_Request::get',
53 'HTTP_POST' => 'AAM_Core_Request::post',
54 'HTTP_COOKIE' => 'AAM_Core_Request::cookie',
55 'PHP_SERVER' => 'AAM_Core_Request::server',
56 'PHP_GLOBAL' => 'AAM_Core_Policy_Token::getGlobalVariable',
57 'ARGS' => 'AAM_Core_Policy_Token::getArgValue',
58 'ENV' => 'getenv',
59 'CONST' => 'AAM_Core_Policy_Token::getConstant',
60 'WP_OPTION' => 'AAM_Core_Policy_Token::getWPOption',
61 'JWT' => 'AAM_Core_Policy_Token::getJwtClaim',
62 'AAM_CONFIG' => 'AAM_Core_Policy_Token::getConfig',
63 'POLICY_PARAM' => 'AAM_Core_Policy_Token::getParam',
64 'POLICY_META' => 'AAM_Core_Policy_Token::getPolicyMeta',
65 'WP_SITE' => 'AAM_Core_Policy_Token::getSiteParam',
66 'WP_NETWORK_OPTION' => 'AAM_Core_Policy_Token::getNetworkOption',
67 'THE_POST' => 'AAM_Core_Policy_Token::getCurrentPostValue'
68 );
69
70 /**
71 * Evaluate collection of tokens and replace them with values
72 *
73 * @param string $part String with tokens
74 * @param array $tokens Extracted token
75 * @param array $args Inline arguments
76 *
77 * @return string
78 *
79 * @since 6.1.0 Changed `getValue` method to `getTokenValue`
80 * @since 6.0.0 Initial implementation of the method
81 *
82 * @access public
83 * @version 6.1.0
84 */
85 public static function evaluate($part, array $tokens, array $args = array())
86 {
87 foreach ($tokens as $token) {
88 $val = self::getTokenValue($token, $args);
89 $part = str_replace(
90 $token,
91 (is_scalar($val) || is_null($val) ? $val : json_encode($val)),
92 $part
93 );
94 }
95
96 return $part;
97 }
98
99 /**
100 * Get token value
101 *
102 * @param string $token
103 * @param array $args
104 *
105 * @return mixed
106 *
107 * @since 6.8.3 https://github.com/aamplugin/advanced-access-manager/issues/206
108 * @since 6.3.3 https://github.com/aamplugin/advanced-access-manager/issues/50
109 * @since 6.1.0 Initial implementation of the method
110 *
111 * @access public
112 * @version 6.8.3
113 */
114 public static function getTokenValue($token, $args = array())
115 {
116 $parts = explode('.', preg_replace('/^\$\{([^}]+)\}$/', '${1}', $token), 2);
117
118 if (isset(self::$map[$parts[0]])) {
119 if ($parts[0] === 'ARGS') {
120 $value = call_user_func(self::$map[$parts[0]], $parts[1], $args);
121 } else {
122 $value = call_user_func(self::$map[$parts[0]], $parts[1]);
123 }
124 } elseif ($parts[0] === 'CALLBACK') {
125 $value = self::evaluateCallback($parts[1], $args);
126 } else {
127 $value = apply_filters(
128 'aam_policy_token_value_filter', null, $parts[0], $parts[1], $args
129 );
130 }
131
132 return $value;
133 }
134
135 /**
136 * Evaluate CALLBACK expression
137 *
138 * @param string $exp
139 * @param array $args
140 *
141 * @return mixed
142 *
143 * @access protected
144 * @version 6.8.3
145 */
146 protected static function evaluateCallback($exp, $args)
147 {
148 $response = null;
149 $cb = self::_parseFunction($exp, $args);
150
151 if (!is_null($cb)) {
152 if (is_callable($cb['func']) || function_exists($cb['func'])) {
153 $result = call_user_func_array($cb['func'], $cb['args']);
154
155 if (!empty($cb['xpath'])) {
156 $response = self::_getValueByXPath($result, $cb['xpath']);
157 } else {
158 $response = $result;
159 }
160 }
161 }
162
163 return $response;
164 }
165
166 /**
167 * Parse CALLBACK expression
168 *
169 * @param string $exp
170 * @param array $args
171 *
172 * @return array
173 *
174 * @access private
175 * @version 6.8.3
176 */
177 private static function _parseFunction($exp, $args)
178 {
179 $response = null;
180 $regex = '/^([^(]+)\(?([^)]*)\)?(.*)$/i';
181
182 if (preg_match($regex, $exp, $match)) {
183 // The second part is the collection of arguments that we pass to
184 // the function
185 $markers = array_map('trim', explode(',', $match[2]));
186 $values = [];
187
188 foreach($markers as $marker) {
189 if (preg_match('/^\'.*\'$/', $marker) === 1) { // This is literal string
190 array_push($values, trim($marker, '\''));
191 } elseif (strpos($marker, '.') !== false) { // Potentially another marker
192 array_push($values, self::getTokenValue($marker, $args));
193 } else {
194 array_push($values, $marker);
195 }
196 }
197
198 $response = array(
199 'func' => trim($match[1]),
200 'args' => $values,
201 'xpath' => trim($match[3])
202 );
203 }
204
205 return $response;
206 }
207
208 /**
209 * Get value by xpath
210 *
211 * This method supports multiple different path
212 *
213 * @param mixed $obj
214 * @param string $xpath
215 *
216 * @return mixed
217 *
218 * @access private
219 * @version 6.8.3
220 */
221 private static function _getValueByXPath($obj, $xpath)
222 {
223 $value = $obj;
224 $path = trim(
225 str_replace(
226 array('["', '[', '"]', ']', '..'), '.', $xpath
227 ),
228 ' .' // white space is important!
229 );
230
231 foreach(explode('.', $path) as $l) {
232 if (is_object($value)) {
233 if (isset($value->{$l})) {
234 $value = $value->{$l};
235 } else {
236 $value = null;
237 break;
238 }
239 } else if (is_array($value)) {
240 if (array_key_exists($l, $value)) {
241 $value = $value[$l];
242 } else {
243 $value = null;
244 break;
245 }
246 }
247 }
248
249 return $value;
250 }
251
252 /**
253 * Get USER's value
254 *
255 * @param string $prop
256 *
257 * @return mixed
258 *
259 * @since 6.3.0 Fixed bug that caused "Fatal error: Allowed memory size of XXX
260 * bytes exhausted"
261 * @since 6.0.0 Initial implementation of the method
262 *
263 * @access protected
264 * @version 6.3.0
265 */
266 protected static function getUserValue($prop)
267 {
268 $user = wp_get_current_user();
269
270 switch (strtolower($prop)) {
271 case 'ip':
272 case 'ipaddress':
273 $value = AAM_Core_Request::server('REMOTE_ADDR');
274 break;
275
276 case 'authenticated':
277 case 'isauthenticated':
278 $value = is_user_logged_in();
279 break;
280
281 case 'capabilities':
282 case 'caps':
283 $allcaps = is_a($user, 'WP_User') ? (array)$user->allcaps : array();
284
285 foreach ($allcaps as $cap => $effect) {
286 if (!empty($effect)) {
287 $value[] = $cap;
288 }
289 }
290 break;
291
292 default:
293 $value = (is_a($user, 'WP_User') ? $user->{$prop} : null);
294 break;
295 }
296
297 return $value;
298 }
299
300 /**
301 * Get user option value(s)
302 *
303 * @param string $option_name
304 *
305 * @return void
306 *
307 * @access protected
308 * @version 6.0.0
309 */
310 protected static function getUserOptionValue($option_name)
311 {
312 $value = null;
313 $id = get_current_user_id();
314
315 if (!empty($id)) { // Only authenticated users have some sort of meta
316 $value = get_user_option($option_name, $id);
317 }
318
319 return $value;
320 }
321
322 /**
323 * Get currently viewed post property
324 *
325 * @param string $option_name
326 *
327 * @return mixed
328 *
329 * @access protected
330 * @version since 6.8.3
331 */
332 protected static function getCurrentPostValue($option_name)
333 {
334 $post = AAM_Core_API::getCurrentPost();
335
336 return is_a($post, 'AAM_Core_Object_Post') ? $post->{$option_name} : null;
337 }
338
339 /**
340 * Get user meta value(s)
341 *
342 * @param string $meta_key
343 *
344 * @return void
345 *
346 * @access protected
347 * @version 6.0.0
348 */
349 protected static function getUserMetaValue($meta_key)
350 {
351 $value = null;
352 $id = get_current_user_id();
353
354 if (!empty($id)) { // Only authenticated users have some sort of meta
355 $meta = get_user_meta($id, $meta_key);
356
357 // If $meta has only one value in the array, then extract it, otherwise
358 // return the array of values
359 if (count($meta) === 1) {
360 $value = array_shift($meta);
361 } else {
362 $value = array_values($meta);
363 }
364 }
365
366 return $value;
367 }
368
369 /**
370 * Get inline argument
371 *
372 * @param string $prop
373 * @param array $args
374 *
375 * @return mixed
376 *
377 * @access protected
378 * @version 6.0.0
379 */
380 protected static function getArgValue($prop, $args)
381 {
382 return (isset($args[$prop]) ? $args[$prop] : null);
383 }
384
385 /**
386 * Get JWT claim property
387 *
388 * @param string $prop
389 *
390 * @return mixed
391 *
392 * @access protected
393 * @version 6.0.0
394 */
395 protected static function getJwtClaim($prop)
396 {
397 return apply_filters('aam_get_jwt_claim', null, $prop);
398 }
399
400 /**
401 * Get a value for the defined constant
402 *
403 * @param string $const
404 *
405 * @return mixed
406 *
407 * @access protected
408 * @version 6.0.0
409 */
410 protected static function getConstant($const)
411 {
412 return (defined($const) ? constant($const) : null);
413 }
414
415 /**
416 * Get database option
417 *
418 * @param string $option
419 *
420 * @return mixed
421 *
422 * @access protected
423 * @version 6.3.0
424 */
425 protected static function getWPOption($option)
426 {
427 if (is_multisite()) {
428 $result = get_blog_option(get_current_blog_id(), $option);
429 } else {
430 $result = get_option($option);
431 }
432
433 return $result;
434 }
435
436 /**
437 * Get AAM configuration
438 *
439 * @param string $config
440 *
441 * @return mixed
442 *
443 * @access protected
444 * @version 6.1.0
445 */
446 protected static function getConfig($config)
447 {
448 return AAM::api()->getConfig($config);
449 }
450
451 /**
452 * Get access policy param
453 *
454 * @param string $param
455 *
456 * @return mixed
457 *
458 * @access protected
459 * @version 6.2.0
460 */
461 protected static function getParam($param)
462 {
463 return AAM::api()->getAccessPolicyManager()->getParam($param);
464 }
465
466 /**
467 * Get access policy metadata
468 *
469 * @param string $meta
470 *
471 * @return mixed
472 *
473 * @since 6.3.0 Fixed potential bug https://github.com/aamplugin/advanced-access-manager/issues/38
474 * @since 6.2.1 Initial implementation of the method
475 *
476 * @access protected
477 * @version 6.3.0
478 */
479 protected static function getPolicyMeta($meta)
480 {
481 $parts = explode('.', $meta, 2);
482
483 return get_post_meta(intval($parts[0]), $parts[1], true);
484 }
485
486 /**
487 * Get current datetime
488 *
489 * @param string $format
490 *
491 * @return string
492 *
493 * @access protected
494 * @version 6.2.0
495 */
496 protected static function getDatetime($format)
497 {
498 $result = null;
499
500 try {
501 $result = (new DateTime('now', new DateTimeZone('UTC')))->format($format);
502 } catch (Exception $e) {
503 _doing_it_wrong(
504 __CLASS__ . '::' . __METHOD__,
505 'Invalid date/time format: ' . $e->getMessage(),
506 AAM_VERSION
507 );
508 }
509
510 return $result;
511 }
512
513 /**
514 * Get current blog details
515 *
516 * @param string $param
517 *
518 * @return mixed
519 *
520 * @access protected
521 * @version 6.2.0
522 */
523 protected static function getSiteParam($param)
524 {
525 $result = null;
526
527 if (is_multisite()) {
528 $result = get_blog_details()->{$param};
529 } elseif ($param === 'blog_id') {
530 $result = get_current_blog_id();
531 }
532
533 return $result;
534 }
535
536 /**
537 * Get global variable's value
538 *
539 * @param string $var
540 *
541 * @return mixed
542 *
543 * @since 6.8.5 https://github.com/aamplugin/advanced-access-manager/issues/216
544 * @since 6.3.0 Initial implementation of the method
545 *
546 * @access protected
547 * @version 6.8.5
548 */
549 protected static function getGlobalVariable($var)
550 {
551 return self::_getValueByXPath($GLOBALS, $var);
552 }
553
554 /**
555 * Get network option
556 *
557 * @param string $option
558 *
559 * @return mixed
560 *
561 * @access protected
562 * @version 6.3.0
563 */
564 protected static function getNetworkOption($option)
565 {
566 return get_site_option($option, null);
567 }
568
569 }