Advanced Access Manager - Version 5.9.2

Version Description

  • Fixed the bug with Access Policy access control
  • Fixed the bug with Access Policy tab shows only 10 last Policies
  • Fixed the bug where AAM was not determining correct max user level
  • Fixed the bug where user was able to manage his roles on the profile page
  • Fixed the bug with Access Policy "Between" condition
  • Optimized AAM to support unusual access capabilities for custom post types https://forum.aamplugin.com/d/99-custom-post-type-does-not-honor-edit-delete-publish-overrides/5
  • Enhanced Access Policy with few new features. The complete reference is here https://aamplugin.com/reference/policy
  • Enabled 'JWT Authentication' by default
  • Significantly improved AAM UI page security
  • Added new JWT Tokens feature to the list of AAM features https://aamplugin.com/reference/plugin#jwt-tokens
  • Added new capability aam_manage_jwt
  • Added "Add New Policies" submenu to fix WordPress core bug with managing access to submenus
  • Removed "Role Expiration" feature - it was too confusing to work with
  • Removed allow_ajax_calls capability support - it was too confusing for end users
Download this release

Release Info

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

Code changes from version 5.9.1.1 to 5.9.2

Files changed (50) hide show
  1. Application/Backend/Feature.php +6 -1
  2. Application/Backend/Feature/Main/404Redirect.php +2 -1
  3. Application/Backend/Feature/Main/Capability.php +4 -2
  4. Application/Backend/Feature/Main/Jwt.php +182 -0
  5. Application/Backend/Feature/Main/LoginRedirect.php +2 -1
  6. Application/Backend/Feature/Main/LogoutRedirect.php +2 -1
  7. Application/Backend/Feature/Main/Menu.php +2 -1
  8. Application/Backend/Feature/Main/Metabox.php +2 -1
  9. Application/Backend/Feature/Main/Policy.php +14 -21
  10. Application/Backend/Feature/Main/Post.php +2 -1
  11. Application/Backend/Feature/Main/Redirect.php +2 -1
  12. Application/Backend/Feature/Main/Route.php +2 -1
  13. Application/Backend/Feature/Main/Toolbar.php +2 -1
  14. Application/Backend/Feature/Main/Uri.php +3 -2
  15. Application/Backend/Feature/Settings/Core.php +1 -1
  16. Application/Backend/Feature/Subject/Role.php +1 -20
  17. Application/Backend/Feature/Subject/User.php +18 -21
  18. Application/Backend/Manager.php +24 -47
  19. Application/Backend/Subject.php +30 -7
  20. Application/Backend/View.php +1 -0
  21. Application/Backend/phtml/index.phtml +0 -27
  22. Application/Backend/phtml/main/jwt.phtml +126 -0
  23. Application/Backend/phtml/main/menu.phtml +2 -2
  24. Application/Backend/phtml/main/metabox.phtml +1 -1
  25. Application/Backend/phtml/main/toolbar.phtml +1 -1
  26. Application/Backend/phtml/user/multiple-roles.phtml +29 -27
  27. Application/Core/Compatibility.php +34 -1
  28. Application/Core/Gateway.php +9 -0
  29. Application/Core/Jwt/Auth.php +69 -0
  30. Application/Core/Jwt/Issuer.php +229 -0
  31. Application/Core/Jwt/Manager.php +356 -0
  32. Application/Core/JwtAuth.php +0 -347
  33. Application/Core/Login.php +20 -4
  34. Application/Core/Object/Post.php +8 -3
  35. Application/Core/Object/Route.php +5 -4
  36. Application/Core/Policy/Condition.php +21 -5
  37. Application/Core/Policy/Token.php +2 -0
  38. Application/Core/Subject/User.php +160 -81
  39. Application/Shared/Manager.php +117 -74
  40. aam.php +22 -14
  41. media/css/aam.css +15 -6
  42. media/font/fontello.eot +0 -0
  43. media/font/fontello.svg +4 -0
  44. media/font/fontello.ttf +0 -0
  45. media/font/fontello.woff +0 -0
  46. media/font/fontello.woff2 +0 -0
  47. media/js/{aam-5.9.1.js → aam-5.9.2.js} +311 -84
  48. media/js/vendor.js +9 -1
  49. readme.txt +18 -1
  50. vendor/firebase/JWT.php +4 -1
Application/Backend/Feature.php CHANGED
@@ -40,19 +40,24 @@ class AAM_Backend_Feature {
40
  public static function registerFeature(stdClass $feature) {
41
  $response = false;
42
 
 
43
  if (empty($feature->capability)){
44
  $cap = 'aam_manager';
45
  } else {
46
  $cap = $feature->capability;
47
  }
48
 
 
49
  if (isset($feature->option)) {
50
  $show = self::isVisible($feature->option);
51
  } else {
52
  $show = true;
53
  }
 
 
 
54
 
55
- if ($show && current_user_can($cap)) {
56
  self::$_features[] = $feature;
57
  $response = true;
58
  }
40
  public static function registerFeature(stdClass $feature) {
41
  $response = false;
42
 
43
+ // Determine correct AAM UI capability
44
  if (empty($feature->capability)){
45
  $cap = 'aam_manager';
46
  } else {
47
  $cap = $feature->capability;
48
  }
49
 
50
+ // Determine if minimum required options are enabled
51
  if (isset($feature->option)) {
52
  $show = self::isVisible($feature->option);
53
  } else {
54
  $show = true;
55
  }
56
+
57
+ // Determine that current user has enough level to manage requested subject
58
+ $allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
59
 
60
+ if ($show && $allowed && current_user_can($cap)) {
61
  self::$_features[] = $feature;
62
  $response = true;
63
  }
Application/Backend/Feature/Main/404Redirect.php CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_404Redirect extends AAM_Backend_Feature_Abstract
21
  public function __construct() {
22
  parent::__construct();
23
 
24
- if (!current_user_can('aam_manage_404_redirect')) {
 
25
  AAM::api()->denyAccess(array('reason' => 'aam_manage_404_redirect'));
26
  }
27
  }
21
  public function __construct() {
22
  parent::__construct();
23
 
24
+ $allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
25
+ if (!$allowed || !current_user_can('aam_manage_404_redirect')) {
26
  AAM::api()->denyAccess(array('reason' => 'aam_manage_404_redirect'));
27
  }
28
  }
Application/Backend/Feature/Main/Capability.php CHANGED
@@ -56,7 +56,8 @@ class AAM_Backend_Feature_Main_Capability extends AAM_Backend_Feature_Abstract {
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', 'aam_edit_policy', 'aam_read_policy', 'aam_delete_policy',
59
- 'aam_delete_policies', 'aam_edit_policies', 'aam_edit_others_policies', 'aam_publish_policies'
 
60
  )
61
  );
62
 
@@ -66,7 +67,8 @@ class AAM_Backend_Feature_Main_Capability extends AAM_Backend_Feature_Abstract {
66
  public function __construct() {
67
  parent::__construct();
68
 
69
- if (!current_user_can('aam_manage_capabilities')) {
 
70
  AAM::api()->denyAccess(array('reason' => 'aam_manage_capabilities'));
71
  }
72
  }
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', 'aam_edit_policy', 'aam_read_policy', 'aam_delete_policy',
59
+ 'aam_delete_policies', 'aam_edit_policies', 'aam_edit_others_policies', 'aam_publish_policies',
60
+ 'aam_manage_jwt'
61
  )
62
  );
63
 
67
  public function __construct() {
68
  parent::__construct();
69
 
70
+ $allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
71
+ if (!$allowed || !current_user_can('aam_manage_capabilities')) {
72
  AAM::api()->denyAccess(array('reason' => 'aam_manage_capabilities'));
73
  }
74
  }
Application/Backend/Feature/Main/Jwt.php ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ * JWT manager
12
+ *
13
+ * @package AAM
14
+ * @author Vasyl Martyniuk <vasyl@vasyltech.com>
15
+ */
16
+ class AAM_Backend_Feature_Main_Jwt extends AAM_Backend_Feature_Abstract {
17
+
18
+ /**
19
+ * Construct
20
+ */
21
+ public function __construct() {
22
+ parent::__construct();
23
+
24
+ $allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
25
+ if (!$allowed || !current_user_can('aam_manage_jwt')) {
26
+ AAM::api()->denyAccess(array('reason' => 'aam_manage_jwt'));
27
+ }
28
+ }
29
+
30
+ /**
31
+ *
32
+ * @return type
33
+ */
34
+ public function getTable() {
35
+ return wp_json_encode($this->retrieveList());
36
+ }
37
+
38
+ /**
39
+ *
40
+ * @return type
41
+ */
42
+ public function generate() {
43
+ $user = AAM_Backend_Subject::getInstance()->get();
44
+ $expires = filter_input(INPUT_POST, 'expires');
45
+
46
+ try {
47
+ $max = AAM::getUser()->getMaxLevel();
48
+ if ($max >= AAM_Core_API::maxLevel($user->allcaps)) {
49
+ $issuer = new AAM_Core_Jwt_Issuer();
50
+ $jwt = $issuer->issueToken(
51
+ array('userId' => $user->ID, 'revocable' => true),
52
+ $expires
53
+ );
54
+ $result = array(
55
+ 'status' => 'success',
56
+ 'jwt' => $jwt->token
57
+ );
58
+ } else {
59
+ throw new Exception('User ID has higher level than current user');
60
+ }
61
+ } catch (Exception $ex) {
62
+ $result = array('status' => 'failure', 'reason' => $ex->getMessage());
63
+ }
64
+
65
+ return wp_json_encode($result);
66
+ }
67
+
68
+ /**
69
+ *
70
+ * @return type
71
+ */
72
+ public function save() {
73
+ $user = AAM_Backend_Subject::getInstance()->get();
74
+ $token = filter_input(INPUT_POST, 'token');
75
+ $claims = AAM_Core_Jwt_Issuer::extractTokenClaims($token);
76
+
77
+ $result = AAM_Core_Jwt_Manager::getInstance()->registerToken(
78
+ $user->ID,
79
+ $token
80
+ );
81
+
82
+ if ($result) {
83
+ $response = array('status' => 'success');
84
+ } else {
85
+ $response = array(
86
+ 'status' => 'failure',
87
+ 'reason' => __('Failed to register JWT token', AAM_KEY)
88
+ );
89
+ }
90
+
91
+ return wp_json_encode($response);
92
+ }
93
+
94
+ /**
95
+ *
96
+ * @return type
97
+ */
98
+ public function delete() {
99
+ $user = AAM_Backend_Subject::getInstance()->get();
100
+ $token = filter_input(INPUT_POST, 'token');
101
+ $result = AAM_Core_Jwt_Manager::getInstance()->revokeToken($user->ID, $token);
102
+
103
+ if ($result) {
104
+ $response = array('status' => 'success');
105
+ } else {
106
+ $response = array(
107
+ 'status' => 'failure',
108
+ 'reason' => __('Failed to revoke JWT token', AAM_KEY)
109
+ );
110
+ }
111
+
112
+ return wp_json_encode($response);
113
+ }
114
+
115
+ /**
116
+ * @inheritdoc
117
+ */
118
+ public static function getTemplate() {
119
+ return 'main/jwt.phtml';
120
+ }
121
+
122
+ /**
123
+ *
124
+ * @return type
125
+ */
126
+ protected function retrieveList() {
127
+ $tokens = AAM_Core_Jwt_Manager::getInstance()->getTokenRegistry(
128
+ AAM_Backend_Subject::getInstance()->get()->ID
129
+ );
130
+
131
+ $response = array(
132
+ 'recordsTotal' => count($tokens),
133
+ 'recordsFiltered' => count($tokens),
134
+ 'draw' => AAM_Core_Request::request('draw'),
135
+ 'data' => array(),
136
+ );
137
+
138
+ $issuer = new AAM_Core_Jwt_Issuer();
139
+
140
+ foreach($tokens as $token) {
141
+ try {
142
+ $claims = $issuer->validateToken($token);
143
+ } catch(Exception $e) {
144
+ $claims = $issuer->extractTokenClaims($token);
145
+ $claims->status = 'invalid';
146
+ }
147
+
148
+ $response['data'][] = array(
149
+ $token,
150
+ add_query_arg('aam-jwt', $token, site_url()),
151
+ $claims->status,
152
+ $claims->exp,
153
+ 'view,delete'
154
+ );
155
+ }
156
+
157
+ return $response;
158
+ }
159
+
160
+ /**
161
+ * Register Menu feature
162
+ *
163
+ * @return void
164
+ *
165
+ * @access public
166
+ */
167
+ public static function register() {
168
+ AAM_Backend_Feature::registerFeature((object) array(
169
+ 'uid' => 'jwt',
170
+ 'position' => 65,
171
+ 'title' => __('JWT Tokens', AAM_KEY) . '<span class="badge">NEW</span>',
172
+ 'capability' => 'aam_manage_jwt',
173
+ 'type' => 'main',
174
+ 'subjects' => array(
175
+ AAM_Core_Subject_User::UID
176
+ ),
177
+ 'option' => 'core.settings.jwtAuthentication',
178
+ 'view' => __CLASS__
179
+ ));
180
+ }
181
+
182
+ }
Application/Backend/Feature/Main/LoginRedirect.php CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_LoginRedirect extends AAM_Backend_Feature_Abstrac
21
  public function __construct() {
22
  parent::__construct();
23
 
24
- if (!current_user_can('aam_manage_login_redirect')) {
 
25
  AAM::api()->denyAccess(array('reason' => 'aam_manage_login_redirect'));
26
  }
27
  }
21
  public function __construct() {
22
  parent::__construct();
23
 
24
+ $allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
25
+ if (!$allowed || !current_user_can('aam_manage_login_redirect')) {
26
  AAM::api()->denyAccess(array('reason' => 'aam_manage_login_redirect'));
27
  }
28
  }
Application/Backend/Feature/Main/LogoutRedirect.php CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_LogoutRedirect extends AAM_Backend_Feature_Abstra
21
  public function __construct() {
22
  parent::__construct();
23
 
24
- if (!current_user_can('aam_manage_logout_redirect')) {
 
25
  AAM::api()->denyAccess(array('reason' => 'aam_manage_logout_redirect'));
26
  }
27
  }
21
  public function __construct() {
22
  parent::__construct();
23
 
24
+ $allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
25
+ if (!$allowed || !current_user_can('aam_manage_logout_redirect')) {
26
  AAM::api()->denyAccess(array('reason' => 'aam_manage_logout_redirect'));
27
  }
28
  }
Application/Backend/Feature/Main/Menu.php CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_Menu extends AAM_Backend_Feature_Abstract {
21
  public function __construct() {
22
  parent::__construct();
23
 
24
- if (!current_user_can('aam_manage_admin_menu')) {
 
25
  AAM::api()->denyAccess(array('reason' => 'aam_manage_admin_menu'));
26
  }
27
  }
21
  public function __construct() {
22
  parent::__construct();
23
 
24
+ $allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
25
+ if (!$allowed || !current_user_can('aam_manage_admin_menu')) {
26
  AAM::api()->denyAccess(array('reason' => 'aam_manage_admin_menu'));
27
  }
28
  }
Application/Backend/Feature/Main/Metabox.php CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_Metabox extends AAM_Backend_Feature_Abstract {
21
  public function __construct() {
22
  parent::__construct();
23
 
24
- if (!current_user_can('aam_manage_metaboxes')) {
 
25
  AAM::api()->denyAccess(array('reason' => 'aam_manage_metaboxes'));
26
  }
27
  }
21
  public function __construct() {
22
  parent::__construct();
23
 
24
+ $allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
25
+ if (!$allowed || !current_user_can('aam_manage_metaboxes')) {
26
  AAM::api()->denyAccess(array('reason' => 'aam_manage_metaboxes'));
27
  }
28
  }
Application/Backend/Feature/Main/Policy.php CHANGED
@@ -15,6 +15,18 @@
15
  */
16
  class AAM_Backend_Feature_Main_Policy extends AAM_Backend_Feature_Abstract {
17
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  /**
19
  *
20
  * @return type
@@ -131,9 +143,8 @@ class AAM_Backend_Feature_Main_Policy extends AAM_Backend_Feature_Abstract {
131
 
132
  $list = get_posts(array(
133
  'post_type' => 'aam_policy',
134
- 'numberposts' => AAM_Core_Request::request('length'),
135
- 'offset' => AAM_Core_Request::request('start'),
136
- 's' => ($search ? $search . '*' : ''),
137
  ));
138
 
139
  $response = array(
@@ -159,24 +170,6 @@ class AAM_Backend_Feature_Main_Policy extends AAM_Backend_Feature_Abstract {
159
  return $response;
160
  }
161
 
162
- /**
163
- *
164
- * @global type $wpdb
165
- * @param type $type
166
- * @param type $search
167
- * @return type
168
- */
169
- protected function getPolicyCount($type, $search) {
170
- global $wpdb;
171
-
172
- $query = "SELECT COUNT(*) AS total FROM {$wpdb->posts} ";
173
- $query .= "WHERE (post_type = %s) AND (post_title LIKE %s) AND (post_status = %s)";
174
-
175
- $args = array($type, "{$search}%", 'publish');
176
-
177
- return $wpdb->get_var($wpdb->prepare($query, $args));
178
- }
179
-
180
  /**
181
  *
182
  * @param type $record
15
  */
16
  class AAM_Backend_Feature_Main_Policy extends AAM_Backend_Feature_Abstract {
17
 
18
+ /**
19
+ * Construct
20
+ */
21
+ public function __construct() {
22
+ parent::__construct();
23
+
24
+ $allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
25
+ if (!$allowed || !current_user_can('aam_manage_policy')) {
26
+ AAM::api()->denyAccess(array('reason' => 'aam_manage_policy'));
27
+ }
28
+ }
29
+
30
  /**
31
  *
32
  * @return type
143
 
144
  $list = get_posts(array(
145
  'post_type' => 'aam_policy',
146
+ 'numberposts' => -1,
147
+ 'post_status' => 'publish'
 
148
  ));
149
 
150
  $response = array(
170
  return $response;
171
  }
172
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  /**
174
  *
175
  * @param type $record
Application/Backend/Feature/Main/Post.php CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_Post extends AAM_Backend_Feature_Abstract {
21
  public function __construct() {
22
  parent::__construct();
23
 
24
- if (!current_user_can('aam_manage_posts')) {
 
25
  AAM::api()->denyAccess(array('reason' => 'aam_manage_posts'));
26
  }
27
  }
21
  public function __construct() {
22
  parent::__construct();
23
 
24
+ $allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
25
+ if (!$allowed || !current_user_can('aam_manage_posts')) {
26
  AAM::api()->denyAccess(array('reason' => 'aam_manage_posts'));
27
  }
28
  }
Application/Backend/Feature/Main/Redirect.php CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_Redirect extends AAM_Backend_Feature_Abstract {
21
  public function __construct() {
22
  parent::__construct();
23
 
24
- if (!current_user_can('aam_manage_access_denied_redirect')) {
 
25
  AAM::api()->denyAccess(array('reason' => 'aam_manage_access_denied_redirect'));
26
  }
27
  }
21
  public function __construct() {
22
  parent::__construct();
23
 
24
+ $allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
25
+ if (!$allowed || !current_user_can('aam_manage_access_denied_redirect')) {
26
  AAM::api()->denyAccess(array('reason' => 'aam_manage_access_denied_redirect'));
27
  }
28
  }
Application/Backend/Feature/Main/Route.php CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_Route extends AAM_Backend_Feature_Abstract {
21
  public function __construct() {
22
  parent::__construct();
23
 
24
- if (!current_user_can('aam_manage_api_routes')) {
 
25
  AAM::api()->denyAccess(array('reason' => 'aam_manage_api_routes'));
26
  }
27
  }
21
  public function __construct() {
22
  parent::__construct();
23
 
24
+ $allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
25
+ if (!$allowed || !current_user_can('aam_manage_api_routes')) {
26
  AAM::api()->denyAccess(array('reason' => 'aam_manage_api_routes'));
27
  }
28
  }
Application/Backend/Feature/Main/Toolbar.php CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_Toolbar extends AAM_Backend_Feature_Abstract {
21
  public function __construct() {
22
  parent::__construct();
23
 
24
- if (!current_user_can('aam_manage_admin_toolbar')) {
 
25
  AAM::api()->denyAccess(array('reason' => 'aam_manage_admin_toolbar'));
26
  }
27
  }
21
  public function __construct() {
22
  parent::__construct();
23
 
24
+ $allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
25
+ if (!$allowed || !current_user_can('aam_manage_admin_toolbar')) {
26
  AAM::api()->denyAccess(array('reason' => 'aam_manage_admin_toolbar'));
27
  }
28
  }
Application/Backend/Feature/Main/Uri.php CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_Uri extends AAM_Backend_Feature_Abstract {
21
  public function __construct() {
22
  parent::__construct();
23
 
24
- if (!current_user_can('aam_manage_uri')) {
 
25
  AAM::api()->denyAccess(array('reason' => 'aam_manage_uri'));
26
  }
27
  }
@@ -146,7 +147,7 @@ class AAM_Backend_Feature_Main_Uri extends AAM_Backend_Feature_Abstract {
146
  AAM_Backend_Feature::registerFeature((object) array(
147
  'uid' => 'uri',
148
  'position' => 55,
149
- 'title' => __('URI Access', AAM_KEY) . '<span class="badge">NEW</span>',
150
  'capability' => 'aam_manage_uri',
151
  'type' => 'main',
152
  'subjects' => array(
21
  public function __construct() {
22
  parent::__construct();
23
 
24
+ $allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
25
+ if (!$allowed || !current_user_can('aam_manage_uri')) {
26
  AAM::api()->denyAccess(array('reason' => 'aam_manage_uri'));
27
  }
28
  }
147
  AAM_Backend_Feature::registerFeature((object) array(
148
  'uid' => 'uri',
149
  'position' => 55,
150
+ 'title' => __('URI Access', AAM_KEY),
151
  'capability' => 'aam_manage_uri',
152
  'type' => 'main',
153
  'subjects' => array(
Application/Backend/Feature/Settings/Core.php CHANGED
@@ -92,7 +92,7 @@ class AAM_Backend_Feature_Settings_Core extends AAM_Backend_Feature_Abstract {
92
  'core.settings.jwtAuthentication' => array(
93
  'title' => __('JWT Authentication', AAM_KEY),
94
  'descr' => sprintf(AAM_Backend_View_Helper::preparePhrase('[Note!] PHP 5.4 or higher is required for this feature. Enable the ability to authenticate user with WordPress RESTful API and JWT token. For more information, check %sHow to authenticate WordPress user with JWT token%s article', 'b'), '<a href="https://aamplugin.com/article/how-to-authenticate-wordpress-user-with-jwt-token">', '</a>'),
95
- 'value' => AAM_Core_Config::get('core.settings.jwtAuthentication', false)
96
  ),
97
  'core.settings.multiSubject' => array(
98
  'title' => __('Multiple Roles Support', AAM_KEY),
92
  'core.settings.jwtAuthentication' => array(
93
  'title' => __('JWT Authentication', AAM_KEY),
94
  'descr' => sprintf(AAM_Backend_View_Helper::preparePhrase('[Note!] PHP 5.4 or higher is required for this feature. Enable the ability to authenticate user with WordPress RESTful API and JWT token. For more information, check %sHow to authenticate WordPress user with JWT token%s article', 'b'), '<a href="https://aamplugin.com/article/how-to-authenticate-wordpress-user-with-jwt-token">', '</a>'),
95
+ 'value' => AAM_Core_Config::get('core.settings.jwtAuthentication', true)
96
  ),
97
  'core.settings.multiSubject' => array(
98
  'title' => __('Multiple Roles Support', AAM_KEY),
Application/Backend/Feature/Subject/Role.php CHANGED
@@ -59,8 +59,7 @@ class AAM_Backend_Feature_Subject_Role {
59
  implode(',', $this->prepareRowActions($uc, $id)),
60
  $data
61
  ),
62
- AAM_Core_API::maxLevel($data['capabilities']),
63
- AAM_Core_API::getOption("aam-role-{$id}-expiration", '')
64
  );
65
  }
66
 
@@ -163,7 +162,6 @@ class AAM_Backend_Feature_Subject_Role {
163
 
164
  if (current_user_can('aam_create_roles')) {
165
  $name = sanitize_text_field(filter_input(INPUT_POST, 'name'));
166
- $expire = filter_input(INPUT_POST, 'expire');
167
  $roles = AAM_Core_API::getRoles();
168
  $role_id = sanitize_key(strtolower($name));
169
 
@@ -185,13 +183,6 @@ class AAM_Backend_Feature_Subject_Role {
185
  $this->cloneSettings($role, $parent);
186
  }
187
 
188
- //save expiration rule if set
189
- if ($expire) {
190
- AAM_Core_API::updateOption("aam-role-{$role_id}-expiration", $expire);
191
- } else {
192
- AAM_Core_API::deleteOption("aam-role-{$role_id}-expiration");
193
- }
194
-
195
  do_action('aam-post-add-role-action', $role, $parent);
196
  } else {
197
  $response['reason'] = __("Role with slug [{$role_id}] already exists", AAM_KEY);
@@ -246,16 +237,6 @@ class AAM_Backend_Feature_Subject_Role {
246
  $role = AAM_Backend_Subject::getInstance();
247
  $role->update(trim(filter_input(INPUT_POST, 'name')));
248
 
249
- $expire = filter_input(INPUT_POST, 'expire');
250
- //save expiration rule if set
251
- if ($expire) {
252
- AAM_Core_API::updateOption(
253
- 'aam-role-' . $role->getId() .'-expiration', $expire
254
- );
255
- } else {
256
- AAM_Core_API::deleteOption('aam-role-' . $role->getId() .'-expiration');
257
- }
258
-
259
  do_action('aam-post-update-role-action', $role->get());
260
 
261
  $response = array('status' => 'success');
59
  implode(',', $this->prepareRowActions($uc, $id)),
60
  $data
61
  ),
62
+ AAM_Core_API::maxLevel($data['capabilities'])
 
63
  );
64
  }
65
 
162
 
163
  if (current_user_can('aam_create_roles')) {
164
  $name = sanitize_text_field(filter_input(INPUT_POST, 'name'));
 
165
  $roles = AAM_Core_API::getRoles();
166
  $role_id = sanitize_key(strtolower($name));
167
 
183
  $this->cloneSettings($role, $parent);
184
  }
185
 
 
 
 
 
 
 
 
186
  do_action('aam-post-add-role-action', $role, $parent);
187
  } else {
188
  $response['reason'] = __("Role with slug [{$role_id}] already exists", AAM_KEY);
237
  $role = AAM_Backend_Subject::getInstance();
238
  $role->update(trim(filter_input(INPUT_POST, 'name')));
239
 
 
 
 
 
 
 
 
 
 
 
240
  do_action('aam-post-update-role-action', $role->get());
241
 
242
  $response = array('status' => 'success');
Application/Backend/Feature/Subject/User.php CHANGED
@@ -98,10 +98,9 @@ class AAM_Backend_Feature_Subject_User {
98
  );
99
 
100
  if (current_user_can('aam_switch_users')) {
101
- $user = new WP_User(AAM_Core_Request::post('user'));
102
- $max = AAM::getUser()->getMaxLevel();
103
 
104
- if ($max >= AAM_Core_API::maxLevel($user->allcaps)) {
105
  AAM_Core_API::updateOption(
106
  'aam-user-switch-' . $user->ID, get_current_user_id()
107
  );
@@ -137,22 +136,6 @@ class AAM_Backend_Feature_Subject_User {
137
  return wp_json_encode($response);
138
  }
139
 
140
- /**
141
- *
142
- * @return type
143
- */
144
- public function generateJWT() {
145
- $userId = filter_input(INPUT_POST, 'user');
146
- $expires = filter_input(INPUT_POST, 'expires');
147
-
148
- $jwt = AAM_Core_JwtAuth::generateJWT($userId, $expires);
149
-
150
- return wp_json_encode(array(
151
- 'status' => 'success',
152
- 'jwt' => $jwt->token
153
- ));
154
- }
155
-
156
  /**
157
  * Query database for list of users
158
  *
@@ -361,9 +344,23 @@ class AAM_Backend_Feature_Subject_User {
361
  * @access protected
362
  */
363
  protected function isAllowed(AAM_Core_Subject_User $user) {
364
- $max = AAM::getUser()->getMaxLevel();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
 
366
- return $max >= AAM_Core_API::maxLevel($user->allcaps);
367
  }
368
 
369
  }
98
  );
99
 
100
  if (current_user_can('aam_switch_users')) {
101
+ $user = AAM_Backend_Subject::getInstance()->get();
 
102
 
103
+ if ($this->isAllowed($user)) {
104
  AAM_Core_API::updateOption(
105
  'aam-user-switch-' . $user->ID, get_current_user_id()
106
  );
136
  return wp_json_encode($response);
137
  }
138
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  /**
140
  * Query database for list of users
141
  *
344
  * @access protected
345
  */
346
  protected function isAllowed(AAM_Core_Subject_User $user) {
347
+ $sameLevel = false;
348
+ if (AAM_Core_API::capabilityExists('manage_same_user_level')) {
349
+ $sameLevel = current_user_can('manage_same_user_level');
350
+ } else {
351
+ $sameLevel = current_user_can('administrator');
352
+ }
353
+
354
+ $userMaxLevel = AAM::api()->getUser()->getMaxLevel();
355
+ $subjectMaxLevel = $user->getMaxLevel();
356
+
357
+ if ($sameLevel) {
358
+ $allowed = $userMaxLevel >= $subjectMaxLevel;
359
+ } else {
360
+ $allowed = $userMaxLevel > $subjectMaxLevel;
361
+ }
362
 
363
+ return $allowed;
364
  }
365
 
366
  }
Application/Backend/Manager.php CHANGED
@@ -46,9 +46,6 @@ class AAM_Backend_Manager {
46
  add_action('admin_print_footer_scripts', array($this, 'printFooterJavascript'));
47
  add_action('admin_print_styles', array($this, 'printStylesheet'));
48
 
49
- //map AAM UI specific capabilities
50
- add_filter('map_meta_cap', array($this, 'mapMetaCap'), 10, 4);
51
-
52
  //user profile update action
53
  add_action('profile_update', array($this, 'profileUpdate'), 10, 2);
54
 
@@ -74,9 +71,10 @@ class AAM_Backend_Manager {
74
  //manager Admin Menu
75
  if (is_multisite() && is_network_admin()) {
76
  //register AAM in the network admin panel
77
- add_action('network_admin_menu', array($this, 'adminMenu'));
78
  } else {
79
- add_action('admin_menu', array($this, 'adminMenu'));
 
80
  add_action('all_admin_notices', array($this, 'notification'));
81
  }
82
 
@@ -314,22 +312,6 @@ class AAM_Backend_Manager {
314
  $importer->dispatch();
315
  }
316
 
317
- /**
318
- *
319
- * @param type $caps
320
- * @param type $cap
321
- * @return type
322
- */
323
- public function mapMetaCap($caps, $cap) {
324
- if (in_array($cap, AAM_Backend_Feature_Main_Capability::$groups['aam'], true)) {
325
- if (!AAM_Core_API::capabilityExists($cap)) {
326
- $caps = array(AAM_Core_Config::get('page.capability', 'administrator'));
327
- }
328
- }
329
-
330
- return $caps;
331
- }
332
-
333
  /**
334
  *
335
  * @param string $html
@@ -368,7 +350,8 @@ class AAM_Backend_Manager {
368
 
369
  if (!empty($newRoles)) {
370
  //remove all current roles and then set new
371
- $user->set_role($role);
 
372
  foreach($newRoles as $role) {
373
  $user->add_role($role);
374
  }
@@ -378,19 +361,6 @@ class AAM_Backend_Manager {
378
  //role changed?
379
  if (implode('', $user->roles) !== implode('', $old->roles)) {
380
  AAM_Core_API::clearCache(new AAM_Core_Subject_User($id));
381
-
382
- // check if role has expiration data set
383
- // TODO: This supports only the first role and NOT the multi-roles
384
- if (is_array($user->roles)) {
385
- $roles = array_values($user->roles);
386
- $role = array_shift($roles);
387
- $expire = AAM_Core_API::getOption("aam-role-{$role}-expiration", '');
388
-
389
- if ($expire) {
390
- update_user_option($id, "aam-original-roles", $old->roles);
391
- update_user_option($id, "aam-role-expires", strtotime($expire));
392
- }
393
- }
394
  }
395
  }
396
 
@@ -514,17 +484,12 @@ class AAM_Backend_Manager {
514
 
515
  if ($uid && AAM_Core_API::capabilityExists('access_dashboard')) {
516
  $caps = AAM::getUser()->allcaps;
517
- if (empty($caps['access_dashboard'])) {
518
- //also additionally check for AJAX calls
519
- if (defined('DOING_AJAX') && empty($caps['allow_ajax_calls'])) {
520
- AAM_Core_API::reject(
521
- 'backend', array('hook' => 'access_dashboard')
522
- );
523
- } elseif (!defined('DOING_AJAX')) {
524
- AAM_Core_API::reject(
525
- 'backend', array('hook' => 'access_dashboard')
526
- );
527
- }
528
  }
529
  }
530
  }
@@ -833,7 +798,7 @@ class AAM_Backend_Manager {
833
  public function printJavascript() {
834
  if (AAM::isAAM()) {
835
  wp_enqueue_script('aam-vendor', AAM_MEDIA . '/js/vendor.js');
836
- wp_enqueue_script('aam-main', AAM_MEDIA . '/js/aam-5.9.1.js');
837
 
838
  //add plugin localization
839
  $this->printLocalization('aam-main');
@@ -956,6 +921,18 @@ class AAM_Backend_Manager {
956
  AAM_Core_Config::get('policy.capability', 'aam_manage_policy'),
957
  'edit.php?post_type=aam_policy'
958
  );
 
 
 
 
 
 
 
 
 
 
 
 
959
  }
960
 
961
  /**
46
  add_action('admin_print_footer_scripts', array($this, 'printFooterJavascript'));
47
  add_action('admin_print_styles', array($this, 'printStylesheet'));
48
 
 
 
 
49
  //user profile update action
50
  add_action('profile_update', array($this, 'profileUpdate'), 10, 2);
51
 
71
  //manager Admin Menu
72
  if (is_multisite() && is_network_admin()) {
73
  //register AAM in the network admin panel
74
+ add_action('_network_admin_menu', array($this, 'adminMenu'));
75
  } else {
76
+ add_action('_user_admin_menu', array($this, 'adminMenu'));
77
+ add_action('_admin_menu', array($this, 'adminMenu'));
78
  add_action('all_admin_notices', array($this, 'notification'));
79
  }
80
 
312
  $importer->dispatch();
313
  }
314
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
  /**
316
  *
317
  * @param string $html
350
 
351
  if (!empty($newRoles)) {
352
  //remove all current roles and then set new
353
+ $user->set_role('');
354
+ // TODO: Fix the bug where multiple roles are not removed
355
  foreach($newRoles as $role) {
356
  $user->add_role($role);
357
  }
361
  //role changed?
362
  if (implode('', $user->roles) !== implode('', $old->roles)) {
363
  AAM_Core_API::clearCache(new AAM_Core_Subject_User($id));
 
 
 
 
 
 
 
 
 
 
 
 
 
364
  }
365
  }
366
 
484
 
485
  if ($uid && AAM_Core_API::capabilityExists('access_dashboard')) {
486
  $caps = AAM::getUser()->allcaps;
487
+ // If this is the AJAX call, still allow it because it will break a lot
488
+ // of frontend stuff that depends on it
489
+ if (empty($caps['access_dashboard']) && !defined('DOING_AJAX')) {
490
+ AAM_Core_API::reject(
491
+ 'backend', array('hook' => 'access_dashboard')
492
+ );
 
 
 
 
 
493
  }
494
  }
495
  }
798
  public function printJavascript() {
799
  if (AAM::isAAM()) {
800
  wp_enqueue_script('aam-vendor', AAM_MEDIA . '/js/vendor.js');
801
+ wp_enqueue_script('aam-main', AAM_MEDIA . '/js/aam-5.9.2.js');
802
 
803
  //add plugin localization
804
  $this->printLocalization('aam-main');
921
  AAM_Core_Config::get('policy.capability', 'aam_manage_policy'),
922
  'edit.php?post_type=aam_policy'
923
  );
924
+
925
+ $type = get_post_type_object('aam_policy');
926
+ if (current_user_can($type->cap->create_posts)) {
927
+ add_submenu_page(
928
+ 'aam',
929
+ 'Add New Policies',
930
+ 'Add New Policies',
931
+ $type->cap->create_posts,
932
+ 'post-new.php?post_type=aam_policy'
933
+ );
934
+ }
935
+
936
  }
937
 
938
  /**
Application/Backend/Subject.php CHANGED
@@ -51,12 +51,6 @@ class AAM_Backend_Subject {
51
  $instance = $this->initRequestedSubject(
52
  $subject, AAM_Core_Request::request('subjectId')
53
  );
54
-
55
- $max = AAM::getUser()->getMaxLevel();
56
-
57
- if ($max < AAM_Core_API::maxLevel($instance->getMaxLevel())) {
58
- AAM::api()->denyAccess(array('reason' => 'User Level is too low'));
59
- }
60
  } else {
61
  $this->initDefaultSubject();
62
  }
@@ -99,7 +93,8 @@ class AAM_Backend_Subject {
99
  */
100
  protected function initDefaultSubject() {
101
  // This cover the scenario when we directly go to user e.g. ?page=aam&user=38
102
- $forceUser = AAM_Core_Request::get('user');
 
103
 
104
  // TODO: The aam_list_roles is legacy and can be removed in Oct 2021
105
  if (!$forceUser && (current_user_can('aam_manage_roles') || current_user_can('aam_list_roles'))) {
@@ -129,6 +124,34 @@ class AAM_Backend_Subject {
129
  protected function setSubject(AAM_Core_Subject $subject) {
130
  $this->subject = $subject;
131
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
 
133
  /**
134
  * Get subject property
51
  $instance = $this->initRequestedSubject(
52
  $subject, AAM_Core_Request::request('subjectId')
53
  );
 
 
 
 
 
 
54
  } else {
55
  $this->initDefaultSubject();
56
  }
93
  */
94
  protected function initDefaultSubject() {
95
  // This cover the scenario when we directly go to user e.g. ?page=aam&user=38
96
+ // or through AJAX post request with user ID
97
+ $forceUser = AAM_Core_Request::request('user');
98
 
99
  // TODO: The aam_list_roles is legacy and can be removed in Oct 2021
100
  if (!$forceUser && (current_user_can('aam_manage_roles') || current_user_can('aam_list_roles'))) {
124
  protected function setSubject(AAM_Core_Subject $subject) {
125
  $this->subject = $subject;
126
  }
127
+
128
+ /**
129
+ * Check if current subject is allowed to be managed
130
+ *
131
+ * @return boolean
132
+ *
133
+ * @access public
134
+ */
135
+ public function isAllowedToManage() {
136
+ // Determine that current user has enough level to manage requested subject
137
+ $sameLevel = false;
138
+ if (AAM_Core_API::capabilityExists('manage_same_user_level')) {
139
+ $sameLevel = current_user_can('manage_same_user_level');
140
+ } else {
141
+ $sameLevel = current_user_can('administrator');
142
+ }
143
+
144
+ $userMaxLevel = AAM::api()->getUser()->getMaxLevel();
145
+ $subjectMaxLevel = $this->subject->getMaxLevel();
146
+
147
+ if ($sameLevel) {
148
+ $allowed = $userMaxLevel >= $subjectMaxLevel;
149
+ } else {
150
+ $allowed = $userMaxLevel > $subjectMaxLevel;
151
+ }
152
+
153
+ return $allowed;
154
+ }
155
 
156
  /**
157
  * Get subject property
Application/Backend/View.php CHANGED
@@ -46,6 +46,7 @@ class AAM_Backend_View {
46
  AAM_Backend_Feature_Main_LogoutRedirect::register();
47
  AAM_Backend_Feature_Main_404Redirect::register();
48
  AAM_Backend_Feature_Main_Uri::register();
 
49
 
50
  AAM_Backend_Feature_Settings_Core::register();
51
  AAM_Backend_Feature_Settings_Content::register();
46
  AAM_Backend_Feature_Main_LogoutRedirect::register();
47
  AAM_Backend_Feature_Main_404Redirect::register();
48
  AAM_Backend_Feature_Main_Uri::register();
49
+ AAM_Backend_Feature_Main_Jwt::register();
50
 
51
  AAM_Backend_Feature_Settings_Core::register();
52
  AAM_Backend_Feature_Settings_Content::register();
Application/Backend/phtml/index.phtml CHANGED
@@ -248,7 +248,6 @@
248
  <th width="65%"><?php echo __('Role', AAM_KEY); ?></th>
249
  <th><?php echo __('Action', AAM_KEY); ?></th>
250
  <th>Level</th>
251
- <th>Expiration</th>
252
  </tr>
253
  </thead>
254
  <tbody></tbody>
@@ -266,10 +265,6 @@
266
  <label><?php echo __('Role Name', AAM_KEY); ?><span class="aam-asterix">*</span></label>
267
  <input type="text" class="form-control" name="name" placeholder="<?php echo __('Enter Role Name', AAM_KEY); ?>" />
268
  </div>
269
- <div class="form-group">
270
- <label><?php echo __('Role Expiration', AAM_KEY); ?> <a href="https://aamplugin.com/article/how-to-manage-wordpress-roles" target="_blank" data-toggle="tooltip" title="For how long user can have this role. Click to learn more."><i class="icon-help-circled"></i></a></label>
271
- <input type="text" class="form-control" name="expire" placeholder="<?php echo __('Enter Expiration Rule', AAM_KEY); ?>" />
272
- </div>
273
  <?php /* TODO: Rethink this filter */ do_action('aam-add-role-ui-action'); ?>
274
  <?php /* TODO: Rethink this filter */ echo apply_filters('aam-add-role-ui-filter', AAM_Backend_View::getInstance()->loadPartial('role-inheritance.phtml')); ?>
275
  </div>
@@ -293,10 +288,6 @@
293
  <label for="new-role-name"><?php echo __('Role Name', AAM_KEY); ?></label>
294
  <input type="text" class="form-control" id="edit-role-name" placeholder="<?php echo __('Enter Role Name', AAM_KEY); ?>" name="name" />
295
  </div>
296
- <div class="form-group">
297
- <label><?php echo __('Role Expiration', AAM_KEY); ?> <a href="https://aamplugin.com/article/how-to-manage-wordpress-roles" target="_blank" data-toggle="tooltip" title="For how long user can have this role. Click to learn more."><i class="icon-help-circled"></i></a></label>
298
- <input type="text" class="form-control" name="expire" id="edit-role-expiration" placeholder="<?php echo __('Enter Expiration Rule', AAM_KEY); ?>" />
299
- </div>
300
  <?php /* TODO: Rethink this filter */ do_action('aam-edit-role-ui-action'); ?>
301
  </div>
302
  <div class="modal-footer">
@@ -352,7 +343,6 @@
352
  <div class="modal-body">
353
  <ul class="nav nav-tabs" role="tablist">
354
  <li role="presentation" class="active"><a href="#edit-user-expiration" aria-controls="edit-user-expiration" role="tab" data-toggle="tab">Temporary Access</a></li>
355
- <li role="presentation"><a href="#edit-user-jwt" aria-controls="edit-user-jwt" role="tab" data-toggle="tab">JWT Auth Token</a></li>
356
  <li role="presentation"><a href="#edit-user-profile" aria-controls="edit-user-profile" role="tab" data-toggle="tab">Edit User</a></li>
357
  </ul>
358
 
@@ -380,23 +370,6 @@
380
  </select>
381
  </div>
382
  </div>
383
- <div role="tabpanel" class="tab-pane" id="edit-user-jwt">
384
- <div class="form-group">
385
- <p class="aam-info"><?php echo sprintf(__('User JWT token to authentication user without a need for entering username/password. To learn more about JWT authentication, please refer to %sHow to authenticate WordPress user with JWT token%s article.', AAM_KEY), '<a href="https://aamplugin.com/article/how-to-authenticate-wordpress-user-with-jwt-token" target="_blank">', '</a>'); ?></p>
386
- <div class="form-group">
387
- <label for="user-auth-url"><?php echo __('JWT Token (for any API calls)', AAM_KEY); ?></label>
388
- <textarea class="form-control" id="user-auth-jwt" readonly rows="5"></textarea>
389
- </div>
390
-
391
- <hr/>
392
-
393
- <div class="form-group">
394
- <label for="user-auth-url"><?php echo __('User Login URL (with JWT token)', AAM_KEY); ?></label>
395
- <textarea class="form-control" id="user-auth-url" data-url="<?php echo add_query_arg('aam-jwt', '%s', site_url()); ?>" readonly rows="5"></textarea>
396
- <small><?php echo __('With this URL user will be automatically logged in until the time defined on the "Temporary Access" tab.', AAM_KEY); ?></small>
397
- </div>
398
- </div>
399
- </div>
400
  <div role="tabpanel" class="tab-pane" id="edit-user-profile">
401
  <p class="aam-info"><?php echo __("To manage user profile, click on the button below.", AAM_KEY); ?></p>
402
  <p class="text-center">
248
  <th width="65%"><?php echo __('Role', AAM_KEY); ?></th>
249
  <th><?php echo __('Action', AAM_KEY); ?></th>
250
  <th>Level</th>
 
251
  </tr>
252
  </thead>
253
  <tbody></tbody>
265
  <label><?php echo __('Role Name', AAM_KEY); ?><span class="aam-asterix">*</span></label>
266
  <input type="text" class="form-control" name="name" placeholder="<?php echo __('Enter Role Name', AAM_KEY); ?>" />
267
  </div>
 
 
 
 
268
  <?php /* TODO: Rethink this filter */ do_action('aam-add-role-ui-action'); ?>
269
  <?php /* TODO: Rethink this filter */ echo apply_filters('aam-add-role-ui-filter', AAM_Backend_View::getInstance()->loadPartial('role-inheritance.phtml')); ?>
270
  </div>
288
  <label for="new-role-name"><?php echo __('Role Name', AAM_KEY); ?></label>
289
  <input type="text" class="form-control" id="edit-role-name" placeholder="<?php echo __('Enter Role Name', AAM_KEY); ?>" name="name" />
290
  </div>
 
 
 
 
291
  <?php /* TODO: Rethink this filter */ do_action('aam-edit-role-ui-action'); ?>
292
  </div>
293
  <div class="modal-footer">
343
  <div class="modal-body">
344
  <ul class="nav nav-tabs" role="tablist">
345
  <li role="presentation" class="active"><a href="#edit-user-expiration" aria-controls="edit-user-expiration" role="tab" data-toggle="tab">Temporary Access</a></li>
 
346
  <li role="presentation"><a href="#edit-user-profile" aria-controls="edit-user-profile" role="tab" data-toggle="tab">Edit User</a></li>
347
  </ul>
348
 
370
  </select>
371
  </div>
372
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
373
  <div role="tabpanel" class="tab-pane" id="edit-user-profile">
374
  <p class="aam-info"><?php echo __("To manage user profile, click on the button below.", AAM_KEY); ?></p>
375
  <p class="text-center">
Application/Backend/phtml/main/jwt.phtml ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if (defined('AAM_KEY')) { ?>
2
+ <div class="aam-feature" id="jwt-content">
3
+ <?php $subject = AAM_Backend_Subject::getInstance(); ?>
4
+
5
+ <div class="row">
6
+ <div class="col-xs-12">
7
+ <p class="aam-info">
8
+ <?php echo sprintf(AAM_Backend_View_Helper::preparePhrase('Manage list of all valid JWT tokens to the website for [%s] account. For more information about JWT tokens please refer to the %sUltimate guide to WordPress JWT authentication%s article.', 'b'), AAM_Backend_Subject::getInstance()->getName(), '<a href="https://aamplugin.com/article/ultimate-guide-to-wordpress-jwt-authentication" target="_blank">', '</a>'); ?>
9
+ </p>
10
+ </div>
11
+ </div>
12
+
13
+ <div class="row">
14
+ <div class="col-xs-12">
15
+ <table id="jwt-list" class="table table-striped table-bordered">
16
+ <thead>
17
+ <tr>
18
+ <th>Token</th>
19
+ <th>URL</th>
20
+ <th width="8%">&nbsp;</th>
21
+ <th width="70%"><?php echo __('Expires', AAM_KEY); ?></th>
22
+ <th><?php echo __('Actions', AAM_KEY); ?></th>
23
+ </tr>
24
+ </thead>
25
+ <tbody></tbody>
26
+ </table>
27
+ </div>
28
+ </div>
29
+
30
+ <div class="modal fade" id="create-jwt-modal" tabindex="-1" role="dialog">
31
+ <div class="modal-dialog" role="document">
32
+ <div class="modal-content">
33
+ <div class="modal-header">
34
+ <button type="button" class="close" data-dismiss="modal" aria-label="<?php echo __('Close', AAM_KEY); ?>"><span aria-hidden="true">&times;</span></button>
35
+ <h4 class="modal-title"><?php echo __('Create JWT Token', AAM_KEY); ?></h4>
36
+ </div>
37
+ <div class="modal-body">
38
+ <div class="form-group aam-bordered">
39
+ <label for="jwt-expiration-datapicker" class="aam-block">
40
+ <?php echo __('JWT Expires', AAM_KEY); ?>
41
+ </label>
42
+ <div id="jwt-expiration-datapicker"></div>
43
+ <input type="hidden" id="jwt-expires" />
44
+ </div>
45
+
46
+ <div class="form-group aam-outer-top-xs">
47
+ <label for="jwt-token-preview" class="aam-block">
48
+ <?php echo __('JWT Token (for any API calls)', AAM_KEY); ?>
49
+ <a href="#" class="aam-copy-clipboard" data-clipboard-target="#jwt-token-preview"><?php echo __('Copy to clipboard', AAM_KEY); ?></a>
50
+ </label>
51
+ <textarea class="form-control" id="jwt-token-preview" readonly rows="5"></textarea>
52
+ </div>
53
+
54
+ <hr/>
55
+
56
+ <div class="form-group">
57
+ <label for="jwt-url-preview" class="aam-block">
58
+ <?php echo __('Account Login URL (with JWT token)', AAM_KEY); ?>
59
+ <a href="#" class="aam-copy-clipboard" data-clipboard-target="#jwt-url-preview"><?php echo __('Copy to clipboard', AAM_KEY); ?></a>
60
+ </label>
61
+ <textarea class="form-control" id="jwt-url-preview" data-url="<?php echo add_query_arg('aam-jwt', '%s', site_url()); ?>" readonly rows="5"></textarea>
62
+ <small><?php echo __('With this URL account will be automatically logged in until the time defined on the "Temporary Access" tab.', AAM_KEY); ?></small>
63
+ </div>
64
+ </div>
65
+ <div class="modal-footer">
66
+ <button type="button" class="btn btn-success" id="create-jwt-btn"><?php echo __('Create', AAM_KEY); ?></button>
67
+ <button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
68
+ </div>
69
+ </div>
70
+ </div>
71
+ </div>
72
+
73
+ <div class="modal fade" id="view-jwt-modal" tabindex="-1" role="dialog">
74
+ <div class="modal-dialog" role="document">
75
+ <div class="modal-content">
76
+ <div class="modal-header">
77
+ <button type="button" class="close" data-dismiss="modal" aria-label="<?php echo __('Close', AAM_KEY); ?>"><span aria-hidden="true">&times;</span></button>
78
+ <h4 class="modal-title"><?php echo __('View JWT Token', AAM_KEY); ?></h4>
79
+ </div>
80
+ <div class="modal-body">
81
+ <div class="form-group">
82
+ <label for="view-jwt-token" class="aam-block">
83
+ <?php echo __('JWT Token (for any API calls)', AAM_KEY); ?>
84
+ <a href="#" class="aam-copy-clipboard" data-clipboard-target="#view-jwt-token"><?php echo __('Copy to clipboard', AAM_KEY); ?></a>
85
+ </label>
86
+ <textarea class="form-control" id="view-jwt-token" readonly rows="5"></textarea>
87
+ </div>
88
+
89
+ <hr/>
90
+
91
+ <div class="form-group">
92
+ <label for="view-jwt-url" class="aam-block">
93
+ <?php echo __('Account Login URL (with JWT token)', AAM_KEY); ?>
94
+ <a href="#" class="aam-copy-clipboard" data-clipboard-target="#view-jwt-url"><?php echo __('Copy to clipboard', AAM_KEY); ?></a>
95
+ </label>
96
+ <textarea class="form-control" id="view-jwt-url" readonly rows="5"></textarea>
97
+ <small><?php echo __('Use this URL to authenticate account without the need to enter username/password.', AAM_KEY); ?></small>
98
+ </div>
99
+ </div>
100
+ <div class="modal-footer">
101
+ <button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
102
+ </div>
103
+ </div>
104
+ </div>
105
+ </div>
106
+
107
+ <div class="modal fade" id="delete-jwt-modal" tabindex="-1" role="dialog">
108
+ <div class="modal-dialog" role="document">
109
+ <div class="modal-content">
110
+ <div class="modal-header">
111
+ <button type="button" class="close" data-dismiss="modal" aria-label="<?php echo __('Close', AAM_KEY); ?>"><span aria-hidden="true">&times;</span></button>
112
+ <h4 class="modal-title"><?php echo __('Delete JWT Token', AAM_KEY); ?></h4>
113
+ </div>
114
+ <div class="modal-body">
115
+ <p class="alert alert-danger text-larger"><?php echo __('You are about to delete already issued JWT token. Any application or person that has this token, will no longer be able to use it. Please confirm.') ?></p>
116
+ </div>
117
+ <div class="modal-footer">
118
+ <button type="button" class="btn btn-danger" id="jwt-delete-btn"><?php echo __('Delete', AAM_KEY); ?></button>
119
+ <button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
120
+ </div>
121
+ </div>
122
+ </div>
123
+ </div>
124
+
125
+ </div>
126
+ <?php }
Application/Backend/phtml/main/menu.phtml CHANGED
@@ -56,13 +56,13 @@
56
  <?php if ($submenu['id'] == 'index.php') { ?>
57
  <div class="col-xs-12 col-md-6 aam-submenu-item">
58
  <label for="menu-item-<?php echo $i . $j; ?>">
59
- <u><?php echo $submenu['name']; ?></u><small class="aam-menu-capability"><?php echo __('Cap:', AAM_KEY), ' <b>', $submenu['capability']; ?></b></small></label>
60
  <a href="#dashboard-lockout-modal" data-toggle="modal"><i class="icon-help-circled"></i></a>
61
  </div>
62
  <?php } else { ?>
63
  <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>
56
  <?php if ($submenu['id'] == 'index.php') { ?>
57
  <div class="col-xs-12 col-md-6 aam-submenu-item">
58
  <label for="menu-item-<?php echo $i . $j; ?>">
59
+ <?php echo $submenu['name']; ?><small class="aam-menu-capability"><?php echo __('Cap:', AAM_KEY), ' <b>', $submenu['capability']; ?></b></small></label>
60
  <a href="#dashboard-lockout-modal" data-toggle="modal"><i class="icon-help-circled"></i></a>
61
  </div>
62
  <?php } else { ?>
63
  <div class="col-xs-12 col-md-6 aam-submenu-item">
64
  <label for="menu-item-<?php echo $i . $j; ?>">
65
+ <?php echo $submenu['name']; ?>
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>
Application/Backend/phtml/main/metabox.phtml CHANGED
@@ -61,7 +61,7 @@
61
  <?php foreach ($metaboxes as $metabox) { ?>
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"' : ''); ?> />
61
  <?php foreach ($metaboxes as $metabox) { ?>
62
  <div class="col-xs-12 col-md-6 aam-submenu-item">
63
  <label for="metabox-<?php echo $screen; ?>-<?php echo $metabox['id']; ?>">
64
+ <?php echo $metabox['title']; ?>
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"' : ''); ?> />
Application/Backend/phtml/main/toolbar.phtml CHANGED
@@ -51,7 +51,7 @@
51
  <?php foreach($this->getAllChildren($branch) as $child) { ?>
52
  <div class="col-xs-12 aam-submenu-item">
53
  <label for="toolbar-<?php echo $child->id; ?>">
54
- <u><?php echo $this->normalizeTitle($child); ?></u>
55
  <small class="aam-menu-capability"><?php echo __('URI:', AAM_KEY); ?> <b><?php echo str_replace(site_url(), '', $child->href); ?></b></small>
56
  <small class="aam-menu-capability"><?php echo __('ID:', AAM_KEY); ?> <b><?php echo esc_js($child->id); ?></b></small>
57
  </label>
51
  <?php foreach($this->getAllChildren($branch) as $child) { ?>
52
  <div class="col-xs-12 aam-submenu-item">
53
  <label for="toolbar-<?php echo $child->id; ?>">
54
+ <?php echo $this->normalizeTitle($child); ?>
55
  <small class="aam-menu-capability"><?php echo __('URI:', AAM_KEY); ?> <b><?php echo str_replace(site_url(), '', $child->href); ?></b></small>
56
  <small class="aam-menu-capability"><?php echo __('ID:', AAM_KEY); ?> <b><?php echo esc_js($child->id); ?></b></small>
57
  </label>
Application/Backend/phtml/user/multiple-roles.phtml CHANGED
@@ -1,30 +1,32 @@
1
  <?php if (defined('AAM_KEY')) { ?>
2
- <table class="form-table">
3
- <tr>
4
- <th><?php echo esc_html('User Roles', AAM_KEY); ?></th>
5
- <td>
6
- <div class="wp-tab-panel">
7
- <ul>
8
- <?php foreach (get_editable_roles() as $id => $role) { ?>
9
- <li>
10
- <label>
11
- <input type="checkbox" name="aam_user_roles[]" value="<?php echo esc_attr($id); ?>" <?php checked(in_array($id, $user->roles)); ?> />
12
- <?php echo esc_html(translate_user_role($role['name'])); ?>
13
- </label>
14
- </li>
15
- <?php } ?>
16
- </ul>
17
- </div>
18
- </td>
19
- </tr>
20
- </table>
 
21
 
22
- <!-- Remove standard WordPress roles selector-->
23
- <script>
24
- (function($) {
25
- $(document).ready(function(){
26
- $('.user-role-wrap').remove();
27
- });
28
- })(jQuery);
29
- </script>
 
30
  <?php } ?>
1
  <?php if (defined('AAM_KEY')) { ?>
2
+ <?php if ( !IS_PROFILE_PAGE && !is_network_admin() && current_user_can('promote_user', $user->ID)) { ?>
3
+ <table class="form-table">
4
+ <tr>
5
+ <th><?php echo esc_html('User Roles', AAM_KEY); ?></th>
6
+ <td>
7
+ <div class="wp-tab-panel">
8
+ <ul>
9
+ <?php foreach (get_editable_roles() as $id => $role) { ?>
10
+ <li>
11
+ <label>
12
+ <input type="checkbox" name="aam_user_roles[]" value="<?php echo esc_attr($id); ?>" <?php checked(in_array($id, $user->roles)); ?> />
13
+ <?php echo esc_html(translate_user_role($role['name'])); ?>
14
+ </label>
15
+ </li>
16
+ <?php } ?>
17
+ </ul>
18
+ </div>
19
+ </td>
20
+ </tr>
21
+ </table>
22
 
23
+ <!-- Remove standard WordPress roles selector-->
24
+ <script>
25
+ (function($) {
26
+ $(document).ready(function(){
27
+ $('.user-role-wrap').remove();
28
+ });
29
+ })(jQuery);
30
+ </script>
31
+ <?php } ?>
32
  <?php } ?>
Application/Core/Compatibility.php CHANGED
@@ -12,10 +12,31 @@
12
  *
13
  * @package AAM
14
  * @author Vasyl Martyniuk <vasyl@vasyltech.com>
15
- * @todo Remove Feb 2018
16
  */
17
  class AAM_Core_Compatibility {
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  /**
20
  * Convert config to the Policy Config
21
  *
@@ -271,4 +292,16 @@ class AAM_Core_Compatibility {
271
  }
272
  }
273
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  }
12
  *
13
  * @package AAM
14
  * @author Vasyl Martyniuk <vasyl@vasyltech.com>
 
15
  */
16
  class AAM_Core_Compatibility {
17
 
18
+ /**
19
+ * Undocumented variable
20
+ *
21
+ * @var [type]
22
+ */
23
+ protected static $instance = null;
24
+
25
+ /**
26
+ * Compatibility between post actions and policy actions
27
+ *
28
+ * @param [type] $action
29
+ * @param [type] $effect
30
+ * @return void
31
+ */
32
+ public static function convertPolicyAction($action, $effect) {
33
+ return array(
34
+ "frontend.{$action}" => $effect,
35
+ "backend.{$action}" => $effect,
36
+ "api.{$action}" => $effect
37
+ );
38
+ }
39
+
40
  /**
41
  * Convert config to the Policy Config
42
  *
292
  }
293
  }
294
 
295
+ /**
296
+ * Undocumented function
297
+ *
298
+ * @return void
299
+ */
300
+ public static function getInstance() {
301
+ if (is_null(self::$instance)) {
302
+ self::$instance = new self;
303
+ }
304
+
305
+ return self::$instance;
306
+ }
307
  }
Application/Core/Gateway.php CHANGED
@@ -123,6 +123,15 @@ final class AAM_Core_Gateway {
123
  );
124
  }
125
 
 
 
 
 
 
 
 
 
 
126
  /**
127
  * Redirect request
128
  *
123
  );
124
  }
125
 
126
+ /**
127
+ * Compatibility manager
128
+ *
129
+ * @return AAM_Core_Compatibility
130
+ */
131
+ public function getCompatibilityManager() {
132
+ return AAM_Core_Compatibility::getInstance();
133
+ }
134
+
135
  /**
136
  * Redirect request
137
  *
Application/Core/Jwt/Auth.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 JWT Authentication handler
12
+ *
13
+ * @package AAM
14
+ * @author Vasyl Martyniuk <vasyl@vasyltech.com>
15
+ * @since v5.9.2
16
+ */
17
+ class AAM_Core_Jwt_Auth {
18
+
19
+ /**
20
+ * Authenticate user with username and password
21
+ *
22
+ * @param string $username
23
+ * @param string $password
24
+ *
25
+ * @return stdClass
26
+ *
27
+ * @access public
28
+ */
29
+ public function authenticateWithCredentials($username, $password) {
30
+ $response = array('error' => true);
31
+
32
+ // try to authenticate user with provided credentials
33
+ try {
34
+ $result = AAM_Core_Login::getInstance()->execute(
35
+ array(
36
+ 'user_login' => $username,
37
+ 'user_password' => $password
38
+ ),
39
+ false
40
+ );
41
+ } catch (Exception $ex) {
42
+ $result = array(
43
+ 'status' => 'failure',
44
+ 'reason' => $ex->getMessage(),
45
+ );
46
+ }
47
+
48
+ if ($result['status'] === 'success') { // generate token
49
+ try {
50
+ $issuer = new AAM_Core_Jwt_Issuer();
51
+ $token = $issuer->issueToken(
52
+ array('userId' => $result['user']->ID, 'revocable' => true)
53
+ );
54
+
55
+ $response = array(
56
+ 'jwt' => $token,
57
+ 'user' => $result['user']
58
+ );
59
+ } catch (Exception $ex) {
60
+ $response['reason'] = $ex->getMessage();
61
+ }
62
+ } else {
63
+ $response['reason'] = $result['reason'];
64
+ }
65
+
66
+ return (object) $response;
67
+ }
68
+
69
+ }
Application/Core/Jwt/Issuer.php ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 JWT Issuer
12
+ *
13
+ * @package AAM
14
+ * @author Vasyl Martyniuk <vasyl@vasyltech.com>
15
+ * @since v5.9.2
16
+ */
17
+ class AAM_Core_Jwt_Issuer {
18
+
19
+ /**
20
+ * Just a local cache
21
+ *
22
+ * @var array
23
+ */
24
+ protected $cache = array();
25
+
26
+ /**
27
+ * Validate JWT token
28
+ *
29
+ * @param string $token
30
+ *
31
+ * @return stdClass
32
+ *
33
+ * @access public
34
+ */
35
+ public function validateToken($token) {
36
+ try {
37
+ $headers = $this->extractTokenHeaders($token);
38
+
39
+ if (strpos($headers->alg, 'RS') === 0) {
40
+ $filepath = AAM_Core_Config::get('authentication.jwt.publicKeyPath');
41
+ $key = (is_readable($filepath) ? file_get_contents($filepath) : null);
42
+ } else {
43
+ $key = AAM_Core_Config::get('authentication.jwt.secret', SECURE_AUTH_KEY);
44
+ }
45
+
46
+ // Step #1. Check if token is actually valid
47
+ $response = Firebase\JWT\JWT::decode(
48
+ $token, $key, array_keys(Firebase\JWT\JWT::$supported_algs)
49
+ );
50
+
51
+ // Step #2. If token is "revocable", make sure that claimed user still has
52
+ // the token in the meta
53
+ if (!empty($response->revocable)) {
54
+ $tokens = $this->getUsersTokens($response->userId);
55
+ if (!in_array($token, $tokens, true)) {
56
+ throw new Exception(__('Token has been revoked', AAM_KEY));
57
+ }
58
+ }
59
+
60
+ $response->status = 'valid';
61
+ } catch (Exception $ex) {
62
+ $response = array_merge(array(
63
+ 'status' => 'invalid',
64
+ 'reason' => $ex->getMessage()
65
+ ), (array) $this->extractTokenClaims($token));
66
+ }
67
+
68
+ return (object) $response;
69
+ }
70
+
71
+ /**
72
+ * Issue JWT token
73
+ *
74
+ * @param array $args
75
+ * @param string $expires
76
+ *
77
+ * @return stdClass
78
+ *
79
+ * @access public
80
+ * @throws Exception
81
+ */
82
+ public function issueToken($args = array(), $expires = null) {
83
+ if (!empty($expires)) {
84
+ $time = DateTime::createFromFormat('m/d/Y, H:i O', $expires);
85
+ } else {
86
+ $time = new DateTime(
87
+ AAM_Core_Config::get('authentication.jwt.expires', '+24 hours')
88
+ );
89
+ }
90
+
91
+ $claims = apply_filters(
92
+ 'aam-jwt-claims-filter',
93
+ array_merge(
94
+ array(
95
+ "iat" => time(),
96
+ 'iss' => get_site_url(),
97
+ 'exp' => $time->format('m/d/Y, H:i O'),
98
+ 'jti' => $this->generateUuid()
99
+ ),
100
+ $args
101
+ )
102
+ );
103
+
104
+ // Determine algorithm and key
105
+ $attr = $this->getJWTSigningAttributes();
106
+
107
+ return (object) array(
108
+ 'token' => Firebase\JWT\JWT::encode($claims, $attr->key, $attr->alg),
109
+ 'claims' => $claims
110
+ );
111
+ }
112
+
113
+ /**
114
+ * Extract tokens headers
115
+ *
116
+ * @param string $token
117
+ *
118
+ * @return object
119
+ *
120
+ * @access public
121
+ */
122
+ public static function extractTokenHeaders($token) {
123
+ $parts = explode('.', $token);
124
+
125
+ try {
126
+ $headers = Firebase\JWT\JWT::jsonDecode(
127
+ Firebase\JWT\JWT::urlsafeB64Decode($parts[0])
128
+ );
129
+ } catch (Exception $ex) {
130
+ $headers = new stdClass();
131
+ }
132
+
133
+ return $headers;
134
+ }
135
+
136
+ /**
137
+ * Extract token claims
138
+ *
139
+ * @param string $token
140
+ *
141
+ * @return object
142
+ *
143
+ * @access public
144
+ */
145
+ public static function extractTokenClaims($token) {
146
+ $parts = explode('.', $token);
147
+
148
+ try {
149
+ $claims = Firebase\JWT\JWT::jsonDecode(
150
+ Firebase\JWT\JWT::urlsafeB64Decode($parts[1])
151
+ );
152
+ } catch (Exception $ex) {
153
+ $claims = new stdClass();
154
+ }
155
+
156
+ return $claims;
157
+ }
158
+
159
+ /**
160
+ * Get JWT attributes for signing
161
+ *
162
+ * @return object
163
+ *
164
+ * @access protected
165
+ */
166
+ protected function getJWTSigningAttributes() {
167
+ $alg = strtoupper(
168
+ AAM_Core_Config::get('authentication.jwt.algorithm', 'HS256')
169
+ );
170
+
171
+ if (strpos($alg, 'RS') === 0) {
172
+ $filepath = AAM_Core_Config::get('authentication.jwt.privateKeyPath');
173
+ $key = (is_readable($filepath) ? file_get_contents($filepath) : null);
174
+ } else {
175
+ $key = AAM_Core_Config::get('authentication.jwt.secret', SECURE_AUTH_KEY);
176
+ }
177
+
178
+ return (object) array(
179
+ 'alg' => $alg,
180
+ 'key' => $key
181
+ );
182
+ }
183
+
184
+ /**
185
+ * Get user's tokens
186
+ *
187
+ * @param int $userId
188
+ *
189
+ * @return array
190
+ *
191
+ * @access protected
192
+ */
193
+ protected function getUsersTokens($userId) {
194
+ if (!isset($this->cache[$userId])) {
195
+ $list = get_user_meta($userId, 'aam-jwt');
196
+ $this->cache[$userId] = is_array($list) ? $list : array();
197
+ }
198
+
199
+ return $this->cache[$userId];
200
+ }
201
+
202
+ /**
203
+ * Generate random uuid
204
+ *
205
+ * @return string
206
+ */
207
+ protected function generateUuid() {
208
+ return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
209
+ // 32 bits for "time_low"
210
+ mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
211
+
212
+ // 16 bits for "time_mid"
213
+ mt_rand( 0, 0xffff ),
214
+
215
+ // 16 bits for "time_hi_and_version",
216
+ // four most significant bits holds version number 4
217
+ mt_rand( 0, 0x0fff ) | 0x4000,
218
+
219
+ // 16 bits, 8 bits for "clk_seq_hi_res",
220
+ // 8 bits for "clk_seq_low",
221
+ // two most significant bits holds zero and one for variant DCE1.1
222
+ mt_rand( 0, 0x3fff ) | 0x8000,
223
+
224
+ // 48 bits for "node"
225
+ mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
226
+ );
227
+ }
228
+
229
+ }
Application/Core/Jwt/Manager.php ADDED
@@ -0,0 +1,356 @@