From 1a4e28818fad8f37434b00c6efa2edb10e337753 Mon Sep 17 00:00:00 2001 From: Ian Dunn Date: Wed, 2 May 2018 01:07:00 +0000 Subject: [PATCH] Privacy: Limit export and erasure to super admins on Multisite. Multisite networks have a variety of use cases, and in many of them single-site administrators are not trusted to take actions that affect the whole network, require making decisions about legal compliance, etc. By default, those actions should require super admin capabilities. Plugins can be used to override that behavior if a particular site's use case calls for it. Props allendav, jeremyfelt, iandunn. Fixes #43919. git-svn-id: https://develop.svn.wordpress.org/trunk@43085 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/ajax-actions.php | 5 +++-- src/wp-admin/includes/user.php | 18 ++++++++++++------ src/wp-includes/capabilities.php | 4 ++++ tests/phpunit/tests/user/capabilities.php | 4 ++++ 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/wp-admin/includes/ajax-actions.php b/src/wp-admin/includes/ajax-actions.php index 1a52e3e0fb..6d2f3e650f 100644 --- a/src/wp-admin/includes/ajax-actions.php +++ b/src/wp-admin/includes/ajax-actions.php @@ -4344,7 +4344,7 @@ function wp_ajax_wp_privacy_export_personal_data() { wp_send_json_error( __( 'Invalid request ID.' ) ); } - if ( ! current_user_can( 'manage_options' ) ) { + if ( ! current_user_can( 'export_others_personal_data' ) ) { wp_send_json_error( __( 'Invalid request.' ) ); } @@ -4522,7 +4522,8 @@ function wp_ajax_wp_privacy_erase_personal_data() { wp_send_json_error( __( 'Invalid request ID.' ) ); } - if ( ! current_user_can( 'delete_users' ) ) { + // Both capabilities are required to avoid confusion, see `_wp_personal_data_removal_page()`. + if ( ! current_user_can( 'erase_others_personal_data' ) || ! current_user_can( 'delete_users' ) ) { wp_send_json_error( __( 'Invalid request.' ) ); } diff --git a/src/wp-admin/includes/user.php b/src/wp-admin/includes/user.php index e242322e35..939ad167bd 100644 --- a/src/wp-admin/includes/user.php +++ b/src/wp-admin/includes/user.php @@ -785,8 +785,8 @@ function _wp_personal_data_cleanup_requests() { * @access private */ function _wp_personal_data_export_page() { - if ( ! current_user_can( 'manage_options' ) ) { - wp_die( esc_html__( 'Sorry, you are not allowed to manage privacy on this site.' ) ); + if ( ! current_user_can( 'export_others_personal_data' ) ) { + wp_die( __( 'Sorry, you are not allowed to export personal data on this site.' ) ); } _wp_personal_data_handle_actions(); @@ -850,8 +850,14 @@ function _wp_personal_data_export_page() { * @access private */ function _wp_personal_data_removal_page() { - if ( ! current_user_can( 'delete_users' ) ) { - wp_die( esc_html__( 'Sorry, you are not allowed to manage privacy on this site.' ) ); + /* + * Require both caps in order to make it explicitly clear that delegating + * erasure from network admins to single-site admins will give them the + * ability to affect global users, rather than being limited to the site + * that they administer. + */ + if ( ! current_user_can( 'erase_others_personal_data' ) || ! current_user_can( 'delete_users' ) ) { + wp_die( __( 'Sorry, you are not allowed to erase data on this site.' ) ); } _wp_personal_data_handle_actions(); @@ -917,8 +923,8 @@ function _wp_personal_data_removal_page() { * @access private */ function _wp_privacy_hook_requests_page() { - add_submenu_page( 'tools.php', __( 'Export Personal Data' ), __( 'Export Personal Data' ), 'manage_options', 'export_personal_data', '_wp_personal_data_export_page' ); - add_submenu_page( 'tools.php', __( 'Remove Personal Data' ), __( 'Remove Personal Data' ), 'manage_options', 'remove_personal_data', '_wp_personal_data_removal_page' ); + add_submenu_page( 'tools.php', __( 'Export Personal Data' ), __( 'Export Personal Data' ), 'export_others_personal_data', 'export_personal_data', '_wp_personal_data_export_page' ); + add_submenu_page( 'tools.php', __( 'Remove Personal Data' ), __( 'Remove Personal Data' ), 'erase_others_personal_data', 'remove_personal_data', '_wp_personal_data_removal_page' ); } // TODO: move the following classes in new files. diff --git a/src/wp-includes/capabilities.php b/src/wp-includes/capabilities.php index a81761db15..efc3dd2e4c 100644 --- a/src/wp-includes/capabilities.php +++ b/src/wp-includes/capabilities.php @@ -555,6 +555,10 @@ function map_meta_cap( $cap, $user_id ) { $caps[] = 'update_core'; } break; + case 'export_others_personal_data': + case 'erase_others_personal_data': + $caps[] = is_multisite() ? 'manage_network' : 'manage_options'; + break; default: // Handle meta capabilities for custom post types. global $post_type_meta_caps; diff --git a/tests/phpunit/tests/user/capabilities.php b/tests/phpunit/tests/user/capabilities.php index 85c5d995d3..7b086d1384 100644 --- a/tests/phpunit/tests/user/capabilities.php +++ b/tests/phpunit/tests/user/capabilities.php @@ -237,6 +237,8 @@ class Tests_User_Capabilities extends WP_UnitTestCase { 'update_languages' => array( 'administrator' ), 'deactivate_plugins' => array( 'administrator' ), 'upgrade_php' => array( 'administrator' ), + 'export_others_personal_data' => array( 'administrator' ), + 'erase_others_personal_data' => array( 'administrator' ), 'edit_categories' => array( 'administrator', 'editor' ), 'delete_categories' => array( 'administrator', 'editor' ), @@ -269,6 +271,8 @@ class Tests_User_Capabilities extends WP_UnitTestCase { 'update_languages' => array(), 'deactivate_plugins' => array(), 'upgrade_php' => array(), + 'export_others_personal_data' => array( '' ), + 'erase_others_personal_data' => array( '' ), 'customize' => array( 'administrator' ), 'delete_site' => array( 'administrator' ),