File "Identity.php"
Full Path: /home/rubycabfbt/www/wp-content/plugins/advanced-access-manager/application/Service/Identity.php
File size: 10.92 KB
MIME-type: text/x-php
Charset: utf-8
<?php
/**
* ======================================================================
* LICENSE: This file is subject to the terms and conditions defined in *
* file 'license.txt', which is part of this source code package. *
* ======================================================================
*/
/**
* Users & Roles (aka Identity) Governance service
*
* @package AAM
* @version 7.0.0
*/
class AAM_Service_Identity
{
use AAM_Service_BaseTrait;
/**
* WordPress core user caps mapped to AAM permissions
*
* @var array
* @access private
*
* @version 7.0.0
*/
private $_user_caps_to_listen = [
'edit_user' => 'edit_user',
'edit_user_meta' => 'edit_user',
'add_user_meta' => 'edit_user',
'delete_user_meta' => 'edit_user',
'promote_user' => 'promote_user',
'delete_user' => 'delete_user',
'remove_user' => 'delete_user'
];
/**
* Constructor
*
* @return void
* @access protected
*
* @version 7.0.4
*/
protected function __construct()
{
// Register RESTful API endpoints
AAM_Restful_Identity::bootstrap();
add_action('init', function() {
$this->initialize_hooks();
}, PHP_INT_MAX);
}
/**
* Initialize service hooks
*
* @return void
* @access protected
*
* @version 7.0.4
*/
protected function initialize_hooks()
{
if (is_admin()) {
// Hook that initialize the AAM UI part of the service
add_action('aam_initialize_ui_action', function () {
AAM_Backend_Feature_Main_Identity::register();
});
}
// Control the list of editable roles
add_filter('editable_roles', function($roles) {
return $this->_filter_editable_roles($roles);
}, 10, 1);
// Control list of roles that are listed above the Users table
add_filter('views_users', function($roles) {
return $this->_filter_views_users($roles);
}, 10, 1);
// Filter the list of users
add_action('pre_get_users', function($query) {
$this->_pre_get_users($query);
}, PHP_INT_MAX, 1);
// RESTful user querying
add_filter('rest_user_query', function($args) {
return $this->_rest_user_query($args);
}, PHP_INT_MAX, 1);
// Check if user has ability to perform certain task on other users
add_filter('map_meta_cap', function($caps, $cap, $_, $args) {
return $this->_map_meta_cap($caps, $cap, $args);
}, PHP_INT_MAX, 4);
// Additionally tap into password management
add_filter('show_password_fields', function($result, $user) {
return $this->_show_password_fields($result, $user);
}, 10, 2);
add_filter('allow_password_reset', function($result, $user_id) {
return $this->_allow_password_reset($result, $user_id);
}, 10, 2);
add_action('check_passwords', function($login, &$pwd1, &$pwd2) {
if (!AAM::api()->misc->is_admin()) {
$this->_check_passwords($login, $pwd1, $pwd2);
}
}, 10, 3);
add_filter('rest_pre_insert_user', function($data, $request) {
return $this->_rest_pre_insert_user($data, $request);
}, 10, 2);
}
/**
* Filter list of allowed roles
*
* @param array $roles
*
* @return array
* @access private
*
* @version 7.0.0
*/
private function _filter_editable_roles($roles)
{
$service = AAM::api()->roles();
foreach (array_keys($roles) as $slug) {
if ($service->is_hidden($slug)) {
unset($roles[$slug]);
}
}
return $roles;
}
/**
* Filter list of roles in the "Users" table
*
* The top list of roles requires some additional filtering
*
* @param array $views
*
* @return array
* @access private
*
* @version 7.0.0
*/
private function _filter_views_users($views)
{
$service = AAM::api()->roles();
foreach(array_keys($views) as $slug) {
if ($slug !== 'all' && $service->is_hidden($slug)) {
unset($views[$slug]);
}
}
return $views;
}
/**
* Filter user query
*
* Exclude all users that have higher user level
*
* @param object $query
*
* @return void
* @access private
*
* @version 7.0.0
*/
private function _pre_get_users($query)
{
$query->query_vars = $this->_prepare_filter_args($query->query_vars);
}
/**
* Filter users for RESTful API calls
*
* @param array $args
*
* @return array
* @access private
*
* @version 7.0.0
*/
private function _rest_user_query($args)
{
return $this->_prepare_filter_args($args);
}
/**
* Prepare filter arguments for the user query object
*
* @param array $args
*
* @return array
* @access private
*
* @version 7.0.1
*/
private function _prepare_filter_args($args)
{
// Identify the list roles & users that are hidden
$role_aggregate = AAM::api()->roles()->aggregate();
// Extract the list of user roles
$roles_not_in = [];
$users_not_in = [];
foreach($role_aggregate as $role_id => $perms) {
if (array_key_exists('list_user', $perms)
&& $perms['list_user']['effect'] === 'deny') {
array_push($roles_not_in, $role_id);
}
}
$user_aggregate = AAM::api()->users()->aggregate();
foreach($user_aggregate as $user_id => $perms) {
if (array_key_exists('list_user', $perms)
&& is_numeric($user_id)
&& $perms['list_user']['effect'] === 'deny') {
array_push($users_not_in, $user_id);
}
}
if (!empty($args['include'])) {
$include = array_diff((array) $args['include'], $users_not_in);
$args['include'] = empty($include) ? [ 0 ] : $include;
} elseif (!empty($args['exclude'])) {
$args['exclude'] = array_unique(array_merge(
(array) $args['exclude'],
$users_not_in
));
} else {
$args['exclude'] = $users_not_in;
}
// Customize the user query accordingly to the permissions defined above
if (!empty($args['role__in'])) {
// Remove roles that are hidden
$role__in = array_diff((array) $args['role__in'], $roles_not_in);
$args['role__in'] = empty($role__in) ? [ 'do_not_allow' ] : $role__in;
} elseif (!empty($args['role__not_in'])) {
$args['role__not_in'] = array_unique(array_merge(
(array) $args['role__not_in'],
$roles_not_in
));
} else {
$args['role__not_in'] = $roles_not_in;
}
return apply_filters('aam_user_query_args_filter', $args, [
'users' => $user_aggregate,
'roles' => $roles_not_in
]);
}
/**
* Check user capability
*
* This add additional layout on top of WordPress core functionality. Based on
* the capability passed in the $args array as "0" element, it performs additional
* check on user's ability to manage other users
*
* @param array $caps
* @param string $cap
* @param array $args
*
* @return array
* @access private
*
* @version 7.0.0
*/
private function _map_meta_cap($caps, $cap, $args)
{
$user_id = (isset($args[0]) ? $args[0] : null);
// If targeting user ID is not provided, no need to do anything
if (!empty($user_id)
&& in_array($cap, array_keys($this->_user_caps_to_listen), true)
) {
if (AAM::api()->users()->is_denied_to($user_id, $cap)) {
array_push($caps, 'do_not_allow');
}
}
return $caps;
}
/**
* Check if user can change other user's password
*
* This method determines if password change fields are going to be displayed
*
* @param boolean $result
* @param WP_User $user
*
* @return boolean
* @access private
*
* @version 7.0.0
*/
private function _show_password_fields($result, $user)
{
$is_profile = $user->ID === get_current_user_id();
$user->ID;
if (!$is_profile) {
$result = AAM::api()->users()->is_allowed_to(
$user, 'change_user_password'
);
}
return $result;
}
/**
* Check if user can reset other user's password
*
* This method determines if password reset fields are going to be displayed
*
* @param boolean $result
* @param int $user
*
* @return boolean
* @access private
*
* @version 7.0.0
*/
private function _allow_password_reset($result, $user_id)
{
$is_profile = ($user_id === get_current_user_id());
if (!$is_profile) {
$result = AAM::api()->users()->is_allowed_to(
$user_id, 'change_user_password'
);
}
return $result;
}
/**
* Check if user can update other user's password
*
* @param mixed $login
* @param string $password
* @param string $password2
*
* @return void
* @access private
*
* @version 7.0.0
*/
private function _check_passwords($login, &$password, &$password2)
{
$user = get_user_by('login', $login);
// Take into consideration scenario when new user is being created
if (is_a($user, 'WP_User')) {
$is_profile = $user->ID === get_current_user_id();
if (!$is_profile) {
if (AAM::api()->users()->is_denied_to($user, 'change_user_password')) {
$password = $password2 = null;
}
}
}
}
/**
* Check if user can update other user's password through RESTful API
*
* @param object $data
* @param WP_REST_Request $request
*
* @return object
* @access private
*
* @version 7.0.0
*/
private function _rest_pre_insert_user($data, $request)
{
$user = get_user_by('id', $request['id']);
// Take into consideration scenario when new user is being created
if (is_a($user, 'WP_User')) {
$is_profile = $user->ID === get_current_user_id();
if (!$is_profile && property_exists($data, 'user_pass')) {
if (AAM::api()->users()->is_denied_to($user, 'change_user_password')) {
unset($data->user_pass);
}
}
}
return $data;
}
}