PluginProbe ʕ •ᴥ•ʔ
Advanced Access Manager – Access Governance for WordPress / trunk
Advanced Access Manager – Access Governance for WordPress vtrunk
6.8.4 6.8.5 6.9.0 6.9.1 6.9.10 6.9.11 6.9.12 6.9.13 6.9.14 6.9.15 6.9.16 6.9.17 6.9.18 6.9.19 6.9.2 6.9.20 6.9.21 6.9.22 6.9.23 6.9.24 6.9.25 6.9.26 6.9.27 6.9.28 6.9.29 6.9.3 6.9.30 6.9.31 6.9.32 6.9.33 6.9.34 6.9.35 6.9.36 6.9.37 6.9.38 6.9.39 6.9.4 6.9.41 6.9.42 6.9.43 6.9.44 6.9.45 6.9.46 6.9.47 6.9.48 6.9.49 6.9.5 6.9.51 6.9.6 6.9.7 6.9.8 6.9.9 7.0.0 7.0.0-alpha.6 7.0.0-alpha.7 7.0.0-beta.1 7.0.0-rc1 7.0.0-rc2 7.0.0-rc3 7.0.1 7.0.10 7.0.11 7.0.2 7.0.3 7.0.4 7.0.5 7.0.6 7.0.7 7.0.8 7.0.9 7.1.0 7.1.1 trunk 3.0 4.0 4.0.1 4.1 4.2 4.3 4.4 4.4.1 4.5 4.6 4.6.1 4.6.2 4.7 4.7.1 4.7.2 4.7.5 4.7.6 4.8 4.8.1 4.9 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 4.9.5.1 4.9.5.2 5.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1 5.1.1 5.10 5.11 5.2 5.2.1 5.2.5 5.2.6 5.2.7 5.3 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.4 5.4.1 5.4.2 5.4.3 5.4.3.1 5.4.3.2 5.5 5.5.1 5.5.2 5.6 5.6.1 5.6.1.1 5.7 5.7.1 5.7.2 5.7.3 5.8 5.8.1 5.8.2 5.8.3 5.9 5.9.1 5.9.1.1 5.9.2 5.9.2.1 5.9.3 5.9.4 5.9.5 5.9.6 5.9.6.1 5.9.6.2 5.9.6.3 5.9.7 5.9.7.1 5.9.7.2 5.9.7.3 5.9.8 5.9.8.1 5.9.9 5.9.9.1 6.0.0 6.0.1 6.0.2 6.0.3 6.0.4 6.0.5 6.1.0 6.1.1 6.2.0 6.2.1 6.2.2 6.3.0 6.3.1 6.3.2 6.3.3 6.4.0 6.4.1 6.4.2 6.4.3 6.5.0 6.5.1 6.5.2 6.5.3 6.5.4 6.6.0 6.6.1 6.6.2 6.6.3 6.6.4 6.7.0 6.7.1 6.7.2 6.7.3 6.7.4 6.7.5 6.7.6 6.7.7 6.7.8 6.7.9 6.8.0 6.8.1 6.8.2 6.8.3
advanced-access-manager / application / Service / Identity.php
advanced-access-manager / application / Service Last commit date
Shortcode 4 months ago AccessDeniedRedirect.php 1 year ago AdminToolbar.php 1 year ago ApiRoute.php 1 year ago BackendMenu.php 1 year ago BaseTrait.php 1 year ago Capability.php 1 year ago Content.php 4 months ago Core.php 8 months ago Hooks.php 1 year ago Identity.php 1 month ago Jwt.php 1 month ago LoginRedirect.php 1 year ago LogoutRedirect.php 1 month ago Metaboxes.php 1 year ago NotFoundRedirect.php 1 year ago Policies.php 1 year ago SecureLogin.php 1 year ago SecurityAudit.php 1 year ago Shortcodes.php 4 months ago Urls.php 1 year ago Welcome.php 1 year ago Widgets.php 1 year ago
Identity.php
407 lines
1 <?php
2
3 /**
4 * ======================================================================
5 * LICENSE: This file is subject to the terms and conditions defined in *
6 * file 'license.txt', which is part of this source code package. *
7 * ======================================================================
8 */
9
10 /**
11 * Users & Roles (aka Identity) Governance service
12 *
13 * @package AAM
14 * @version 7.0.0
15 */
16 class AAM_Service_Identity
17 {
18
19 use AAM_Service_BaseTrait;
20
21 /**
22 * WordPress core user caps mapped to AAM permissions
23 *
24 * @var array
25 * @access private
26 *
27 * @version 7.0.0
28 */
29 private $_user_caps_to_listen = [
30 'edit_user' => 'edit_user',
31 'edit_user_meta' => 'edit_user',
32 'add_user_meta' => 'edit_user',
33 'delete_user_meta' => 'edit_user',
34 'promote_user' => 'promote_user',
35 'delete_user' => 'delete_user',
36 'remove_user' => 'delete_user'
37 ];
38
39 /**
40 * Constructor
41 *
42 * @return void
43 * @access protected
44 *
45 * @version 7.0.4
46 */
47 protected function __construct()
48 {
49 // Register RESTful API endpoints
50 AAM_Restful_Identity::bootstrap();
51
52 add_action('init', function() {
53 $this->initialize_hooks();
54 }, PHP_INT_MAX);
55 }
56
57 /**
58 * Initialize service hooks
59 *
60 * @return void
61 * @access protected
62 *
63 * @version 7.0.4
64 */
65 protected function initialize_hooks()
66 {
67 if (is_admin()) {
68 // Hook that initialize the AAM UI part of the service
69 add_action('aam_initialize_ui_action', function () {
70 AAM_Backend_Feature_Main_Identity::register();
71 });
72 }
73
74 // Control the list of editable roles
75 add_filter('editable_roles', function($roles) {
76 return $this->_filter_editable_roles($roles);
77 }, 10, 1);
78
79 // Control list of roles that are listed above the Users table
80 add_filter('views_users', function($roles) {
81 return $this->_filter_views_users($roles);
82 }, 10, 1);
83
84 // Filter the list of users
85 add_action('pre_get_users', function($query) {
86 $this->_pre_get_users($query);
87 }, PHP_INT_MAX, 1);
88
89 // RESTful user querying
90 add_filter('rest_user_query', function($args) {
91 return $this->_rest_user_query($args);
92 }, PHP_INT_MAX, 1);
93
94 // Check if user has ability to perform certain task on other users
95 add_filter('map_meta_cap', function($caps, $cap, $_, $args) {
96 return $this->_map_meta_cap($caps, $cap, $args);
97 }, PHP_INT_MAX, 4);
98
99 // Additionally tap into password management
100 add_filter('show_password_fields', function($result, $user) {
101 return $this->_show_password_fields($result, $user);
102 }, 10, 2);
103 add_filter('allow_password_reset', function($result, $user_id) {
104 return $this->_allow_password_reset($result, $user_id);
105 }, 10, 2);
106 add_action('check_passwords', function($login, &$pwd1, &$pwd2) {
107 if (!AAM::api()->misc->is_admin()) {
108 $this->_check_passwords($login, $pwd1, $pwd2);
109 }
110 }, 10, 3);
111 add_filter('rest_pre_insert_user', function($data, $request) {
112 return $this->_rest_pre_insert_user($data, $request);
113 }, 10, 2);
114 }
115
116 /**
117 * Filter list of allowed roles
118 *
119 * @param array $roles
120 *
121 * @return array
122 * @access private
123 *
124 * @version 7.0.0
125 */
126 private function _filter_editable_roles($roles)
127 {
128 $service = AAM::api()->roles();
129
130 foreach (array_keys($roles) as $slug) {
131 if ($service->is_hidden($slug)) {
132 unset($roles[$slug]);
133 }
134 }
135
136 return $roles;
137 }
138
139 /**
140 * Filter list of roles in the "Users" table
141 *
142 * The top list of roles requires some additional filtering
143 *
144 * @param array $views
145 *
146 * @return array
147 * @access private
148 *
149 * @version 7.0.0
150 */
151 private function _filter_views_users($views)
152 {
153 $service = AAM::api()->roles();
154
155 foreach(array_keys($views) as $slug) {
156 if (!in_array($slug, ['all', 'none']) && $service->is_hidden($slug)) {
157 unset($views[$slug]);
158 }
159 }
160
161 return $views;
162 }
163
164 /**
165 * Filter user query
166 *
167 * Exclude all users that have higher user level
168 *
169 * @param object $query
170 *
171 * @return void
172 * @access private
173 *
174 * @version 7.0.0
175 */
176 private function _pre_get_users($query)
177 {
178 $query->query_vars = $this->_prepare_filter_args($query->query_vars);
179 }
180
181 /**
182 * Filter users for RESTful API calls
183 *
184 * @param array $args
185 *
186 * @return array
187 * @access private
188 *
189 * @version 7.0.0
190 */
191 private function _rest_user_query($args)
192 {
193 return $this->_prepare_filter_args($args);
194 }
195
196 /**
197 * Prepare filter arguments for the user query object
198 *
199 * @param array $args
200 *
201 * @return array
202 * @access private
203 *
204 * @version 7.0.1
205 */
206 private function _prepare_filter_args($args)
207 {
208 // Identify the list roles & users that are hidden
209 $role_aggregate = AAM::api()->roles()->aggregate();
210
211 // Extract the list of user roles
212 $roles_not_in = [];
213 $users_not_in = [];
214
215 foreach($role_aggregate as $role_id => $perms) {
216 if (array_key_exists('list_user', $perms)
217 && $perms['list_user']['effect'] === 'deny') {
218 array_push($roles_not_in, $role_id);
219 }
220 }
221
222 $user_aggregate = AAM::api()->users()->aggregate();
223
224 foreach($user_aggregate as $user_id => $perms) {
225 if (array_key_exists('list_user', $perms)
226 && is_numeric($user_id)
227 && $perms['list_user']['effect'] === 'deny') {
228 array_push($users_not_in, $user_id);
229 }
230 }
231
232 if (!empty($args['include'])) {
233 $include = array_diff((array) $args['include'], $users_not_in);
234 $args['include'] = empty($include) ? [ 0 ] : $include;
235 } elseif (!empty($args['exclude'])) {
236 $args['exclude'] = array_unique(array_merge(
237 (array) $args['exclude'],
238 $users_not_in
239 ));
240 } else {
241 $args['exclude'] = $users_not_in;
242 }
243
244 // Customize the user query accordingly to the permissions defined above
245 if (!empty($args['role__in'])) {
246 // Remove roles that are hidden
247 $role__in = array_diff((array) $args['role__in'], $roles_not_in);
248 $args['role__in'] = empty($role__in) ? [ 'do_not_allow' ] : $role__in;
249 } elseif (!empty($args['role__not_in'])) {
250 $args['role__not_in'] = array_unique(array_merge(
251 (array) $args['role__not_in'],
252 $roles_not_in
253 ));
254 } else {
255 $args['role__not_in'] = $roles_not_in;
256 }
257
258 return apply_filters('aam_user_query_args_filter', $args, [
259 'users' => $user_aggregate,
260 'roles' => $roles_not_in
261 ]);
262 }
263
264 /**
265 * Check user capability
266 *
267 * This add additional layout on top of WordPress core functionality. Based on
268 * the capability passed in the $args array as "0" element, it performs additional
269 * check on user's ability to manage other users
270 *
271 * @param array $caps
272 * @param string $cap
273 * @param array $args
274 *
275 * @return array
276 * @access private
277 *
278 * @version 7.0.0
279 */
280 private function _map_meta_cap($caps, $cap, $args)
281 {
282 $user_id = (isset($args[0]) ? $args[0] : null);
283
284 // If targeting user ID is not provided, no need to do anything
285 if (!empty($user_id)
286 && in_array($cap, array_keys($this->_user_caps_to_listen), true)
287 ) {
288 if (AAM::api()->users()->is_denied_to($user_id, $cap)) {
289 array_push($caps, 'do_not_allow');
290 }
291 }
292
293 return $caps;
294 }
295
296 /**
297 * Check if user can change other user's password
298 *
299 * This method determines if password change fields are going to be displayed
300 *
301 * @param boolean $result
302 * @param WP_User $user
303 *
304 * @return boolean
305 * @access private
306 *
307 * @version 7.0.0
308 */
309 private function _show_password_fields($result, $user)
310 {
311 $is_profile = $user->ID === get_current_user_id();
312
313 $user->ID;
314
315 if (!$is_profile) {
316 $result = AAM::api()->users()->is_allowed_to(
317 $user, 'change_user_password'
318 );
319 }
320
321 return $result;
322 }
323
324 /**
325 * Check if user can reset other user's password
326 *
327 * This method determines if password reset fields are going to be displayed
328 *
329 * @param boolean $result
330 * @param int $user
331 *
332 * @return boolean
333 * @access private
334 *
335 * @version 7.0.0
336 */
337 private function _allow_password_reset($result, $user_id)
338 {
339 $is_profile = ($user_id === get_current_user_id());
340
341 if (!$is_profile) {
342 $result = AAM::api()->users()->is_allowed_to(
343 $user_id, 'change_user_password'
344 );
345 }
346
347 return $result;
348 }
349
350 /**
351 * Check if user can update other user's password
352 *
353 * @param mixed $login
354 * @param string $password
355 * @param string $password2
356 *
357 * @return void
358 * @access private
359 *
360 * @version 7.0.0
361 */
362 private function _check_passwords($login, &$password, &$password2)
363 {
364 $user = get_user_by('login', $login);
365
366 // Take into consideration scenario when new user is being created
367 if (is_a($user, 'WP_User')) {
368 $is_profile = $user->ID === get_current_user_id();
369
370 if (!$is_profile) {
371 if (AAM::api()->users()->is_denied_to($user, 'change_user_password')) {
372 $password = $password2 = null;
373 }
374 }
375 }
376 }
377
378 /**
379 * Check if user can update other user's password through RESTful API
380 *
381 * @param object $data
382 * @param WP_REST_Request $request
383 *
384 * @return object
385 * @access private
386 *
387 * @version 7.0.0
388 */
389 private function _rest_pre_insert_user($data, $request)
390 {
391 $user = get_user_by('id', $request['id']);
392
393 // Take into consideration scenario when new user is being created
394 if (is_a($user, 'WP_User')) {
395 $is_profile = $user->ID === get_current_user_id();
396
397 if (!$is_profile && property_exists($data, 'user_pass')) {
398 if (AAM::api()->users()->is_denied_to($user, 'change_user_password')) {
399 unset($data->user_pass);
400 }
401 }
402 }
403
404 return $data;
405 }
406
407 }