PluginProbe ʕ •ᴥ•ʔ
Advanced Access Manager – Access Governance for WordPress / 5.9
Advanced Access Manager – Access Governance for WordPress v5.9
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 / Policy / Manager.php
advanced-access-manager / Application / Core / Policy Last commit date
Condition.php 7 years ago Factory.php 7 years ago Manager.php 7 years ago Token.php 7 years ago Validator.php 7 years ago
Manager.php
326 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 * AAM core policy manager
12 *
13 * @package AAM
14 * @author Vasyl Martyniuk <vasyl@vasyltech.com>
15 * @since AAM v5.7.2
16 */
17 final class AAM_Core_Policy_Manager {
18
19 /**
20 * Policy core object
21 *
22 * @var AAM_Core_Object_Policy
23 *
24 * @access protected
25 */
26 protected $policyObject;
27
28 /**
29 * Current subject
30 *
31 * @var AAM_Core_Subject
32 *
33 * @access protected
34 */
35 protected $subject;
36
37 /**
38 * Parsed policy tree
39 *
40 * @var array
41 *
42 * @access protected
43 */
44 protected $tree = null;
45
46 /**
47 * Constructor
48 *
49 * @access protected
50 *
51 * @return void
52 */
53 public function __construct(AAM_Core_Subject $subject) {
54 $this->policyObject = $subject->getObject('policy');
55 $this->subject = $subject;
56 }
57
58 /**
59 * Call policy object public methods
60 *
61 * @param string $name
62 * @param array $args
63 *
64 * @return mixed
65 *
66 * @access public
67 */
68 public function __call($name, $args) {
69 $result = null;
70
71 if (method_exists($this->policyObject, $name)) {
72 $result = call_user_func_array(array($this->policyObject, $name), $args);
73 }
74
75 return $result;
76 }
77
78 /**
79 * Find all the matching policies
80 *
81 * @param string $s RegEx
82 * @param array $args Inline arguments
83 * @param bool $single Single record only - the last record
84 *
85 * @return array
86 *
87 * @access public
88 */
89 public function find($s, $args = array(), $single = false) {
90 $statements = array();
91 $tree = $this->preparePolicyTree();
92
93 foreach($tree['Statement'] as $key => $stm) {
94 if (preg_match($s, $key) && $this->isApplicable($stm, $args)) {
95 $statements[strtolower($key)] = $stm;
96 }
97 }
98
99 return ($single ? end($statements) : $statements);
100 }
101
102 /**
103 * Check if specified action is allowed for resource
104 *
105 * This method is working with "Statement" array.
106 *
107 * @param string $resource Resource name
108 * @param array $args Args that will be injected during condition evaluation
109 *
110 * @return boolean|null
111 *
112 * @access public
113 */
114 public function isAllowed($resource, $args = array()) {
115 $allowed = null;
116 $tree = $this->preparePolicyTree();
117 $id = strtolower($resource);
118
119 if (isset($tree['Statement'][$id])) {
120 $stm = $tree['Statement'][$id];
121
122 if ($this->isApplicable($stm, $args)) {
123 $effect = strtolower($stm['Effect']);
124 $allowed = ($effect === 'allow');
125 }
126 }
127
128 return $allowed;
129 }
130
131 /**
132 * Get Policy Param
133 *
134 * @param string $name
135 * @param array $args
136 *
137 * @return mixed
138 *
139 * @access public
140 */
141 public function getParam($name, $args = array()) {
142 $value = null;
143 $id = strtolower($name);
144
145 if (isset($this->tree['Param'][$id])) {
146 $param = $this->tree['Param'][$id];
147
148 if ($this->isApplicable($param, $args)) {
149 $value = $param['Value'];
150 }
151 }
152
153 return $value;
154 }
155
156 /**
157 * Check if current subject can toggle specific policy
158 *
159 * Verify that policy can be attached/detached
160 *
161 * @param int $id Policy ID
162 * @param string $action Either "attach" or "detach"
163 *
164 * @return bool
165 *
166 * @access public
167 * @since v5.9
168 */
169 public function canTogglePolicy($id, $action) {
170 $post = get_post($id);
171
172 // Verify that current user can perform following action
173 $stm = $this->find(
174 "/^post:{$post->post_type}:({$post->post_name}|{$post->ID}):{$action}/i",
175 array('post' => $post),
176 true
177 );
178
179 return (empty($stm['Effect']) || $stm['Effect'] === 'allow');
180 }
181
182 /**
183 * Check if policy block is applicable
184 *
185 * @param array $block
186 * @param array $args
187 *
188 * @return boolean
189 *
190 * @access protected
191 */
192 protected function isApplicable($block, $args) {
193 $result = true;
194
195 if (!empty($block['Condition']) && !is_scalar($block['Condition'])) {
196 $result = AAM_Core_Policy_Condition::getInstance()->evaluate(
197 $block['Condition'], $args
198 );
199 }
200
201 return $result;
202 }
203
204 /**
205 * Prepare policy tree
206 *
207 * This is the lazy load for the policy tree. If tree has not been initialized,
208 * trigger the process of parsing and merging statements and settings.
209 *
210 * @return array
211 *
212 * @access protected
213 */
214 protected function preparePolicyTree() {
215 if (is_null($this->tree)) {
216 $cache = $this->subject->getObject('cache')->get('policyTree');
217
218 if (empty($cache)) {
219 $this->tree = array(
220 'Statement' => array(),
221 'Param' => array()
222 );
223
224 foreach($this->policyObject->getOption() as $id => $effect) {
225 if (!empty($effect)) { // Load policy only if it is attached
226 $this->extendTree(
227 $this->tree, $this->parsePolicy(get_post($id))
228 );
229 }
230 }
231
232 $this->subject->getObject('cache')->add('policyTree', 0, $this->tree);
233 } else {
234 $this->tree = $cache;
235 }
236 }
237
238 return $this->tree;
239 }
240
241 /**
242 * Parse policy post and extract Statements and Params
243 *
244 * @param WP_Post $policy
245 *
246 * @return array
247 *
248 * @access protected
249 */
250 protected function parsePolicy($policy) {
251 $tree = array('Statement' => array(), 'Param' => array());
252 // Only parse if policy is valid WP post and is published (active)
253 if (is_a($policy, 'WP_Post') && ($policy->post_status === 'publish')) {
254 $val = json_decode($policy->post_content, true);
255
256 // Do not load the policy if any errors
257 if (json_last_error() === JSON_ERROR_NONE) {
258 $tree = array(
259 'Statement' => isset($val['Statement']) ? (array) $val['Statement'] : array(),
260 'Param' => isset($val['Param']) ? (array) $val['Param'] : array(),
261 );
262 }
263 }
264
265 return $tree;
266 }
267
268 /**
269 * Extend tree with additional statements and params
270 *
271 * @param array &$tree
272 * @param array $addition
273 *
274 * @return array
275 *
276 * @access protected
277 */
278 protected function extendTree(&$tree, $addition) {
279 // Step #1. If there are any statements, let's index them by resource:action
280 // and insert into the list of statements
281 foreach($addition['Statement'] as $stm) {
282 $ress = (isset($stm['Resource']) ? (array) $stm['Resource'] : array());
283 $acts = (isset($stm['Action']) ? (array) $stm['Action'] : array(''));
284
285 foreach($ress as $res) {
286 foreach($acts as $act) {
287 $id = strtolower($res . (!empty($act) ? ":{$act}" : ''));
288
289 if (!isset($tree['Statement'][$id]) || empty($tree['Statement'][$id]['Enforce'])) {
290 $tree['Statement'][$id] = $this->removeKeys($stm, array('Resource', 'Action'));
291 }
292 }
293 }
294 }
295
296 // Step #2. If there are any params, let's index them and insert into the list
297 foreach($addition['Param'] as $param) {
298 $id = (isset($param['Key']) ? $param['Key'] : '__none');
299
300 if (!isset($tree['Param'][$id]) || empty($tree['Param'][$id]['Enforce'])) {
301 $tree['Param'][$id] = $this->removeKeys($param, array('Key'));
302 }
303 }
304 }
305
306 /**
307 * Remove unnecessary keys from array
308 *
309 * @param array $arr
310 * @param array $keys
311 *
312 * @return array
313 *
314 * @access private
315 */
316 private function removeKeys($arr, $keys) {
317 foreach($keys as $key) {
318 if (isset($arr[$key])) {
319 unset($arr[$key]);
320 }
321 }
322
323 return $arr;
324 }
325
326 }