Advanced Access Manager - Version 5.7.2

Version Description

  • Fixed bug with Posts & Terms feature for WP version under 4.8
  • Fixed bug were Access Policy can't be attached to any principal on the Policy edit screen
  • Fixed bug with Access URI options were not merged for users with multiple roles
  • Fixed bug with Access URI options were not exported
  • Fixed but with Post PUBLISH option due to the fact that Gutenberg is using RESTful API
  • Extended Access & Security Policy to support Posts & Terms options
  • Added /validate-jwt RESTful API endpoint to validate JWT
  • Added ability to extract JWT token from GET queries or POST payload
  • Added custom capability aam_view_help_btn to hide HELP icon on AAM UI
  • Significantly improved capability mapping mechanism and access control based on caps
  • Added URI Access support to Access & Security Policy
  • Added Post, Term, PostType support to Access & Security Policy
Download this release

Release Info

Developer vasyltech
Plugin Icon 128x128 Advanced Access Manager
Version 5.7.2
Comparing to
See all releases

Code changes from version 5.7.1 to 5.7.2

Application/Api/Rest/Resource/Post.php CHANGED
@@ -48,7 +48,11 @@ class AAM_Api_Rest_Resource_Post {
48
  case 'POST':
49
  case 'PUT':
50
  case 'PATCH':
51
- $result = $this->authorizeUpdate($post);
 
 
 
 
52
  break;
53
 
54
  case 'DELETE':
@@ -93,6 +97,20 @@ class AAM_Api_Rest_Resource_Post {
93
  return $this->processPipeline($steps, $post, $request);
94
  }
95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  /**
97
  *
98
  * @param AAM_Core_Object_Post $post
@@ -310,6 +328,33 @@ class AAM_Api_Rest_Resource_Post {
310
  return $result;
311
  }
312
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
  /**
314
  * Check EDIT & EDIT_BY_OTHERS options
315
  *
48
  case 'POST':
49
  case 'PUT':
50
  case 'PATCH':
51
+ if ($request['status'] === 'publish') {
52
+ $result = $this->authorizePublish($post);
53
+ } else {
54
+ $result = $this->authorizeUpdate($post);
55
+ }
56
  break;
57
 
58
  case 'DELETE':
97
  return $this->processPipeline($steps, $post, $request);
98
  }
99
 
100
+ /**
101
+ *
102
+ * @param AAM_Core_Object_Post $post
103
+ * @return type
104
+ */
105
+ protected function authorizePUblish(AAM_Core_Object_Post $post) {
106
+ $steps = array(
107
+ // Step #1. Check if publish action is alloed
108
+ array($this, 'checkPublish'),
109
+ );
110
+
111
+ return $this->processPipeline($steps, $post);
112
+ }
113
+
114
  /**
115
  *
116
  * @param AAM_Core_Object_Post $post
328
  return $result;
329
  }
330
 
331
+ /**
332
+ * Check PUBLISH & PUBLISH_BY_OTHERS options
333
+ *
334
+ * @param AAM_Core_Object_Post $post
335
+ *
336
+ * @return void
337
+ *
338
+ * @access protected
339
+ */
340
+ protected function checkPublish(AAM_Core_Object_Post $post) {
341
+ $result = null;
342
+
343
+ // Keep this compatible with older version of Publish (without Gutenberg)
344
+ if (!$post->allowed('api.publish') || !$post->allowed('backend.publish')) {
345
+ $result = new WP_Error(
346
+ 'rest_post_cannot_publish',
347
+ "User is unauthorized to publish the post. Access denied.",
348
+ array(
349
+ 'action' => 'api.publish',
350
+ 'status' => 401
351
+ )
352
+ );
353
+ }
354
+
355
+ return $result;
356
+ }
357
+
358
  /**
359
  * Check EDIT & EDIT_BY_OTHERS options
360
  *
Application/Backend/Feature/Main/Capability.php CHANGED
@@ -54,7 +54,8 @@ class AAM_Backend_Feature_Main_Capability extends AAM_Backend_Feature_Abstract {
54
  'aam_manage_404_redirect', 'aam_manage_ip_check', 'aam_manage_admin_toolbar',
55
  'aam_manage_default', 'aam_manage_visitors', 'aam_manage_roles', 'aam_manage_users',
56
  'aam_edit_roles', 'aam_delete_roles', 'aam_toggle_users', 'aam_switch_users',
57
- 'aam_manage_configpress', 'aam_manage_api_routes', 'aam_manage_uri', 'aam_manage_policy'
 
58
  )
59
  );
60
 
@@ -153,7 +154,7 @@ class AAM_Backend_Feature_Main_Capability extends AAM_Backend_Feature_Abstract {
153
 
154
  $toggle = ($subject->hasCapability($cap) ? 'checked' : 'unchecked');
155
 
156
- if (AAM::api()->isAllowed("Capability:{$cap}", 'AAM:toggle') === false) {
157
  $toggle = 'no-' . $toggle;
158
  }
159
 
@@ -191,7 +192,7 @@ class AAM_Backend_Feature_Main_Capability extends AAM_Backend_Feature_Abstract {
191
  }
192
 
193
  // Access & Security policy has higher priority
194
- if (AAM::api()->isAllowed("Capability:{$cap}", 'AAM:update') === false) {
195
  $allowed = false;
196
  }
197
 
@@ -212,7 +213,7 @@ class AAM_Backend_Feature_Main_Capability extends AAM_Backend_Feature_Abstract {
212
  }
213
 
214
  // Access & Security policy has higher priority
215
- if (AAM::api()->isAllowed("Capability:{$cap}", 'AAM:delete') === false) {
216
  $allowed = false;
217
  }
218
 
@@ -250,10 +251,25 @@ class AAM_Backend_Feature_Main_Capability extends AAM_Backend_Feature_Abstract {
250
  */
251
  protected function retrieveAllCaps() {
252
  $response = array();
253
- $caps = AAM_Core_API::getAllCapabilities();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
 
255
  foreach (array_keys($caps) as $cap) {
256
- if (AAM::api()->isAllowed("Capability:{$cap}", 'AAM:list') !== false) {
257
  $response[] = array(
258
  $cap,
259
  $this->getGroup($cap),
54
  'aam_manage_404_redirect', 'aam_manage_ip_check', 'aam_manage_admin_toolbar',
55
  'aam_manage_default', 'aam_manage_visitors', 'aam_manage_roles', 'aam_manage_users',
56
  'aam_edit_roles', 'aam_delete_roles', 'aam_toggle_users', 'aam_switch_users',
57
+ 'aam_manage_configpress', 'aam_manage_api_routes', 'aam_manage_uri', 'aam_manage_policy',
58
+ 'aam_view_help_btn'
59
  )
60
  );
61
 
154
 
155
  $toggle = ($subject->hasCapability($cap) ? 'checked' : 'unchecked');
156
 
157
+ if (AAM::api()->isAllowed("Capability:{$cap}:AAM:toggle") === false) {
158
  $toggle = 'no-' . $toggle;
159
  }
160
 
192
  }
193
 
194
  // Access & Security policy has higher priority
195
+ if (AAM::api()->isAllowed("Capability:{$cap}:AAM:update") === false) {
196
  $allowed = false;
197
  }
198
 
213
  }
214
 
215
  // Access & Security policy has higher priority
216
+ if (AAM::api()->isAllowed("Capability:{$cap}:AAM:delete") === false) {
217
  $allowed = false;
218
  }
219
 
251
  */
252
  protected function retrieveAllCaps() {
253
  $response = array();
254
+
255
+ // Load also capabilities defined in policy
256
+ $stms = AAM_Core_Policy_Manager::getInstance()->find(
257
+ "/^Capability:/i", AAM_Backend_Subject::getInstance()->get()
258
+ );
259
+
260
+ $policyCaps = array();
261
+
262
+ foreach($stms as $key => $stm) {
263
+ $chunks = explode(':', $key);
264
+ if (count($chunks) === 2) {
265
+ $policyCaps[$chunks[1]] = ($stm['Effect'] === 'allow' ? 1 : 0);
266
+ }
267
+ }
268
+
269
+ $caps = array_merge($policyCaps, AAM_Core_API::getAllCapabilities());
270
 
271
  foreach (array_keys($caps) as $cap) {
272
+ if (AAM::api()->isAllowed("Capability:{$cap}:AAM:list") !== false) {
273
  $response[] = array(
274
  $cap,
275
  $this->getGroup($cap),
Application/Backend/Feature/Main/Menu.php CHANGED
@@ -53,6 +53,7 @@ class AAM_Backend_Feature_Main_Menu extends AAM_Backend_Feature_Abstract {
53
 
54
  //let's create menu list with submenus
55
  if (!empty($menu)) {
 
56
  foreach ($menu as $item) {
57
  if (preg_match('/^separator/', $item[2])) {
58
  continue; //skip separator
@@ -63,15 +64,18 @@ class AAM_Backend_Feature_Main_Menu extends AAM_Backend_Feature_Abstract {
63
  $allowed = AAM_Backend_Subject::getInstance()->hasCapability($item[1]);
64
 
65
  if ($allowed || count($submenu) > 0) {
66
- $response[] = array(
67
  //add menu- prefix to define that this is the top level menu
68
  //WordPress by default gives the same menu id to the first
69
  //submenu
70
  'id' => 'menu-' . $item[2],
71
  'name' => $this->filterMenuName($item[0]),
72
  'submenu' => $submenu,
73
- 'capability' => $item[1]
 
74
  );
 
 
75
  }
76
  }
77
  }
@@ -111,6 +115,7 @@ class AAM_Backend_Feature_Main_Menu extends AAM_Backend_Feature_Abstract {
111
  */
112
  protected function getSubmenu($menu) {
113
  $submenu = json_decode(base64_decode(AAM_Core_Request::post('submenu')), 1);
 
114
 
115
  $response = array();
116
  $subject = AAM_Backend_Subject::getInstance();
@@ -119,11 +124,15 @@ class AAM_Backend_Feature_Main_Menu extends AAM_Backend_Feature_Abstract {
119
  if (array_key_exists($menu, $submenu) && is_array($submenu[$menu])) {
120
  foreach ($submenu[$menu] as $item) {
121
  if ($subject->hasCapability($item[1]) || $isDefault) {
122
- $response[] = array(
123
- 'id' => $this->normalizeItem($item[2]),
 
124
  'name' => $this->filterMenuName($item[0]),
125
- 'capability' => $item[1]
 
126
  );
 
 
127
  }
128
  }
129
  }
@@ -151,16 +160,15 @@ class AAM_Backend_Feature_Main_Menu extends AAM_Backend_Feature_Abstract {
151
 
152
  /**
153
  *
154
- * @param type $object
155
  * @param type $subs
156
  * @return boolean
157
  */
158
- protected function hasSubmenuChecked($object, $subs) {
159
  $has = false;
160
 
161
  if (!empty($subs)) {
162
  foreach($subs as $submenu) {
163
- if ($object->has($submenu['id'])) {
164
  $has = true;
165
  break;
166
  }
53
 
54
  //let's create menu list with submenus
55
  if (!empty($menu)) {
56
+ $object = AAM_Backend_Subject::getInstance()->getObject('menu');
57
  foreach ($menu as $item) {
58
  if (preg_match('/^separator/', $item[2])) {
59
  continue; //skip separator
64
  $allowed = AAM_Backend_Subject::getInstance()->hasCapability($item[1]);
65
 
66
  if ($allowed || count($submenu) > 0) {
67
+ $menuItem = array(
68
  //add menu- prefix to define that this is the top level menu
69
  //WordPress by default gives the same menu id to the first
70
  //submenu
71
  'id' => 'menu-' . $item[2],
72
  'name' => $this->filterMenuName($item[0]),
73
  'submenu' => $submenu,
74
+ 'capability' => $item[1],
75
+ 'crc32' => crc32('menu-' . $item[2]),
76
  );
77
+ $menuItem['checked'] = $object->has($menuItem['id']) || $object->has($menuItem['crc32']);
78
+ $response[] = $menuItem;
79
  }
80
  }
81
  }
115
  */
116
  protected function getSubmenu($menu) {
117
  $submenu = json_decode(base64_decode(AAM_Core_Request::post('submenu')), 1);
118
+ $object = AAM_Backend_Subject::getInstance()->getObject('menu');
119
 
120
  $response = array();
121
  $subject = AAM_Backend_Subject::getInstance();
124
  if (array_key_exists($menu, $submenu) && is_array($submenu[$menu])) {
125
  foreach ($submenu[$menu] as $item) {
126
  if ($subject->hasCapability($item[1]) || $isDefault) {
127
+ $id = $this->normalizeItem($item[2]);
128
+ $menuItem = array(
129
+ 'id' => $id,
130
  'name' => $this->filterMenuName($item[0]),
131
+ 'capability' => $item[1],
132
+ 'crc32' => crc32($id)
133
  );
134
+ $menuItem['checked'] = $object->has($menuItem['id']) || $object->has($menuItem['crc32']);
135
+ $response[] = $menuItem;
136
  }
137
  }
138
  }
160
 
161
  /**
162
  *
 
163
  * @param type $subs
164
  * @return boolean
165
  */
166
+ protected function hasSubmenuChecked($subs) {
167
  $has = false;
168
 
169
  if (!empty($subs)) {
170
  foreach($subs as $submenu) {
171
+ if ($submenu['checked']) {
172
  $has = true;
173
  break;
174
  }
Application/Backend/Feature/Main/Policy.php CHANGED
@@ -31,18 +31,14 @@ class AAM_Backend_Feature_Main_Policy extends AAM_Backend_Feature_Abstract {
31
  * @access public
32
  */
33
  public function save() {
34
- if (defined('AAM_PLUS_PACKAGE')) {
35
- $subject = AAM_Backend_Subject::getInstance();
36
- $id = AAM_Core_Request::post('id');
37
- $effect = AAM_Core_Request::post('effect');
38
 
39
- //clear cache
40
- AAM_Core_API::clearCache();
41
 
42
- $result = $subject->save($id, $effect, 'policy');
43
- } else {
44
- $result = false;
45
- }
46
 
47
  return wp_json_encode(array(
48
  'status' => ($result ? 'success' : 'failure')
31
  * @access public
32
  */
33
  public function save() {
34
+ $subject = AAM_Backend_Subject::getInstance();
35
+ $id = AAM_Core_Request::post('id');
36
+ $effect = AAM_Core_Request::post('effect');
 
37
 
38
+ //clear cache
39
+ AAM_Core_API::clearCache();
40
 
41
+ $result = $subject->save($id, $effect, 'policy');
 
 
 
42
 
43
  return wp_json_encode(array(
44
  'status' => ($result ? 'success' : 'failure')
Application/Backend/Feature/Main/Post.php CHANGED
@@ -167,16 +167,7 @@ class AAM_Backend_Feature_Main_Post extends AAM_Backend_Feature_Abstract {
167
  'term',
168
  $record->name,
169
  'manage,edit',
170
- rtrim(get_term_parents_list(
171
- $record->term_id,
172
- $record->taxonomy,
173
- array(
174
- 'link' => false,
175
- 'format' => 'name',
176
- 'separator' => '/',
177
- 'inclusive' => false
178
- )
179
- ), '/'),
180
  apply_filters(
181
  'aam-term-override-status',
182
  false,
@@ -190,6 +181,51 @@ class AAM_Backend_Feature_Main_Post extends AAM_Backend_Feature_Abstract {
190
  return $response;
191
  }
192
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  /**
194
  *
195
  * @return type
167
  'term',
168
  $record->name,
169
  'manage,edit',
170
+ rtrim($this->getParentTermList($record), '/'),
 
 
 
 
 
 
 
 
 
171
  apply_filters(
172
  'aam-term-override-status',
173
  false,
181
  return $response;
182
  }
183
 
184
+ /**
185
+ *
186
+ * @global type $wp_version
187
+ * @param type $term
188
+ * @return type
189
+ * @todo Remove when min WP version will be 4.8
190
+ */
191
+ protected function getParentTermList($term) {
192
+ global $wp_version;
193
+
194
+ $list = '';
195
+ $args = array(
196
+ 'link' => false,
197
+ 'format' => 'name',
198
+ 'separator' => '/',
199
+ 'inclusive' => false
200
+ );
201
+
202
+ if (version_compare($wp_version, '4.8.0') === -1) {
203
+ $term = get_term($term->term_id, $term->taxonomy);
204
+
205
+ foreach (array('link', 'inclusive') as $bool) {
206
+ $args[$bool] = wp_validate_boolean($args[$bool]);
207
+ }
208
+
209
+ $parents = get_ancestors($term->term_id, $term->taxonomy, 'taxonomy');
210
+
211
+ foreach (array_reverse($parents) as $term_id) {
212
+ $parent = get_term($term_id, $term->taxonomy);
213
+
214
+ if ($args['link']) {
215
+ $url = esc_url(get_term_link($parent->term_id, $term->taxonomy));
216
+ $list .= sprintf('<a href="%s">%s</a>', $url, $parent->name);
217
+ } else {
218
+ $list .= $parent->name;
219
+ }
220
+ $list .= $args['separator'];
221
+ }
222
+ } else {
223
+ $list = get_term_parents_list($term->term_id, $term->taxonomy, $args);
224
+ }
225
+
226
+ return $list;
227
+ }
228
+
229
  /**
230
  *
231
  * @return type
Application/Backend/Manager.php CHANGED
@@ -290,12 +290,16 @@ EOT;
290
  AAM_Core_API::clearCache(new AAM_Core_Subject_User($id));
291
 
292
  //check if role has expiration data set
293
- $role = (is_array($user->roles) ? $user->roles[0] : '');
294
- $expire = AAM_Core_API::getOption("aam-role-{$role}-expiration", '');
295
-
296
- if ($expire) {
297
- update_user_option($id, "aam-original-roles", $old->roles);
298
- update_user_option($id, "aam-role-expires", strtotime($expire));
 
 
 
 
299
  }
300
  }
301
  }
@@ -740,7 +744,7 @@ EOT;
740
  public function printJavascript() {
741
  if (AAM::isAAM()) {
742
  wp_enqueue_script('aam-vendor', AAM_MEDIA . '/js/vendor.js');
743
- wp_enqueue_script('aam-main', AAM_MEDIA . '/js/aam-5.7.js');
744
 
745
  //add plugin localization
746
  $this->printLocalization('aam-main');
@@ -883,7 +887,7 @@ EOT;
883
  check_ajax_referer('aam_ajax');
884
 
885
  // flush any output buffer
886
- ob_clean();
887
 
888
  if (AAM::getUser()->hasCapability('aam_manager')) {
889
  $response = AAM_Backend_View::getInstance()->renderContent(
290
  AAM_Core_API::clearCache(new AAM_Core_Subject_User($id));
291
 
292
  //check if role has expiration data set
293
+ // TODO: This supports only the first role and NOT the multi-roles
294
+ if (is_array($user->roles)) {
295
+ $roles = array_values($user->roles);
296
+ $role = array_shift($roles);
297
+ $expire = AAM_Core_API::getOption("aam-role-{$role}-expiration", '');
298
+
299
+ if ($expire) {
300
+ update_user_option($id, "aam-original-roles", $old->roles);
301
+ update_user_option($id, "aam-role-expires", strtotime($expire));
302
+ }
303
  }
304
  }
305
  }
744
  public function printJavascript() {
745
  if (AAM::isAAM()) {
746
  wp_enqueue_script('aam-vendor', AAM_MEDIA . '/js/vendor.js');
747
+ wp_enqueue_script('aam-main', AAM_MEDIA . '/js/aam-5.7.2.js');
748
 
749
  //add plugin localization
750
  $this->printLocalization('aam-main');
887
  check_ajax_referer('aam_ajax');
888
 
889
  // flush any output buffer
890
+ @ob_clean();
891
 
892
  if (AAM::getUser()->hasCapability('aam_manager')) {
893
  $response = AAM_Backend_View::getInstance()->renderContent(
Application/Backend/Subject.php CHANGED
@@ -70,7 +70,11 @@ class AAM_Backend_Subject {
70
  $classname = 'AAM_Core_Subject_' . ucfirst($type);
71
 
72
  if (class_exists($classname)) {
73
- $this->setSubject(new $classname(stripslashes($id)));
 
 
 
 
74
  }
75
  }
76
 
70
  $classname = 'AAM_Core_Subject_' . ucfirst($type);
71
 
72
  if (class_exists($classname)) {
73
+ $subject = new $classname(stripslashes($id));
74
+ // Load access policy
75
+ $subject->getObject('policy');
76
+
77
+ $this->setSubject($subject);
78
  }
79
  }
80
 
Application/Backend/phtml/index.phtml CHANGED
@@ -62,10 +62,12 @@
62
  <span>Extensions</span>
63
  </a>
64
  <?php } ?>
65
- <a href="https://aamplugin.com/help" title="Help" target="_blank">
66
- <i class="icon-help-circled"></i>
67
- <span>Help</span>
68
- </a>
 
 
69
  </div>
70
  </div>
71
  </div>
62
  <span>Extensions</span>
63
  </a>
64
  <?php } ?>
65
+ <?php if (current_user_can('aam_view_help_btn')) { ?>
66
+ <a href="https://aamplugin.com/help" title="Help" target="_blank">
67
+ <i class="icon-help-circled"></i>
68
+ <span>Help</span>
69
+ </a>
70
+ <?php } ?>
71
  </div>
72
  </div>
73
  </div>
Application/Backend/phtml/main/menu.phtml CHANGED
@@ -31,9 +31,9 @@
31
  <a role="button" data-toggle="collapse" data-parent="#admin-menu" href="#menu-<?php echo $i; ?>" aria-controls="menu-<?php echo $i; ?>" <?php if (!$first) { echo 'aria-expanded="true"'; } ?>>
32
  <?php echo $menu['name']; ?> <small class="aam-menu-capability"><?php echo $menu['capability']; ?></small>
33
  </a>
34
- <?php if ($object->has($menu['id'])) { ?>
35
  <i class="aam-panel-title-icon icon-eye-off text-danger"></i>
36
- <?php } elseif ($this->hasSubmenuChecked($object, $menu['submenu'])) { ?>
37
  <i class="aam-panel-title-icon icon-attention-circled text-warning"></i>
38
  <?php } ?>
39
  </h4>
@@ -44,14 +44,14 @@
44
  <?php if ($menu['id'] != 'menu-index.php') { ?>
45
  <div class="row aam-inner-tab">
46
  <div class="col-xs-12 text-center">
47
- <small class="aam-menu-capability"><?php echo __('Menu ID:', AAM_KEY); ?> <b><?php echo crc32($menu['id']); ?></b></small>
48
  </div>
49
  </div>
50
  <hr class="aam-divider" />
51
  <?php } ?>
52
  <?php if (!empty($menu['submenu'])) { ?>
53
  <div class="row aam-inner-tab">
54
- <?php echo ($object->has($menu['id']) ? '<div class="aam-lock"></div>' : ''); ?>
55
  <?php foreach ($menu['submenu'] as $j => $submenu) { ?>
56
  <?php if ($submenu['id'] == 'index.php') { ?>
57
  <div class="col-xs-12 col-md-6 aam-submenu-item">
@@ -64,9 +64,9 @@
64
  <label for="menu-item-<?php echo $i . $j; ?>">
65
  <u><?php echo $submenu['name']; ?></u>
66
  <small class="aam-menu-capability"><?php echo __('Cap:', AAM_KEY), ' <b>', $submenu['capability']; ?></b></small>
67
- <small class="aam-menu-capability"><?php echo __('ID:', AAM_KEY), ' <b>', crc32($submenu['id']); ?></b></small>
68
  </label>
69
- <input type="checkbox" class="aam-checkbox-danger" id="menu-item-<?php echo $i . $j; ?>" data-menu-id="<?php echo $submenu['id']; ?>"<?php echo ($object->has($submenu['id']) ? ' checked="checked"' : ''); ?> />
70
  <label for="menu-item-<?php echo $i . $j; ?>" data-toggle="tooltip" title="<?php echo ($object->has($submenu['id']) ? __('Uncheck to allow', AAM_KEY) : __('Check to restrict', AAM_KEY)); ?>"></label>
71
  </div>
72
  <?php } ?>
@@ -79,7 +79,7 @@
79
  <?php if ($menu['id'] != 'menu-index.php') { ?>
80
  <div class="row<?php echo (!empty($menu['submenu']) ? ' aam-margin-top-xs' : ''); ?>">
81
  <div class="col-xs-10 col-md-6 col-xs-offset-1 col-md-offset-3">
82
- <?php if ($object->has($menu['id'])) { ?>
83
  <a href="#" class="btn btn-primary btn-sm btn-block aam-restrict-menu" data-menu-id="<?php echo $menu['id']; ?>" data-target="#menu-<?php echo $i; ?>">
84
  <i class="icon-eye"></i> <?php echo __('Show Menu', AAM_KEY); ?>
85
  </a>
31
  <a role="button" data-toggle="collapse" data-parent="#admin-menu" href="#menu-<?php echo $i; ?>" aria-controls="menu-<?php echo $i; ?>" <?php if (!$first) { echo 'aria-expanded="true"'; } ?>>
32
  <?php echo $menu['name']; ?> <small class="aam-menu-capability"><?php echo $menu['capability']; ?></small>
33
  </a>
34
+ <?php if ($menu['checked']) { ?>
35
  <i class="aam-panel-title-icon icon-eye-off text-danger"></i>
36
+ <?php } elseif ($this->hasSubmenuChecked($menu['submenu'])) { ?>
37
  <i class="aam-panel-title-icon icon-attention-circled text-warning"></i>
38
  <?php } ?>
39
  </h4>
44
  <?php if ($menu['id'] != 'menu-index.php') { ?>
45
  <div class="row aam-inner-tab">
46
  <div class="col-xs-12 text-center">
47
+ <small class="aam-menu-capability"><?php echo __('Menu ID:', AAM_KEY); ?> <b><?php echo $menu['crc32']; ?></b></small>
48
  </div>
49
  </div>
50
  <hr class="aam-divider" />
51
  <?php } ?>
52
  <?php if (!empty($menu['submenu'])) { ?>
53
  <div class="row aam-inner-tab">
54
+ <?php echo ($menu['checked'] ? '<div class="aam-lock"></div>' : ''); ?>
55
  <?php foreach ($menu['submenu'] as $j => $submenu) { ?>
56
  <?php if ($submenu['id'] == 'index.php') { ?>
57
  <div class="col-xs-12 col-md-6 aam-submenu-item">
64
  <label for="menu-item-<?php echo $i . $j; ?>">
65
  <u><?php echo $submenu['name']; ?></u>
66
  <small class="aam-menu-capability"><?php echo __('Cap:', AAM_KEY), ' <b>', $submenu['capability']; ?></b></small>
67
+ <small class="aam-menu-capability"><?php echo __('ID:', AAM_KEY), ' <b>', $submenu['crc32']; ?></b></small>
68
  </label>
69
+ <input type="checkbox" class="aam-checkbox-danger" id="menu-item-<?php echo $i . $j; ?>" data-menu-id="<?php echo $submenu['id']; ?>"<?php echo ($submenu['checked'] ? ' checked="checked"' : ''); ?> />
70
  <label for="menu-item-<?php echo $i . $j; ?>" data-toggle="tooltip" title="<?php echo ($object->has($submenu['id']) ? __('Uncheck to allow', AAM_KEY) : __('Check to restrict', AAM_KEY)); ?>"></label>
71
  </div>
72
  <?php } ?>
79
  <?php if ($menu['id'] != 'menu-index.php') { ?>
80
  <div class="row<?php echo (!empty($menu['submenu']) ? ' aam-margin-top-xs' : ''); ?>">
81
  <div class="col-xs-10 col-md-6 col-xs-offset-1 col-md-offset-3">
82
+ <?php if ($menu['checked']) { ?>
83
  <a href="#" class="btn btn-primary btn-sm btn-block aam-restrict-menu" data-menu-id="<?php echo $menu['id']; ?>" data-target="#menu-<?php echo $i; ?>">
84
  <i class="icon-eye"></i> <?php echo __('Show Menu', AAM_KEY); ?>
85
  </a>
Application/Backend/phtml/main/metabox.phtml CHANGED
@@ -62,7 +62,7 @@
62
  <div class="col-xs-12 col-md-6 aam-submenu-item">
63
  <label for="metabox-<?php echo $screen; ?>-<?php echo $metabox['id']; ?>">
64
  <u><?php echo $metabox['title']; ?></u>
65
- <small class="aam-metabox-details"><?php echo __('ID:', AAM_KEY); ?> <b><?php echo crc32($screen . $metabox['id']); ?></b></small>
66
  </label>
67
  <input type="checkbox" class="aam-checkbox-danger" id="metabox-<?php echo $screen; ?>-<?php echo $metabox['id']; ?>" data-metabox="<?php echo $screen; ?>|<?php echo $metabox['id']; ?>"<?php echo ($object->has($screen, $metabox['id']) ? ' checked="checked"' : ''); ?> />
68
  <label for="metabox-<?php echo $screen; ?>-<?php echo $metabox['id']; ?>" data-toggle="tooltip" title="<?php echo ($object->has($screen, $metabox['id']) ? __('Uncheck to show', AAM_KEY) : __('Check to hide', AAM_KEY)); ?>"></label>
62
  <div class="col-xs-12 col-md-6 aam-submenu-item">
63
  <label for="metabox-<?php echo $screen; ?>-<?php echo $metabox['id']; ?>">
64
  <u><?php echo $metabox['title']; ?></u>
65
+ <small class="aam-metabox-details"><?php echo __('ID:', AAM_KEY); ?> <b><?php echo crc32($screen . '|' . $metabox['id']); ?></b></small>
66
  </label>
67
  <input type="checkbox" class="aam-checkbox-danger" id="metabox-<?php echo $screen; ?>-<?php echo $metabox['id']; ?>" data-metabox="<?php echo $screen; ?>|<?php echo $metabox['id']; ?>"<?php echo ($object->has($screen, $metabox['id']) ? ' checked="checked"' : ''); ?> />
68
  <label for="metabox-<?php echo $screen; ?>-<?php echo $metabox['id']; ?>" data-toggle="tooltip" title="<?php echo ($object->has($screen, $metabox['id']) ? __('Uncheck to show', AAM_KEY) : __('Check to hide', AAM_KEY)); ?>"></label>
Application/Core/Compatibility.php CHANGED
@@ -35,6 +35,58 @@ class AAM_Core_Compatibility {
35
  return $key;
36
  }
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  /**
39
  * Convert all-style AAM settings to standard ConfigPress style settings
40
  *
35
  return $key;
36
  }
37
 
38
+ /**
39
+ * Converting metabox options from 2 dimensional to 1
40
+ *
41
+ * @param array $metaboxes
42
+ *
43
+ * @return array
44
+ * @todo Remove in 2021
45
+ */
46
+ public static function convertMetaboxes($metaboxes) {
47
+ $response = array();
48
+
49
+ if (is_array($metaboxes)) {
50
+ foreach($metaboxes as $key => $value) {
51
+ if (is_array($value)) {
52
+ foreach($value as $id => $grand) {
53
+ $response["{$key}|{$id}"] = $grand;
54
+ }
55
+ } else {
56
+ $response[$key] = $value;
57
+ }
58
+ }
59
+ }
60
+
61
+ return $response;
62
+ }
63
+
64
+ /**
65
+ *
66
+ * @param type $list
67
+ * @return type
68
+ * @todo Remove in 2021
69
+ */
70
+ public static function convertRoute($list) {
71
+ $response = array();
72
+
73
+ if (is_array($list)) {
74
+ foreach($list as $type => $routes) {
75
+ if (is_array($routes)) {
76
+ foreach($routes as $route => $methods) {
77
+ foreach($methods as $method => $grand) {
78
+ $response[strtolower("{$type}|{$route}|{$method}")] = $grand;
79
+ }
80
+ }
81
+ } else {
82
+ $response[$type] = $routes;
83
+ }
84
+ }
85
+ }
86
+
87
+ return $response;
88
+ }
89
+
90
  /**
91
  * Convert all-style AAM settings to standard ConfigPress style settings
92
  *
Application/Core/Exporter.php CHANGED
@@ -120,6 +120,8 @@ class AAM_Core_Exporter {
120
  $this->pushData('options', '/^aam_menu_role/');
121
  } elseif ($feature === 'toolbar') {
122
  $this->pushData('options', '/^aam_toolbar_role/');
 
 
123
  } elseif ($feature === 'route') {
124
  $this->pushData('options', '/^aam_route_role/');
125
  } elseif ($feature === 'metabox') {
@@ -148,6 +150,8 @@ class AAM_Core_Exporter {
148
  $this->pushData('usermeta', '/^' . $wpdb->prefix . 'aam_menu/');
149
  } elseif ($feature === 'toolbar') {
150
  $this->pushData('usermeta', '/^' . $wpdb->prefix . 'aam_toolbar/');
 
 
151
  } elseif ($feature === 'route') {
152
  $this->pushData('usermeta', '/^' . $wpdb->prefix . 'aam_route/');
153
  } elseif ($feature === 'metabox') {
@@ -182,6 +186,8 @@ class AAM_Core_Exporter {
182
  $this->pushData('options', '/^aam_visitor_redirect/');
183
  } elseif ($feature === 'route') {
184
  $this->pushData('options', '/^aam_visitor_route/');
 
 
185
  }
186
  }
187
  }
@@ -200,6 +206,8 @@ class AAM_Core_Exporter {
200
  $this->pushData('options', '/^aam_route_default/');
201
  } elseif ($feature === 'toolbar') {
202
  $this->pushData('options', '/^aam_toolbar_default/');
 
 
203
  } elseif ($feature === 'post') {
204
  $this->pushData('options', '/^aam_type_[\w_\-]_default/');
205
  $this->pushData('options', '/^aam_term_[\d]+\|.+_default/');
120
  $this->pushData('options', '/^aam_menu_role/');
121
  } elseif ($feature === 'toolbar') {
122
  $this->pushData('options', '/^aam_toolbar_role/');
123
+ } elseif ($feature === 'uri') {
124
+ $this->pushData('options', '/^aam_uri_role/');
125
  } elseif ($feature === 'route') {
126
  $this->pushData('options', '/^aam_route_role/');
127
  } elseif ($feature === 'metabox') {
150
  $this->pushData('usermeta', '/^' . $wpdb->prefix . 'aam_menu/');
151
  } elseif ($feature === 'toolbar') {
152
  $this->pushData('usermeta', '/^' . $wpdb->prefix . 'aam_toolbar/');
153
+ } elseif ($feature === 'uri') {
154
+ $this->pushData('usermeta', '/^' . $wpdb->prefix . 'aam_uri/');
155
  } elseif ($feature === 'route') {
156
  $this->pushData('usermeta', '/^' . $wpdb->prefix . 'aam_route/');
157
  } elseif ($feature === 'metabox') {
186
  $this->pushData('options', '/^aam_visitor_redirect/');
187
  } elseif ($feature === 'route') {
188
  $this->pushData('options', '/^aam_visitor_route/');
189
+ } elseif ($feature === 'uri') {
190
+ $this->pushData('options', '/^aam_visitor_uri/');
191
  }
192
  }
193
  }
206
  $this->pushData('options', '/^aam_route_default/');
207
  } elseif ($feature === 'toolbar') {
208
  $this->pushData('options', '/^aam_toolbar_default/');
209
+ } elseif ($feature === 'uri') {
210
+ $this->pushData('options', '/^aam_uri_default/');
211
  } elseif ($feature === 'post') {
212
  $this->pushData('options', '/^aam_type_[\w_\-]_default/');
213
  $this->pushData('options', '/^aam_term_[\d]+\|.+_default/');
Application/Core/Gateway.php CHANGED
@@ -104,7 +104,20 @@ final class AAM_Core_Gateway {
104
  * exact match found
105
  */
106
  public function isAllowed($resource, $action = null) {
107
- return AAM::api()->getUser()->getObject('policy')->isAllowed($resource, $action);
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  }
109
 
110
  /**
104
  * exact match found
105
  */
106
  public function isAllowed($resource, $action = null) {
107
+ $policy = AAM::api()->getUser()->getObject('policy');
108
+
109
+ return $policy->isAllowed($resource, $action);
110
+ }
111
+
112
+ /**
113
+ * Get policy manager
114
+ *
115
+ * @return AAM_Core_Policy_Manager
116
+ *
117
+ * @access public
118
+ */
119
+ public function getPolicyManager() {
120
+ return AAM_Core_Policy_Manager::getInstance();
121
  }
122
 
123
  /**
Application/Core/JwtAuth.php CHANGED
@@ -48,6 +48,7 @@ class AAM_Core_JwtAuth {
48
  * @access public
49
  */
50
  public function registerAPI() {
 
51
  register_rest_route('aam/v1', '/authenticate', array(
52
  'methods' => 'POST',
53
  'callback' => array($this, 'authenticate'),
@@ -62,6 +63,18 @@ class AAM_Core_JwtAuth {
62
  )
63
  ),
64
  ));
 
 
 
 
 
 
 
 
 
 
 
 
65
  }
66
 
67
  /**
@@ -110,6 +123,38 @@ class AAM_Core_JwtAuth {
110
  return apply_filters('aam-jwt-response-filter', $response);
111
  }
112
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  /**
114
  * Generate JWT token
115
  *
@@ -123,7 +168,9 @@ class AAM_Core_JwtAuth {
123
  public function generateJWT($userId, $container = 'header') {
124
  $key = AAM_Core_Config::get('authentication.jwt.secret', SECURE_AUTH_KEY);
125
  $expire = AAM_Core_Config::get('authentication.jwt.expires', 86400);
126
- $container = AAM_Core_Config::get('authentication.jwt.container', $container);
 
 
127
  $alg = AAM_Core_Config::get('authentication.jwt.algorithm', 'HS256');
128
 
129
  if ($key) {
@@ -135,7 +182,7 @@ class AAM_Core_JwtAuth {
135
 
136
  $token = Firebase\JWT\JWT::encode($claims, $key, $alg);
137
 
138
- if ($container === 'cookie') {
139
  setcookie(
140
  'aam-jwt',
141
  $token,
@@ -188,26 +235,38 @@ class AAM_Core_JwtAuth {
188
  * @return type
189
  */
190
  protected function extractJwt() {
191
- $container = AAM_Core_Config::get('authentication.jwt.container', 'header');
 
 
192
 
193
- if ($container === 'header') {
194
- $jwt = apply_filters(
195
- 'aam-jwt-authentication-header-filter',
196
- AAM_Core_Request::server('HTTP_AUTHENTICATION')
197
- );
198
- } elseif ($container === 'cookie') {
199
- $jwt = apply_filters(
200
- 'aam-jwt-authentication-cookie-filter',
201
- AAM_Core_Request::cookie('aam-jwt')
202
- );
203
- } else {
204
- AAM_Core_Console::add(
205
- sprint_f(
206
- __('Invalid value %s for property %s', AAM_KEY),
207
- $container,
208
- 'authentication.jwt.container'
209
- )
210
- );
 
 
 
 
 
 
 
 
 
 
211
  }
212
 
213
  return (!empty($jwt) ? preg_replace('/^Bearer /', '', $jwt) : null);
48
  * @access public
49
  */
50
  public function registerAPI() {
51
+ // Authenticate user
52
  register_rest_route('aam/v1', '/authenticate', array(
53
  'methods' => 'POST',
54
  'callback' => array($this, 'authenticate'),
63
  )
64
  ),
65
  ));
66
+
67
+ // Validate JWT token
68
+ register_rest_route('aam/v1', '/validate-jwt', array(
69
+ 'methods' => 'POST',
70
+ 'callback' => array($this, 'validateJWT'),
71
+ 'args' => array(
72
+ 'jwt' => array(
73
+ 'description' => __('JWT token.', AAM_KEY),
74
+ 'type' => 'string',
75
+ )
76
+ ),
77
+ ));
78
  }
79
 
80
  /**
123
  return apply_filters('aam-jwt-response-filter', $response);
124
  }
125
 
126
+ /**
127
+ *
128
+ * @param WP_REST_Request $request
129
+ */
130
+ public function validateJWT(WP_REST_Request $request) {
131
+ $jwt = $request->get_param('jwt');
132
+ $key = AAM_Core_Config::get('authentication.jwt.secret', SECURE_AUTH_KEY);
133
+
134
+ $response = new WP_REST_Response(array(
135
+ 'status' => 'invalid'
136
+ ), 400);
137
+
138
+ if (!empty($jwt)) {
139
+ try {
140
+ $claims = Firebase\JWT\JWT::decode(
141
+ $jwt, $key, array_keys(Firebase\JWT\JWT::$supported_algs)
142
+ );
143
+
144
+ if (isset($claims->userId)) {
145
+ $response->status = 200;
146
+ $response->data = array (
147
+ 'status' => 'valid'
148
+ );
149
+ }
150
+ } catch (Exception $ex) {
151
+ // Do nothing
152
+ }
153
+ }
154
+
155
+ return $response;
156
+ }
157
+
158
  /**
159
  * Generate JWT token
160
  *
168
  public function generateJWT($userId, $container = 'header') {
169
  $key = AAM_Core_Config::get('authentication.jwt.secret', SECURE_AUTH_KEY);
170
  $expire = AAM_Core_Config::get('authentication.jwt.expires', 86400);
171
+ $container = explode(
172
+ ',', AAM_Core_Config::get('authentication.jwt.container', $container)
173
+ );
174
  $alg = AAM_Core_Config::get('authentication.jwt.algorithm', 'HS256');
175
 
176
  if ($key) {
182
 
183
  $token = Firebase\JWT\JWT::encode($claims, $key, $alg);
184
 
185
+ if (in_array('cookie', $container, true)) {
186
  setcookie(
187
  'aam-jwt',
188
  $token,
235
  * @return type
236
  */
237
  protected function extractJwt() {
238
+ $container = explode(',', AAM_Core_Config::get(
239
+ 'authentication.jwt.container', 'header'
240
+ ));
241
 
242
+ $jwt = null;
243
+
244
+ foreach($container as $method) {
245
+ switch(strtolower(trim($method))) {
246
+ case 'header':
247
+ $jwt = AAM_Core_Request::server('HTTP_AUTHENTICATION');
248
+ break;
249
+
250
+ case 'cookie':
251
+ $jwt = AAM_Core_Request::cookie('aam-jwt');
252
+ break;
253
+
254
+ case 'query':
255
+ $jwt = AAM_Core_Request::get('aam-jwt');
256
+ break;
257
+
258
+ case 'post':
259
+ $jwt = AAM_Core_Request::post('aam-jwt');
260
+ break;
261
+
262
+ default:
263
+ $jwt = apply_filters('aam-get-jwt-filter', null, $method);
264
+ break;
265
+ }
266
+
267
+ if (!is_null($jwt)) {
268
+ break;
269
+ }
270
  }
271
 
272
  return (!empty($jwt) ? preg_replace('/^Bearer /', '', $jwt) : null);
Application/Core/Object/Capability.php CHANGED
@@ -27,17 +27,32 @@ class AAM_Core_Object_Capability extends AAM_Core_Object {
27
  public function __construct(AAM_Core_Subject $subject) {
28
  parent::__construct($subject);
29
 
30
- $this->setOption($this->getSubject()->getCapabilities());
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
  //check if capabilities are overwritten but only for user subject
33
  if (is_a($this->getSubject(), 'AAM_Core_Subject_User')) {
34
- $caps = get_user_option(
35
  AAM_Core_Subject_User::AAM_CAPKEY, $this->getSubject()->getId()
36
  );
37
- if (!empty($caps)) {
 
38
  $this->setOverwritten(true);
39
  }
40
  }
 
 
41
  }
42
 
43
  /**
27
  public function __construct(AAM_Core_Subject $subject) {
28
  parent::__construct($subject);
29
 
30
+ $caps = $this->getSubject()->getCapabilities();
31
+
32
+ // Load Capabilities from the policy
33
+ $stms = AAM_Core_Policy_Manager::getInstance()->find(
34
+ "/^Capability:/i", $subject
35
+ );
36
+
37
+ foreach($stms as $key => $stm) {
38
+ $chunks = explode(':', $key);
39
+ if (count($chunks) === 2) {
40
+ $caps[$chunks[1]] = ($stm['Effect'] === 'allow' ? 1 : 0);
41
+ }
42
+ }
43
 
44
  //check if capabilities are overwritten but only for user subject
45
  if (is_a($this->getSubject(), 'AAM_Core_Subject_User')) {
46
+ $userCaps = get_user_option(
47
  AAM_Core_Subject_User::AAM_CAPKEY, $this->getSubject()->getId()
48
  );
49
+ if (!empty($userCaps)) {
50
+ $caps = array_merge($caps, $userCaps);
51
  $this->setOverwritten(true);
52
  }
53
  }
54
+
55
+ $this->setOption($caps);
56
  }
57
 
58
  /**
Application/Core/Object/Menu.php CHANGED
@@ -29,10 +29,25 @@ class AAM_Core_Object_Menu extends AAM_Core_Object {
29
 
30
  $option = $this->getSubject()->readOption('menu');
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  if (empty($option)) {
33
  $option = $this->getSubject()->inheritFromParent('menu');
34
- } else {
35
- $this->setOverwritten(true);
36
  }
37
 
38
  $this->setOption($option);
@@ -104,6 +119,27 @@ class AAM_Core_Object_Menu extends AAM_Core_Object {
104
 
105
  return $menu;
106
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
 
108
  /**
109
  * Filter submenu
@@ -190,20 +226,14 @@ class AAM_Core_Object_Menu extends AAM_Core_Object {
190
  $options = $this->getOption();
191
  $parent = $this->getParentMenu($decoded);
192
 
193
- // Policy API
194
- $api = AAM::api();
195
- $crc = crc32($decoded);
196
- $bcrc = crc32('menu-' . $decoded);
197
- $pcrc = crc32('menu-' . $parent);
198
-
199
  // Step #1. Check if menu is directly restricted
200
- $direct = !empty($options[$decoded]) || ($api->isAllowed("BackendMenu:{$crc}") === false);
201
 
202
  // Step #2. Check if whole branch is restricted
203
- $branch = ($both && (!empty($options['menu-' . $decoded]) || ($api->isAllowed("BackendMenu:{$bcrc}") === false)));
204
 
205
  // Step #3. Check if dynamic submenu is restricted because of whole branch
206
- $indirect = ($parent && (!empty($options['menu-' . $parent]) || ($api->isAllowed("BackendMenu:{$pcrc}") === false)));
207
 
208
  return $direct || $branch || $indirect;
209
  }
29
 
30
  $option = $this->getSubject()->readOption('menu');
31
 
32
+ if (!empty($option)) {
33
+ $this->setOverwritten(true);
34
+ }
35
+
36
+ // Load settings from Access & Security Policy
37
+ if (empty($option)) {
38
+ $stms = AAM_Core_Policy_Manager::getInstance()->find(
39
+ "/^BackendMenu:/i", $subject
40
+ );
41
+
42
+ foreach($stms as $key => $stm) {
43
+ $chunks = explode(':', $key);
44
+ $option[$chunks[1]] = ($stm['Effect'] === 'deny' ? 1 : 0);
45
+ }
46
+ }
47
+
48
+ // Finally try to load from parent
49
  if (empty($option)) {
50
  $option = $this->getSubject()->inheritFromParent('menu');
 
 
51
  }
52
 
53
  $this->setOption($option);
119
 
120
  return $menu;
121
  }
122
+
123
+ /**
124
+ * Update single option item
125
+ *
126
+ * @param string $item
127
+ * @param mixed $value
128
+ *
129
+ * @return boolean Always true
130
+ *
131
+ * @access public
132
+ */
133
+ public function updateOptionItem($item, $value) {
134
+ $option = $this->getOption();
135
+
136
+ $option[$item] = $value;
137
+ $option[crc32($item)] = $value;
138
+
139
+ $this->setOption($option);
140
+
141
+ return true;
142
+ }
143
 
144
  /**
145
  * Filter submenu
226
  $options = $this->getOption();
227
  $parent = $this->getParentMenu($decoded);
228
 
 
 
 
 
 
 
229
  // Step #1. Check if menu is directly restricted
230
+ $direct = !empty($options[$decoded]) || !empty($options[crc32($decoded)]);
231
 
232
  // Step #2. Check if whole branch is restricted
233
+ $branch = ($both && (!empty($options['menu-' . $decoded]) || !empty($options[crc32('menu-' . $decoded)])));
234
 
235
  // Step #3. Check if dynamic submenu is restricted because of whole branch
236
+ $indirect = ($parent && (!empty($options['menu-' . $parent]) || !empty($options[crc32('menu-' . $parent)])));
237
 
238
  return $direct || $branch || $indirect;
239
  }
Application/Core/Object/Metabox.php CHANGED
@@ -27,12 +27,28 @@ class AAM_Core_Object_Metabox extends AAM_Core_Object {
27
  public function __construct(AAM_Core_Subject $subject) {
28
  parent::__construct($subject);
29
 
30
- $option = $this->getSubject()->readOption('metabox');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
  if (empty($option)) {
33
  $option = $this->getSubject()->inheritFromParent('metabox');
34
- } else {
35
- $this->setOverwritten(true);
36
  }
37
 
38
  $this->setOption($option);
@@ -143,10 +159,10 @@ class AAM_Core_Object_Metabox extends AAM_Core_Object {
143
  * @inheritdoc
144
  */
145
  public function save($metabox, $granted) {
146
- $param = explode('|', $metabox);
147
  $option = $this->getOption();
148
 
149
- $option[$param[0]][$param[1]] = $granted;
 
150
 
151
  return $this->getSubject()->updateOption($option, 'metabox');
152
  }
@@ -166,12 +182,9 @@ class AAM_Core_Object_Metabox extends AAM_Core_Object {
166
  */
167
  public function has($screen, $metabox) {
168
  $options = $this->getOption();
 
169
 
170
- $area = ($screen === 'widgets' ? 'Widget' : 'Metabox');
171
- $uid = crc32($screen . $metabox);
172
- $isAllowed = AAM::api()->isAllowed("{$area}:{$uid}");
173
-
174
- return !empty($options[$screen][$metabox]) || ($isAllowed === false);
175
  }
176
 
177
  /**
27
  public function __construct(AAM_Core_Subject $subject) {
28
  parent::__construct($subject);
29
 
30
+ $option = AAM_Core_Compatibility::convertMetaboxes(
31
+ $this->getSubject()->readOption('metabox')
32
+ );
33
+
34
+ if (!empty($option)) {
35
+ $this->setOverwritten(true);
36
+ }
37
+
38
+ // Load settings from Access & Security Policy
39
+ if (empty($option)) {
40
+ $stms = AAM_Core_Policy_Manager::getInstance()->find(
41
+ "/^(Metabox|Widget):/i", $subject
42
+ );
43
+
44
+ foreach($stms as $key => $stm) {
45
+ $chunks = explode(':', $key);
46
+ $option[$chunks[1]] = ($stm['Effect'] === 'deny' ? 1 : 0);
47
+ }
48
+ }
49
 
50
  if (empty($option)) {
51
  $option = $this->getSubject()->inheritFromParent('metabox');
 
 
52
  }
53
 
54
  $this->setOption($option);
159
  * @inheritdoc
160
  */
161
  public function save($metabox, $granted) {
 
162
  $option = $this->getOption();
163
 
164
+ $option[$metabox] = $granted;
165
+ $option[crc32($metabox)] = $granted;
166
 
167
  return $this->getSubject()->updateOption($option, 'metabox');
168
  }
182
  */
183
  public function has($screen, $metabox) {
184
  $options = $this->getOption();
185
+ $mid = "{$screen}|{$metabox}";
186
 
187
+ return !empty($options[$mid]) || !empty($options[crc32($mid)]);
 
 
 
 
188
  }
189
 
190
  /**
Application/Core/Object/Policy.php CHANGED
@@ -16,10 +16,16 @@
16
  class AAM_Core_Object_Policy extends AAM_Core_Object {
17
 
18
  /**
19
- *
20
- * @var type
 
 
 
 
 
 
21
  */
22
- protected $resources = array();
23
 
24
  /**
25
  * Constructor
@@ -33,12 +39,21 @@ class AAM_Core_Object_Policy extends AAM_Core_Object {
33
  public function __construct(AAM_Core_Subject $subject) {
34
  parent::__construct($subject);
35
 
36
- $parent = $this->getSubject()->inheritFromParent('policy');
 
 
 
 
 
 
 
 
 
37
  if(empty($parent)) {
38
  $parent = array();
39
  }
40
 
41
- $option = $this->getSubject()->readOption('policy');
42
  if (empty($option)) {
43
  $option = array();
44
  } else {
@@ -50,36 +65,41 @@ class AAM_Core_Object_Policy extends AAM_Core_Object {
50
  }
51
 
52
  $this->setOption($parent);
 
 
 
 
 
53
  }
54
 
55
  /**
56
  *
57
  */
58
- public function load() {
59
  $resources = array();
60
-
61
- foreach($this->loadStatements() as $statement) {
62
  if (isset($statement['Resource']) && $this->applicable($statement)) {
63
  $this->evaluateStatement($statement, $resources);
64
  }
65
  }
66
 
67
- $this->resources = $resources;
68
  }
69
 
70
  /**
71
  *
72
  * @return type
73
  */
74
- protected function loadStatements() {
75
  $cache = AAM::api()->getUser()->getObject('cache');
76
- $statements = $cache->get('policyStatements', 0, null);
77
-
78
  // Step #1. Extract all statements
79
  if (is_null($statements)) {
80
  $statements = array();
81
 
82
- foreach($this->getOption() as $id => $effect) {
83
  if ($effect) {
84
  $policy = get_post($id);
85
 
@@ -93,7 +113,7 @@ class AAM_Core_Object_Policy extends AAM_Core_Object {
93
  }
94
  }
95
  }
96
- $cache->add('policyStatements', 0, $statements);
97
  }
98
 
99
  return $statements;
@@ -597,10 +617,11 @@ class AAM_Core_Object_Policy extends AAM_Core_Object {
597
  public function isAllowed($resource, $action = null) {
598
  $allowed = null;
599
 
600
- $id = strtolower($resource . (!empty($action) ? ":{$action}" : ''));
 
601
 
602
- if (isset($this->resources[$id])) {
603
- $allowed = ($this->resources[$id]['Effect'] === 'allow');
604
  }
605
 
606
  return $allowed;
@@ -631,4 +652,31 @@ class AAM_Core_Object_Policy extends AAM_Core_Object {
631
  return AAM::api()->mergeSettings($external, $this->getOption(), 'policy');
632
  }
633
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
634
  }
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
  * Constructor
39
  public function __construct(AAM_Core_Subject $subject) {
40
  parent::__construct($subject);
41
 
42
+ $this->initialize(); // Read options from the database table first
43
+ }
44
+
45
+ /**
46
+ *
47
+ */
48
+ public function initialize() {
49
+ $subject = $this->getSubject();
50
+ $parent = $subject->inheritFromParent('policy');
51
+
52
  if(empty($parent)) {
53
  $parent = array();
54
  }
55
 
56
+ $option = $subject->readOption('policy');
57
  if (empty($option)) {
58
  $option = array();
59
  } else {
65
  }
66
 
67
  $this->setOption($parent);
68
+
69
+ // Load statements for policies
70
+ $subjectId = $subject->getUID();
71
+ $subjectId .= ($subject->getId() ? ".{$subject->getId()}" : '');
72
+ $this->load($subjectId, $option);
73
  }
74
 
75
  /**
76
  *
77
  */
78
+ public function load($subjectId, $policies) {
79
  $resources = array();
80
+
81
+ foreach($this->loadStatements($subjectId, $policies) as $statement) {
82
  if (isset($statement['Resource']) && $this->applicable($statement)) {
83
  $this->evaluateStatement($statement, $resources);
84
  }
85
  }
86
 
87
+ self::$resources[$subjectId] = $resources;
88
  }
89
 
90
  /**
91
  *
92
  * @return type
93
  */
94
+ protected function loadStatements($subjectId, $policies) {
95
  $cache = AAM::api()->getUser()->getObject('cache');
96
+ $statements = $cache->get('policy', $subjectId, null);
97
+
98
  // Step #1. Extract all statements
99
  if (is_null($statements)) {
100
  $statements = array();
101
 
102
+ foreach($policies as $id => $effect) {
103
  if ($effect) {
104
  $policy = get_post($id);
105
 
113
  }
114
  }
115
  }
116
+ $cache->add('policy', $subjectId, $statements);
117
  }
118
 
119
  return $statements;
617
  public function isAllowed($resource, $action = null) {
618
  $allowed = null;
619
 
620
+ $id = strtolower($resource . (!empty($action) ? ":{$action}" : ''));
621
+ $res = $this->getResources();
622
 
623
+ if (isset($res[$id])) {
624
+ $allowed = ($res[$id]['Effect'] === 'allow');
625
  }
626
 
627
  return $allowed;
652
  return AAM::api()->mergeSettings($external, $this->getOption(), 'policy');
653
  }
654
 
655
+ /**
656
+ *
657
+ * @return type
658
+ */
659
+ public function getResources(AAM_Core_Subject $subject = null) {
660
+ $response = array();
661
+
662
+ if (is_null($subject)) {
663
+ if (!isset(self::$resources['__combined'])) {
664
+ foreach(self::$resources as $resources) {
665
+ $response = array_merge($resources, $response);
666
+ }
667
+ self::$resources['__combined'] = $response;
668
+ } else {
669
+ $response = self::$resources['__combined'];
670
+ }
671
+ } else {
672
+ $subjectId = $subject->getUID();
673
+ $subjectId .= ($subject->getId() ? ".{$subject->getId()}" : '');
674
+
675
+ if (isset(self::$resources[$subjectId])) {
676
+ $response = self::$resources[$subjectId];
677
+ }
678
+ }
679
+
680
+ return $response;
681
+ }
682
  }
Application/Core/Object/Post.php CHANGED
@@ -40,7 +40,7 @@ class AAM_Core_Object_Post extends AAM_Core_Object {
40
  //make sure that we are dealing with WP_Post object
41
  if (is_object($post)) {
42
  $this->setPost($post);
43
- } elseif (intval($post)) {
44
  $this->setPost(get_post($post));
45
  }
46
 
@@ -93,6 +93,23 @@ class AAM_Core_Object_Post extends AAM_Core_Object {
93
  $option = get_post_meta($post->ID, $this->getOptionName(), true);
94
  $this->setOverwritten(!empty($option));
95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  // Inherit from terms or default settings - AAM Plus Package
97
  if (empty($option)) {
98
  $option = apply_filters('aam-post-access-filter', $option, $this);
40
  //make sure that we are dealing with WP_Post object
41
  if (is_object($post)) {
42
  $this->setPost($post);
43
+ } elseif (is_numeric($post)) {
44
  $this->setPost(get_post($post));
45
  }
46
 
93
  $option = get_post_meta($post->ID, $this->getOptionName(), true);
94
  $this->setOverwritten(!empty($option));
95
 
96
+ // Read settings from access policy
97
+ if (empty($option)) {
98
+ $stms = AAM_Core_Policy_Manager::getInstance()->find(
99
+ "/^post:{$post->post_type}:({$post->post_name}|{$post->ID}):/",
100
+ $subject
101
+ );
102
+
103
+ foreach($stms as $key => $stm) {
104
+ // TODO: Prepare better conversion from policy Action to AAM
105
+ // post & term action. For example listToOthers -> list_others
106
+ $chunks = explode(':', $key);
107
+ $option["frontend.{$chunks[3]}"] = $stm['Effect'] === 'deny';
108
+ $option["backend.{$chunks[3]}"] = $stm['Effect'] === 'deny';
109
+ $option["api.{$chunks[3]}"] = $stm['Effect'] === 'deny';
110
+ }
111
+ }
112
+
113
  // Inherit from terms or default settings - AAM Plus Package
114
  if (empty($option)) {
115
  $option = apply_filters('aam-post-access-filter', $option, $this);
Application/Core/Object/Route.php CHANGED
@@ -27,12 +27,30 @@ class AAM_Core_Object_Route extends AAM_Core_Object {
27
  public function __construct(AAM_Core_Subject $subject) {
28
  parent::__construct($subject);
29
 
30
- $option = $this->getSubject()->readOption('route');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
  if (empty($option)) {
33
  $option = $this->getSubject()->inheritFromParent('route');
34
- } else {
35
- $this->setOverwritten(true);
36
  }
37
 
38
  $this->setOption($option);
@@ -51,8 +69,9 @@ class AAM_Core_Object_Route extends AAM_Core_Object {
51
  */
52
  public function has($type, $route, $method = 'POST') {
53
  $options = $this->getOption();
 
54
 
55
- return !empty($options[$type][$route][$method]);
56
  }
57
 
58
  /**
@@ -64,7 +83,10 @@ class AAM_Core_Object_Route extends AAM_Core_Object {
64
  */
65
  public function save($type, $route, $method, $value) {
66
  $option = $this->getOption();
67
- $option[$type][$route][$method] = $value;
 
 
 
68
  $this->setOption($option);
69
 
70
  return $this->getSubject()->updateOption($this->getOption(), 'route');
27
  public function __construct(AAM_Core_Subject $subject) {
28
  parent::__construct($subject);
29
 
30
+ $option = AAM_Core_Compatibility::convertRoute(
31
+ $this->getSubject()->readOption('route')
32
+ );
33
+
34
+ if (!empty($option)) {
35
+ $this->setOverwritten(true);
36
+ }
37
+
38
+ // Load settings from Access & Security Policy
39
+ if (empty($option)) {
40
+ $stms = AAM_Core_Policy_Manager::getInstance()->find(
41
+ "/^Route:/i", $subject
42
+ );
43
+
44
+ foreach($stms as $key => $stm) {
45
+ $chunks = explode(':', $key);
46
+ $id = "{$chunks[1]}|{$chunks[2]}|{$chunks[3]}";
47
+
48
+ $option[$id] = ($stm['Effect'] === 'deny' ? 1 : 0);
49
+ }
50
+ }
51
 
52
  if (empty($option)) {
53
  $option = $this->getSubject()->inheritFromParent('route');
 
 
54
  }
55
 
56
  $this->setOption($option);
69
  */
70
  public function has($type, $route, $method = 'POST') {
71
  $options = $this->getOption();
72
+ $id = strtolower("{$type}|{$route}|{$method}");
73
 
74
+ return !empty($options[$id]);
75
  }
76
 
77
  /**
83
  */
84
  public function save($type, $route, $method, $value) {
85
  $option = $this->getOption();
86
+
87
+ $id = strtolower("{$type}|{$route}|{$method}");
88
+ $option[$id] = $value;
89
+
90
  $this->setOption($option);
91
 
92
  return $this->getSubject()->updateOption($this->getOption(), 'route');
Application/Core/Object/Toolbar.php CHANGED
@@ -29,10 +29,24 @@ class AAM_Core_Object_Toolbar extends AAM_Core_Object {
29
 
30
  $option = $this->getSubject()->readOption('toolbar');
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  if (empty($option)) {
33
  $option = $this->getSubject()->inheritFromParent('toolbar');
34
- } else {
35
- $this->setOverwritten(true);
36
  }
37
 
38
  $this->setOption($option);
@@ -52,14 +66,11 @@ class AAM_Core_Object_Toolbar extends AAM_Core_Object {
52
  public function has($item, $both = false) {
53
  $options = $this->getOption();
54
 
55
- // Policy API
56
- $api = AAM::api();
57
-
58
  // Step #1. Check if toolbar item is directly restricted
59
- $direct = !empty($options[$item]) || ($api->isAllowed("Toolbar:{$item}") === false);
60
 
61
  // Step #2. Check if whole branch is restricted
62
- $branch = ($both && (!empty($options['toolbar-' . $item]) || ($api->isAllowed("Toolbar:toolbar-{$item}") === false)));
63
 
64
  return $direct || $branch;
65
  }
29
 
30
  $option = $this->getSubject()->readOption('toolbar');
31
 
32
+ if (!empty($option)) {
33
+ $this->setOverwritten(true);
34
+ }
35
+
36
+ // Load settings from Access & Security Policy
37
+ if (empty($option)) {
38
+ $stms = AAM_Core_Policy_Manager::getInstance()->find(
39
+ "/^Toolbar:/i", $subject
40
+ );
41
+
42
+ foreach($stms as $key => $stm) {
43
+ $chunks = explode(':', $key);
44
+ $option[$chunks[1]] = ($stm['Effect'] === 'deny' ? 1 : 0);
45
+ }
46
+ }
47
+
48
  if (empty($option)) {
49
  $option = $this->getSubject()->inheritFromParent('toolbar');
 
 
50
  }
51
 
52
  $this->setOption($option);
66
  public function has($item, $both = false) {
67
  $options = $this->getOption();
68
 
 
 
 
69
  // Step #1. Check if toolbar item is directly restricted
70
+ $direct = !empty($options[$item]);
71
 
72
  // Step #2. Check if whole branch is restricted
73
+ $branch = ($both && !empty($options['toolbar-' . $item]));
74
 
75
  return $direct || $branch;
76
  }
Application/Core/Object/Uri.php CHANGED
@@ -29,10 +29,67 @@ class AAM_Core_Object_Uri extends AAM_Core_Object {
29
 
30
  $option = $this->getSubject()->readOption('uri');
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  if (empty($option)) {
33
  $option = $this->getSubject()->inheritFromParent('uri');
34
- } else {
35
- $this->setOverwritten(true);
36
  }
37
 
38
  $this->setOption($option);
@@ -115,5 +172,14 @@ class AAM_Core_Object_Uri extends AAM_Core_Object {
115
  public function reset() {
116
  return $this->getSubject()->deleteOption('uri');
117
  }
 
 
 
 
 
 
 
 
 
118
 
119
  }
29
 
30
  $option = $this->getSubject()->readOption('uri');
31
 
32
+ if (!empty($option)) {
33
+ $this->setOverwritten(true);
34
+ }
35
+
36
+ if (empty($option)) {
37
+ $stms = AAM_Core_Policy_Manager::getInstance()->find(
38
+ "/^URI:/i", $subject
39
+ );
40
+
41
+ foreach($stms as $key => $stm) {
42
+ $chunks = explode(':', $key);
43
+ $effect = ($stm['Effect'] === 'deny' ? 1 : 0);
44
+ $type = $stm['Effect'];
45
+ $destination = null;
46
+
47
+ if ($effect === 1 && !empty($stm['Metadata']['Redirect'])) {
48
+ $type = strtolower($stm['Metadata']['Redirect']['Type']);
49
+
50
+ switch($type) {
51
+ case 'message':
52
+ $destination = $stm['Metadata']['Redirect']['Message'];
53
+ break;
54
+
55
+ case 'page':
56
+ if (isset($stm['Metadata']['Redirect']['Id'])) {
57
+ $destination = intval($stm['Metadata']['Redirect']['Id']);
58
+ } elseif (isset($stm['Metadata']['Redirect']['Slug'])) {
59
+ $page = $post = get_page_by_path(
60
+ $stm['Metadata']['Redirect']['Slug'], OBJECT
61
+ );
62
+ $destination = (is_a($page, 'WP_Post') ? $page->ID : 0);
63
+ }
64
+ break;
65
+
66
+ case 'url':
67
+ $destination = filter_var(
68
+ $stm['Metadata']['Redirect']['URL'],
69
+ FILTER_VALIDATE_URL
70
+ );
71
+ if (empty($destination)) {
72
+ $type = 'message';
73
+ $destination = "Invalid URL: [{$stm['Metadata']['Redirect']['URL']}]";
74
+ }
75
+ break;
76
+
77
+ case 'callback':
78
+ $destination = $stm['Metadata']['Redirect']['Callback'];
79
+ break;
80
+ }
81
+ }
82
+
83
+ $option[crc32($chunks[1] . $type. $destination)] = array(
84
+ 'uri' => $chunks[1],
85
+ 'type' => $type,
86
+ 'action' => $destination
87
+ );
88
+ }
89
+ }
90
+
91
  if (empty($option)) {
92
  $option = $this->getSubject()->inheritFromParent('uri');
 
 
93
  }
94
 
95
  $this->setOption($option);
172
  public function reset() {
173
  return $this->getSubject()->deleteOption('uri');
174
  }
175
+
176
+ /**
177
+ *
178
+ * @param type $external
179
+ * @return type
180
+ */
181
+ public function mergeOption($external) {
182
+ return array_merge($external, $this->getOption());
183
+ }
184
 
185
  }
Application/Core/Object/Visibility.php CHANGED
@@ -45,7 +45,8 @@ class AAM_Core_Object_Visibility extends AAM_Core_Object {
45
  if ($option === false) { //if false, then the cache is empty but exists
46
  $option = array();
47
  } elseif (empty($option)) {
48
- $query = "SELECT pm.`post_id`, pm.`meta_value`, p.`post_type` FROM {$wpdb->postmeta} AS pm ";
 
49
  $query .= "LEFT JOIN {$wpdb->posts} AS p ON (pm.`post_id` = p.ID) ";
50
  $query .= "WHERE pm.`meta_key` = %s";
51
 
@@ -56,6 +57,36 @@ class AAM_Core_Object_Visibility extends AAM_Core_Object {
56
  }
57
  }
58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  do_action('aam-visibility-initialize-action', $this);
60
 
61
  // inherit settings from parent
45
  if ($option === false) { //if false, then the cache is empty but exists
46
  $option = array();
47
  } elseif (empty($option)) {
48
+ $query = "SELECT pm.`post_id`, pm.`meta_value`, p.`post_type` ";
49
+ $query .= "FROM {$wpdb->postmeta} AS pm ";
50
  $query .= "LEFT JOIN {$wpdb->posts} AS p ON (pm.`post_id` = p.ID) ";
51
  $query .= "WHERE pm.`meta_key` = %s";
52
 
57
  }
58
  }
59
 
60
+ // Read all the settings from the Access & Security Policies
61
+ $area = AAM_Core_Api_Area::get();
62
+ $stms = AAM_Core_Policy_Manager::getInstance()->find(
63
+ "/^post:(.*):(list|listtoothers)$/",
64
+ $subject
65
+ );
66
+
67
+ foreach($stms as $key => $stm) {
68
+ $chunks = explode(':', $key);
69
+
70
+ $action = ($chunks[3] === 'listtoothers' ? 'list_others' : 'list');
71
+
72
+ if (is_numeric($chunks[2])) {
73
+ $postId = $chunks[2];
74
+ } else {
75
+ $post = get_page_by_path(
76
+ $chunks[2], OBJECT, $chunks[1]
77
+ );
78
+ $postId = (is_a($post, 'WP_Post') ? $post->ID : 0);
79
+ }
80
+
81
+ $this->pushOptions(
82
+ 'post',
83
+ "{$postId}|{$chunks[1]}",
84
+ array(
85
+ "{$area}.{$action}" => ($stm['Effect'] === 'deny' ? 1 : 0)
86
+ )
87
+ );
88
+ }
89
+
90
  do_action('aam-visibility-initialize-action', $this);
91
 
92
  // inherit settings from parent
Application/Core/Policy/Manager.php ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ * Single instance of itself
21
+ *
22
+ * @var AAM_Core_Policy_Manager
23
+ *
24
+ * @access private
25
+ * @static
26
+ */
27
+ private static $_instance = null;
28
+
29
+ /**
30
+ * Policy core object
31
+ *
32
+ * @var AAM_Core_Object_Policy
33
+ *
34
+ * @access protected
35
+ */
36
+ protected $policyObject;
37
+
38
+ /**
39
+ * Constructor
40
+ *
41
+ * @access protected
42
+ *
43
+ * @return void
44
+ */
45
+ protected function __construct() {
46
+ $this->policyObject = AAM::getUser()->getObject('policy');
47
+ }
48
+
49
+ /**
50
+ * Find all the matching policies
51
+ *
52
+ * @param string $s RegEx
53
+ * @param AAM_Core_Subject $subject Subject to search for
54
+ *
55
+ * @return array
56
+ *
57
+ * @access public
58
+ */
59
+ public function find($s, AAM_Core_Subject $subject = null) {
60
+ $statements = array();
61
+
62
+ // Get list of policies
63
+ if (is_null($subject)) {
64
+ $policies = $this->policyObject;
65
+ } else {
66
+ $policies = $subject->getObject('policy');
67
+ }
68
+
69
+ foreach($policies->getResources($subject) as $key => $stm) {
70
+ if (preg_match($s, $key)) {
71
+ $statements[strtolower($key)] = $stm;
72
+ }
73
+ }
74
+
75
+ return $statements;
76
+ }
77
+
78
+ /**
79
+ * Get single instance of itself
80
+ *
81
+ * @return AAM_Core_Policy_Manager
82
+ *
83
+ * @access public
84
+ * @static
85
+ */
86
+ public static function getInstance() {
87
+ if (is_null(self::$_instance)) {
88
+ self::$_instance = new self();
89
+ }
90
+
91
+ return self::$_instance;
92
+ }
93
+
94
+ /**
95
+ * Load the policy manager
96
+ *
97
+ * @return void
98
+ *
99
+ * @access public
100
+ * @static
101
+ */
102
+ public static function bootstrap() {
103
+ self::getInstance();
104
+ }
105
+ }
Application/Core/Subject.php CHANGED
@@ -252,7 +252,6 @@ abstract class AAM_Core_Subject {
252
  }
253
  } else {
254
  $object = $this->_objects[$type][$id];
255
- $object->initialize();
256
  }
257
 
258
  return $object;
252
  }
253
  } else {
254
  $object = $this->_objects[$type][$id];
 
255
  }
256
 
257
  return $object;
Application/Core/Subject/Role.php CHANGED
@@ -127,6 +127,28 @@ class AAM_Core_Subject_Role extends AAM_Core_Subject {
127
  public function getCapabilities() {
128
  return $this->getSubject()->capabilities;
129
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
 
131
  /**
132
  *
127
  public function getCapabilities() {
128
  return $this->getSubject()->capabilities;
129
  }
130
+
131
+ /**
132
+ * Check if subject has capability
133
+ *
134
+ * @param string $cap
135
+ *
136
+ * @return boolean
137
+ *
138
+ * @access public
139
+ */
140
+ public function hasCapability($cap) {
141
+ $has = $this->getSubject()->has_cap($cap);
142
+
143
+ // Override by policy if is set
144
+ $stm = AAM::api()->getPolicyManager()->find("/^Capability:{$cap}$/i", $this);
145
+ if (!empty($stm)) {
146
+ $val = end($stm);
147
+ $has = ($val['Effect'] === 'allow' ? 1 : 0);
148
+ }
149
+
150
+ return $has;
151
+ }
152
 
153
  /**
154
  *
Application/Core/Subject/User.php CHANGED
@@ -170,26 +170,47 @@ class AAM_Core_Subject_User extends AAM_Core_Subject {
170
  * @access protected
171
  */
172
  protected function retrieveSubject() {
173
- $subject = new WP_User($this->getId());
174
-
175
- //retrieve aam capabilities if are not retrieved yet
176
- $caps = get_user_option(self::AAM_CAPKEY, $this->getId());
177
- if (is_array($caps)) {
178
- $caps = array_merge($subject->caps, $caps);
179
- $allcaps = array_merge($subject->allcaps, $caps);
180
-
181
- //reset the user capabilities
182
- $subject->allcaps = $allcaps;
183
- $subject->caps = $caps;
184
-
185
- if (wp_get_current_user()->ID === $subject->ID) {
186
- wp_get_current_user()->allcaps = $allcaps;
187
- wp_get_current_user()->caps = $caps;
188
- }
189
  }
190
 
191
  return $subject;
192
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
 
194
  /**
195
  * Get user capabilities
170
  * @access protected
171
  */
172
  protected function retrieveSubject() {
173
+ if ($this->getId() === get_current_user_id()) {
174
+ $subject = wp_get_current_user();
175
+ } else {
176
+ $subject = new WP_User($this->getId());
 
 
 
 
 
 
 
 
 
 
 
 
177
  }
178
 
179
  return $subject;
180
  }
181
+
182
+ /**
183
+ *
184
+ */
185
+ public function loadCapabilities() {
186
+ $subject = $this->getSubject();
187
+
188
+ // Retrieve all capabilities set in Access Policy
189
+ // Load Capabilities from the policy
190
+ $stms = AAM_Core_Policy_Manager::getInstance()->find("/^Capability:/i");
191
+
192
+ $policyCaps = array();
193
+
194
+ foreach($stms as $key => $stm) {
195
+ $chunks = explode(':', $key);
196
+ if (count($chunks) === 2) {
197
+ $policyCaps[$chunks[1]] = ($stm['Effect'] === 'allow' ? 1 : 0);
198
+ }
199
+ }
200
+
201
+ //reset the user capabilities
202
+ $subject->allcaps = array_merge($subject->allcaps, $policyCaps);
203
+ $subject->caps = array_merge($subject->caps, $policyCaps);
204
+
205
+ // Retrieve user capabilities set with AAM
206
+ $userCaps = get_user_option(self::AAM_CAPKEY, $this->getId());
207
+
208
+ if (is_array($userCaps)) {
209
+ //reset the user capabilities
210
+ $subject->allcaps = array_merge($subject->allcaps, $userCaps);
211
+ $subject->caps = array_merge($subject->caps, $userCaps);
212
+ }
213
+ }
214
 
215
  /**
216
  * Get user capabilities
Application/Extension/Repository.php CHANGED
@@ -139,14 +139,14 @@ class AAM_Extension_Repository {
139
 
140
  // determin if extension meets minimum required AAM version
141
  $list = AAM_Extension_List::get();
142
- $version = !empty($conf['requires']['aam']) && (version_compare(AAM_Core_API::version(), $conf['requires']['aam']) >= 0);
143
- $load = $status && $version;
144
 
145
- if (!$version) {
146
  if (!empty($list[$conf['id']]['title'])) { // Any custom extensions
147
  AAM_Core_Console::add(AAM_Backend_View_Helper::preparePhrase(
148
  sprintf(
149
- __('[%s] was not loaded. Update extension to the latest version.', AAM_KEY),
150
  $list[$conf['id']]['title']
151
  ),
152
  'b'
139
 
140
  // determin if extension meets minimum required AAM version
141
  $list = AAM_Extension_List::get();
142
+ $issue = !empty($conf['requires']['aam']) && (version_compare(AAM_Core_API::version(), $conf['requires']['aam']) === -1);
143
+ $load = $status && !$issue;
144
 
145
+ if ($issue) {
146
  if (!empty($list[$conf['id']]['title'])) { // Any custom extensions
147
  AAM_Core_Console::add(AAM_Backend_View_Helper::preparePhrase(
148
  sprintf(
149
+ __('[%s] was not loaded. Update AAM plugin to the latest version.', AAM_KEY),
150
  $list[$conf['id']]['title']
151
  ),
152
  'b'
Application/Shared/Manager.php CHANGED
@@ -92,7 +92,7 @@ class AAM_Shared_Manager {
92
 
93
  // Check if user has ability to perform certain task based on provided
94
  // capability and meta data
95
- add_filter('user_has_cap', array(self::$_instance, 'userHasCap'), 999, 3);
96
 
97
  // Security. Make sure that we escaping all translation strings
98
  add_filter(
@@ -273,7 +273,7 @@ class AAM_Shared_Manager {
273
  } else {
274
  $query = '';
275
  }
276
-
277
  $clauses['where'] .= apply_filters(
278
  'aam-post-where-clause-filter', $query, $wpQuery, $option
279
  );
@@ -434,61 +434,67 @@ class AAM_Shared_Manager {
434
  *
435
  * @access public
436
  */
437
- public function userHasCap($caps, $meta, $args) {
438
- $capability = (isset($args[0]) && is_string($args[0]) ? $args[0] : '');
439
- $uid = (isset($args[2]) && is_numeric($args[2]) ? $args[2] : 0);
440
-
441
- // Apply policy first
442
- $effect = AAM::api()->isAllowed("Capability:{$capability}");
443
-
444
- if ($effect !== null) {
445
- $caps = $this->updateCapabilities($caps, $meta, $effect);
446
- }
447
 
448
- switch($capability) {
449
  case 'edit_user':
450
  case 'delete_user':
451
- $caps = $this->authorizeUserUpdate($uid, $caps, $meta);
452
  break;
453
 
454
  case 'edit_post':
455
- $caps = $this->authorizePostEdit($uid, $caps, $meta);
 
456
  break;
457
 
458
  case 'delete_post':
459
- $caps = $this->authorizePostDelete($uid, $caps, $meta);
 
460
  break;
461
 
462
- case 'publish_posts':
463
- case 'publish_pages':
464
- $caps = $this->authorizePublishPost($caps, $meta);
 
 
 
 
465
  break;
466
 
467
  case 'install_plugins':
468
- $caps = $this->checkPluginsAction('install', $caps, $meta);
 
 
 
 
 
 
 
 
469
  break;
470
 
471
  case 'delete_plugins':
472
- $caps = $this->checkPluginsAction('delete', $caps, $meta);
473
  break;
474
 
475
  case 'edit_plugins':
476
- $caps = $this->checkPluginsAction('edit', $caps, $meta);
477
  break;
478
 
479
  case 'update_plugins':
480
- $caps = $this->checkPluginsAction('update', $caps, $meta);
481
  break;
482
 
483
  case 'activate_plugin':
484
  $caps = $this->checkPluginAction(
485
- (isset($args[2]) ? $args[2] : ''), 'activate', $caps, $meta
486
  );
487
  break;
488
 
489
  case 'deactivate_plugin':
490
  $caps = $this->checkPluginAction(
491
- (isset($args[2]) ? $args[2] : ''), 'deactivate', $caps, $meta
492
  );
493
  break;
494
 
@@ -503,14 +509,14 @@ class AAM_Shared_Manager {
503
  *
504
  * @param type $action
505
  * @param type $caps
506
- * @param type $meta
507
  * @return type
508
  */
509
- protected function checkPluginsAction($action, $caps, $meta) {
510
  $allow = AAM::api()->isAllowed("Plugin", "WP:{$action}");
511
 
512
  if ($allow !== null) {
513
- $caps = $this->updateCapabilities($caps, $meta);
514
  }
515
 
516
  return $caps;
@@ -521,18 +527,16 @@ class AAM_Shared_Manager {
521
  * @param type $plugin
522
  * @param type $action
523
  * @param type $caps
524
- * @param type $meta
525
  * @return type
526
  */
527
- protected function checkPluginAction($plugin, $action, $caps, $meta) {
528
  $parts = explode('/', $plugin);
529
  $slug = (!empty($parts[0]) ? $parts[0] : null);
530
 
531
- if ($slug) {
532
- $allow = AAM::api()->isAllowed("Plugin:{$slug}", "WP:{$action}");
533
- if ($allow !== null) {
534
- $caps = $this->updateCapabilities($caps, $meta, $allow);
535
- }
536
  }
537
 
538
  return $caps;
@@ -612,8 +616,8 @@ class AAM_Shared_Manager {
612
  *
613
  * @access protected
614
  */
615
- protected function authorizeUserUpdate($id, $allcaps, $metacaps) {
616
- $user = new WP_User($id);
617
 
618
  //current user max level
619
  $maxLevel = AAM_Core_API::maxLevel(AAM::getUser()->allcaps);
@@ -621,10 +625,10 @@ class AAM_Shared_Manager {
621
  $userLevel = AAM_Core_API::maxLevel($user->allcaps);
622
 
623
  if ($maxLevel < $userLevel) {
624
- $allcaps = $this->updateCapabilities($allcaps, $metacaps);
625
  }
626
 
627
- return $allcaps;
628
  }
629
 
630
  /**
@@ -638,16 +642,16 @@ class AAM_Shared_Manager {
638
  *
639
  * @access protected
640
  */
641
- protected function authorizePostEdit($id, $allcaps, $metacaps) {
642
  $object = AAM::getUser()->getObject('post', $id);
643
  $draft = $object->post_status === 'auto-draft';
644
  $area = AAM_Core_Api_Area::get();
645
 
646
- if (!$draft && !$object->allowed($area . '.edit')) {
647
- $allcaps = $this->updateCapabilities($allcaps, $metacaps);
648
  }
649
 
650
- return $allcaps;
651
  }
652
 
653
  /**
@@ -661,15 +665,15 @@ class AAM_Shared_Manager {
661
  *
662
  * @access protected
663
  */
664
- protected function authorizePostDelete($id, $allcaps, $metacaps) {
665
  $object = AAM::getUser()->getObject('post', $id);
666
  $area = AAM_Core_Api_Area::get();
667
 
668
  if (!$object->allowed($area . '.delete')) {
669
- $allcaps = $this->updateCapabilities($allcaps, $metacaps);
670
  }
671
 
672
- return $allcaps;
673
  }
674
 
675
  /**
@@ -683,42 +687,37 @@ class AAM_Shared_Manager {
683
  * @access protected
684
  * @global WP_Post $post
685
  */
686
- protected function authorizePublishPost($allcaps, $metacaps) {
687
- global $post;
688
-
689
- if (is_a($post, 'WP_Post')) {
690
- $object = AAM::getUser()->getObject('post', $post->ID);
691
- $area = AAM_Core_Api_Area::get();
692
-
693
- if (!$object->allowed($area . '.publish')) {
694
- $allcaps = $this->updateCapabilities($allcaps, $metacaps);
695
- }
696
  }
697
 
698
- return $allcaps;
699
  }
700
 
701
  /**
702
- * Restrict user capabilities
703
- *
704
- * Iterate through the list of meta capabilities and disable them in the
705
- * list of all user capabilities. Keep in mind that this disable caps only
706
- * for one time call.
707
  *
708
- * @param array $allCaps
709
- * @param array $metaCaps
710
- * @param bool $allow
711
  *
712
  * @return array
713
  *
714
  * @access protected
 
715
  */
716
- protected function updateCapabilities($allCaps, $metaCaps, $allow = false) {
717
- foreach($metaCaps as $cap) {
718
- $allCaps[$cap] = $allow;
 
 
 
719
  }
720
 
721
- return $allCaps;
722
  }
723
 
724
  /**
@@ -736,4 +735,5 @@ class AAM_Shared_Manager {
736
 
737
  return self::$_instance;
738
  }
 
739
  }
92
 
93
  // Check if user has ability to perform certain task based on provided
94
  // capability and meta data
95
+ add_filter('map_meta_cap', array(self::$_instance, 'mapMetaCaps'), 999, 4);
96
 
97
  // Security. Make sure that we escaping all translation strings
98
  add_filter(
273
  } else {
274
  $query = '';
275
  }
276
+
277
  $clauses['where'] .= apply_filters(
278
  'aam-post-where-clause-filter', $query, $wpQuery, $option
279
  );
434
  *
435
  * @access public
436
  */
437
+ public function mapMetaCaps($caps, $cap, $user_id, $args) {
438
+ global $post;
 
 
 
 
 
 
 
 
439
 
440
+ switch($cap) {
441
  case 'edit_user':
442
  case 'delete_user':
443
+ $caps = $this->authorizeUserUpdate($caps, $args[0]);
444
  break;
445
 
446
  case 'edit_post':
447
+ case 'edit_page':
448
+ $caps = $this->authorizePostEdit($caps, $args[0]);
449
  break;
450
 
451
  case 'delete_post':
452
+ case 'delete_page':
453
+ $caps = $this->authorizePostDelete($caps, $args[0]);
454
  break;
455
 
456
+ case 'read_post':
457
+ case 'read_page':
458
+ $caps = $this->authorizePostRead($caps, $args[0]);
459
+ break;
460
+
461
+ case 'publish_post':
462
+ $caps = $this->authorizePublishPost($caps, $args[0]);
463
  break;
464
 
465
  case 'install_plugins':
466
+ $caps = $this->checkPluginsAction('install', $caps, $cap);
467
+ break;
468
+
469
+ case 'publish_posts':
470
+ // There is a bug in WP core that instead of checking if user has
471
+ // ability to publish_post, it checks for edit_post
472
+ if (is_a($post, 'WP_Post')) {
473
+ $caps = $this->authorizePublishPost($caps, $post->ID);
474
+ }
475
  break;
476
 
477
  case 'delete_plugins':
478
+ $caps = $this->checkPluginsAction('delete', $caps, $cap);
479
  break;
480
 
481
  case 'edit_plugins':
482
+ $caps = $this->checkPluginsAction('edit', $caps, $cap);
483
  break;
484
 
485
  case 'update_plugins':
486
+ $caps = $this->checkPluginsAction('update', $caps, $cap);
487
  break;
488
 
489
  case 'activate_plugin':
490
  $caps = $this->checkPluginAction(
491
+ (isset($args[0]) ? $args[0] : ''), 'activate', $caps, $cap
492
  );
493
  break;
494
 
495
  case 'deactivate_plugin':
496
  $caps = $this->checkPluginAction(
497
+ (isset($args[0]) ? $args[0] : ''), 'deactivate', $caps, $cap
498
  );
499
  break;
500
 
509
  *
510
  * @param type $action
511
  * @param type $caps
512
+ * @param type $cap
513
  * @return type
514
  */
515
+ protected function checkPluginsAction($action, $caps, $cap) {
516
  $allow = AAM::api()->isAllowed("Plugin", "WP:{$action}");
517
 
518
  if ($allow !== null) {
519
+ $caps[] = $allow ? $cap : 'do_not_allow';
520
  }
521
 
522
  return $caps;
527
  * @param type $plugin
528
  * @param type $action
529
  * @param type $caps
530
+ * @param type $cap
531
  * @return type
532
  */
533
+ protected function checkPluginAction($plugin, $action, $caps, $cap) {
534
  $parts = explode('/', $plugin);
535
  $slug = (!empty($parts[0]) ? $parts[0] : null);
536
 
537
+ $allow = AAM::api()->isAllowed("Plugin:{$slug}", "WP:{$action}");
538
+ if ($allow !== null) {
539
+ $caps[] = $allow ? $cap : 'do_not_allow';
 
 
540
  }
541
 
542
  return $caps;
616
  *
617
  * @access protected
618
  */
619
+ protected function authorizeUserUpdate($caps, $userId) {
620
+ $user = new WP_User($userId);
621
 
622
  //current user max level
623
  $maxLevel = AAM_Core_API::maxLevel(AAM::getUser()->allcaps);
625
  $userLevel = AAM_Core_API::maxLevel($user->allcaps);
626
 
627
  if ($maxLevel < $userLevel) {
628
+ $caps[] = 'do_not_allow';
629
  }
630
 
631
+ return $caps;
632
  }
633
 
634
  /**
642
  *
643
  * @access protected
644
  */
645
+ protected function authorizePostEdit($caps, $id) {
646
  $object = AAM::getUser()->getObject('post', $id);
647
  $draft = $object->post_status === 'auto-draft';
648
  $area = AAM_Core_Api_Area::get();
649
 
650
+ if (!$draft && (!$object->allowed($area . '.edit') )) {
651
+ $caps[] = 'do_not_allow';
652
  }
653
 
654
+ return $caps;
655
  }
656
 
657
  /**
665
  *
666
  * @access protected
667
  */
668
+ protected function authorizePostDelete($caps, $id) {
669
  $object = AAM::getUser()->getObject('post', $id);
670
  $area = AAM_Core_Api_Area::get();
671
 
672
  if (!$object->allowed($area . '.delete')) {
673
+ $caps[] = 'do_not_allow';
674
  }
675
 
676
+ return $caps;
677
  }
678
 
679
  /**
687
  * @access protected
688
  * @global WP_Post $post
689
  */
690
+ protected function authorizePublishPost($caps, $id) {
691
+ $object = AAM::getUser()->getObject('post', $id);
692
+ $area = AAM_Core_Api_Area::get();
693
+
694
+ if (!$object->allowed($area . '.publish')) {
695
+ $caps[] = 'do_not_allow';
 
 
 
 
696
  }
697
 
698
+ return $caps;
699
  }
700
 
701
  /**
702
+ * Check if user is allowed to publish post
 
 
 
 
703
  *
704
+ * @param array $allcaps
705
+ * @param array $metacaps
 
706
  *
707
  * @return array
708
  *
709
  * @access protected
710
+ * @global WP_Post $post
711
  */
712
+ protected function authorizePostRead($caps, $id) {
713
+ $object = AAM::getUser()->getObject('post', $id);
714
+ $area = AAM_Core_Api_Area::get();
715
+
716
+ if (!$object->allowed($area . '.read')) {
717
+ $caps[] = 'do_not_allow';
718
  }
719
 
720
+ return $caps;
721
  }
722
 
723
  /**
735
 
736
  return self::$_instance;
737
  }
738
+
739
  }
aam.php CHANGED
@@ -3,7 +3,7 @@
3
  /**
4
  Plugin Name: Advanced Access Manager
5
  Description: All you need to manage access to your WordPress website
6
- Version: 5.7.1
7
  Author: Vasyl Martyniuk <vasyl@vasyltech.com>
8
  Author URI: https://vasyltech.com
9
 
@@ -124,7 +124,7 @@ class AAM {
124
  }
125
 
126
  // Load Access/Security Policies
127
- self::getUser()->getObject('policy')->load();
128
 
129
  //load WP Core hooks
130
  AAM_Shared_Manager::bootstrap();
@@ -172,6 +172,9 @@ class AAM {
172
  if (is_null(self::$_instance)) {
173
  self::$_instance = new self;
174
 
 
 
 
175
  // Logout user if he/she is blocked
176
  self::$_instance->getUser()->validateUserStatus();
177
 
3
  /**
4
  Plugin Name: Advanced Access Manager
5
  Description: All you need to manage access to your WordPress website
6
+ Version: 5.7.2
7
  Author: Vasyl Martyniuk <vasyl@vasyltech.com>
8
  Author URI: https://vasyltech.com
9
 
124
  }
125
 
126
  // Load Access/Security Policies
127
+ AAM_Core_Policy_Manager::bootstrap();
128
 
129
  //load WP Core hooks
130
  AAM_Shared_Manager::bootstrap();
172
  if (is_null(self::$_instance)) {
173
  self::$_instance = new self;
174
 
175
+ // Load user capabilities
176
+ self::$_instance->getUser()->loadCapabilities();
177
+
178
  // Logout user if he/she is blocked
179
  self::$_instance->getUser()->validateUserStatus();
180
 
media/js/{aam-5.7.js → aam-5.7.2.js} RENAMED
@@ -406,7 +406,7 @@
406
  id: data[0]
407
  },
408
  $('#object-id').val(),
409
- 1,
410
  this
411
  );
412
  }));
@@ -424,7 +424,7 @@
424
  id: data[0]
425
  },
426
  $('#object-id').val(),
427
- 0,
428
  this
429
  );
430
  }));
406
  id: data[0]
407
  },
408
  $('#object-id').val(),
409
+ ($(this).hasClass('icon-check-empty') ? 1 : 0),
410
  this
411
  );
412
  }));
424
  id: data[0]
425
  },
426
  $('#object-id').val(),
427
+ ($(this).hasClass('icon-check') ? 0 : 1),
428
  this
429
  );
430
  }));
readme.txt CHANGED
@@ -1,9 +1,9 @@
1
  === Advanced Access Manager ===
2
  Contributors: vasyltech
3
- Tags: access control, membership, backend menu, user role, restricted content
4
  Requires at least: 4.0
5
- Tested up to: 4.9.8
6
- Stable tag: 5.7.1
7
 
8
  All you need to manage access to you WordPress websites on frontend, backend and API levels for any role, user or visitors.
9
 
@@ -15,8 +15,8 @@ https://www.youtube.com/watch?v=mj5Xa_Wc16Y
15
 
16
  = Few Quick Facts =
17
 
 
18
  * Bullet-proven plugin that is used on over 90,000 websites where all features are well-tested and [documented](https://aamplugin.com/help). Very low amount of support tickets speaks for quality;
19
- * AAM contains the most powerful and flexible set of features to manage access to your WordPress website and were majority of them are absolutely free;
20
  * It is the only plugin that gives you the ability to manage access to your website content for any role, individual user and visitors or even define the default access to all posts, pages, custom post types, categories and custom hierarchical taxonomies;
21
  * AAM is [developer oriented plugin](https://aamplugin.com/developers). It has dozens of hooks and configurations. It is integrated with WordPress RESTful and XML-RPC APIs and has numerous abstract layers to simplify coding;
22
  * No ads or other promotional crap. The UI is clean and well crafted so you can focus only on what matters;
@@ -25,6 +25,7 @@ https://www.youtube.com/watch?v=mj5Xa_Wc16Y
25
 
26
  = Main Areas Of Focus =
27
 
 
28
  * Content access control on frontend, backend and API sides to posts, pages, custom post types, categories, custom hierarchical taxonomies and CPTs for any role, user and visitors;
29
  * Roles & capabilities management with ability to create new roles and capabilities, edit, clone or delete existing;
30
  * Access control to backend area including backend menu, toolbar, metaboxes & widgets;
@@ -42,6 +43,7 @@ https://www.youtube.com/watch?v=mj5Xa_Wc16Y
42
  * [free] Backend Lockdown. Restrict access to your website backend side for any user or role. Find out more from [How to lockdown WordPress backend](https://aamplugin.com/help/how-to-lockdown-wordpress-backend) article;
43
  * [free] Secure Login Widget & Shortcode. Drop AJAX login widget or shortcode anywhere on your website. Find out more from [How does AAM Secure Login works](https://aamplugin.com/help/how-does-aam-secure-login-works) article;
44
  * [free] Ability to enable/disable RESTful and XML-RPC APIs.
 
45
  * [free] Manage access to RESTful or XML-RPC individual endpoints for any role, user or visitors.
46
  * [free] JWT authentication. Authenticate user with WordPress RESTful API and use received JWT token for further requests. Fid out more from [Hot to authenticate WordPress user with JWT token](https://aamplugin.com/help/how-to-authenticate-wordpress-user-with-jwt-token)
47
  * [free] Content Filter. Filter or replace parts of your content with AAM shortcodes. Find out more from [How to filter WordPress post content](https://aamplugin.com/help/how-to-filter-wordpress-post-content) article;
@@ -76,6 +78,20 @@ https://www.youtube.com/watch?v=mj5Xa_Wc16Y
76
 
77
  == Changelog ==
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  = 5.7.1 =
80
  * Fixed the bug with AAM notifications related to extension updates
81
  * Fixed the bug with AAM not taking in consideration capabilities that defined in policy
1
  === Advanced Access Manager ===
2
  Contributors: vasyltech
3
+ Tags: access control, membership, backend menu, user role, restricted content, security, jwt
4
  Requires at least: 4.0
5
+ Tested up to: 5.0.2
6
+ Stable tag: 5.7.2
7
 
8
  All you need to manage access to you WordPress websites on frontend, backend and API levels for any role, user or visitors.
9
 
15
 
16
  = Few Quick Facts =
17
 
18
+ * The only plugin that gives you absolute freedom to define the most granular access to any aspect of your website and most of the feature are free;
19
  * Bullet-proven plugin that is used on over 90,000 websites where all features are well-tested and [documented](https://aamplugin.com/help). Very low amount of support tickets speaks for quality;
 
20
  * It is the only plugin that gives you the ability to manage access to your website content for any role, individual user and visitors or even define the default access to all posts, pages, custom post types, categories and custom hierarchical taxonomies;
21
  * AAM is [developer oriented plugin](https://aamplugin.com/developers). It has dozens of hooks and configurations. It is integrated with WordPress RESTful and XML-RPC APIs and has numerous abstract layers to simplify coding;
22
  * No ads or other promotional crap. The UI is clean and well crafted so you can focus only on what matters;
25
 
26
  = Main Areas Of Focus =
27
 
28
+ * [Access & Security Policy](https://aamplugin.com/access-and-security-policy) allows you to define who, when, how and under what conditions your website resources can be accessed;
29
  * Content access control on frontend, backend and API sides to posts, pages, custom post types, categories, custom hierarchical taxonomies and CPTs for any role, user and visitors;
30
  * Roles & capabilities management with ability to create new roles and capabilities, edit, clone or delete existing;
31
  * Access control to backend area including backend menu, toolbar, metaboxes & widgets;
43
  * [free] Backend Lockdown. Restrict access to your website backend side for any user or role. Find out more from [How to lockdown WordPress backend](https://aamplugin.com/help/how-to-lockdown-wordpress-backend) article;
44
  * [free] Secure Login Widget & Shortcode. Drop AJAX login widget or shortcode anywhere on your website. Find out more from [How does AAM Secure Login works](https://aamplugin.com/help/how-does-aam-secure-login-works) article;
45
  * [free] Ability to enable/disable RESTful and XML-RPC APIs.
46
+ * [limited] URI Access. Allow or deny access to any page of you website by the page URL as well as how to redirect user when access is denied;
47
  * [free] Manage access to RESTful or XML-RPC individual endpoints for any role, user or visitors.
48
  * [free] JWT authentication. Authenticate user with WordPress RESTful API and use received JWT token for further requests. Fid out more from [Hot to authenticate WordPress user with JWT token](https://aamplugin.com/help/how-to-authenticate-wordpress-user-with-jwt-token)
49
  * [free] Content Filter. Filter or replace parts of your content with AAM shortcodes. Find out more from [How to filter WordPress post content](https://aamplugin.com/help/how-to-filter-wordpress-post-content) article;
78
 
79
  == Changelog ==
80
 
81
+ = 5.7.2 =
82
+ * Fixed bug with Posts & Terms feature for WP version under 4.8
83
+ * Fixed bug were Access Policy can't be attached to any principal on the Policy edit screen
84
+ * Fixed bug with Access URI options were not merged for users with multiple roles
85
+ * Fixed bug with Access URI options were not exported
86
+ * Fixed but with Post PUBLISH option due to the fact that Gutenberg is using RESTful API
87
+ * Extended Access & Security Policy to support Posts & Terms options
88
+ * Added /validate-jwt RESTful API endpoint to validate JWT
89
+ * Added ability to extract JWT token from GET queries or POST payload
90
+ * Added custom capability aam_view_help_btn to hide HELP icon on AAM UI
91
+ * Significantly improved capability mapping mechanism and access control based on caps
92
+ * Added URI Access support to Access & Security Policy
93
+ * Added Post, Term, PostType support to Access & Security Policy
94
+
95
  = 5.7.1 =
96
  * Fixed the bug with AAM notifications related to extension updates
97
  * Fixed the bug with AAM not taking in consideration capabilities that defined in policy