From c27098a3a37d101b41f360228b8e34018d8df502 Mon Sep 17 00:00:00 2001 From: TimothyBlynJacobs Date: Sun, 31 Jan 2021 19:03:59 +0000 Subject: [PATCH] App Passwords: Introduce fine grained capabilities. Previously, all permission checks for using app passwords were implemented using `edit_user`. This commit introduces a series of more fine grained meta capabilities that should be used instead: `create_app_password`, `list_app_passwords`, `read_app_password`, `edit_app_password`, `delete_app_password` and `delete_app_passwords`. These capabilities all map to `edit_user` by default, but may now be customized by developers. Props johnbillion, TimothyBlynJacobs. Fixes #51703. Built from https://develop.svn.wordpress.org/trunk@50114 git-svn-id: http://core.svn.wordpress.org/trunk@49793 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/capabilities.php | 8 ++ ...-rest-application-passwords-controller.php | 99 +++++++++++++++++-- wp-includes/version.php | 2 +- 3 files changed, 102 insertions(+), 7 deletions(-) diff --git a/wp-includes/capabilities.php b/wp-includes/capabilities.php index 22eff2b1e3..26c09a1944 100644 --- a/wp-includes/capabilities.php +++ b/wp-includes/capabilities.php @@ -592,6 +592,14 @@ function map_meta_cap( $cap, $user_id, ...$args ) { case 'manage_privacy_options': $caps[] = is_multisite() ? 'manage_network' : 'manage_options'; break; + case 'create_app_password': + case 'list_app_passwords': + case 'read_app_password': + case 'edit_app_password': + case 'delete_app_passwords': + case 'delete_app_password': + $caps = map_meta_cap( 'edit_user', $user_id, $args[0] ); + break; default: // Handle meta capabilities for custom post types. global $post_type_meta_caps; diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php index c3474df09a..84fa144800 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php @@ -110,7 +110,21 @@ class WP_REST_Application_Passwords_Controller extends WP_REST_Controller { * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { - return $this->do_permissions_check( $request ); + $user = $this->get_user( $request ); + + if ( is_wp_error( $user ) ) { + return $user; + } + + if ( ! current_user_can( 'list_app_passwords', $user->ID ) ) { + return new WP_Error( + 'rest_cannot_list_application_passwords', + __( 'Sorry, you are not allowed to list application passwords for this user.' ), + array( 'status' => rest_authorization_required_code() ) + ); + } + + return true; } /** @@ -149,7 +163,21 @@ class WP_REST_Application_Passwords_Controller extends WP_REST_Controller { * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { - return $this->do_permissions_check( $request ); + $user = $this->get_user( $request ); + + if ( is_wp_error( $user ) ) { + return $user; + } + + if ( ! current_user_can( 'read_app_password', $user->ID, $request['uuid'] ) ) { + return new WP_Error( + 'rest_cannot_read_application_password', + __( 'Sorry, you are not allowed to read this application password.' ), + array( 'status' => rest_authorization_required_code() ) + ); + } + + return true; } /** @@ -179,7 +207,21 @@ class WP_REST_Application_Passwords_Controller extends WP_REST_Controller { * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise. */ public function create_item_permissions_check( $request ) { - return $this->do_permissions_check( $request ); + $user = $this->get_user( $request ); + + if ( is_wp_error( $user ) ) { + return $user; + } + + if ( ! current_user_can( 'create_app_password', $user->ID ) ) { + return new WP_Error( + 'rest_cannot_create_application_passwords', + __( 'Sorry, you are not allowed to create application passwords for this user.' ), + array( 'status' => rest_authorization_required_code() ) + ); + } + + return true; } /** @@ -248,7 +290,21 @@ class WP_REST_Application_Passwords_Controller extends WP_REST_Controller { * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise. */ public function update_item_permissions_check( $request ) { - return $this->do_permissions_check( $request ); + $user = $this->get_user( $request ); + + if ( is_wp_error( $user ) ) { + return $user; + } + + if ( ! current_user_can( 'edit_app_password', $user->ID, $request['uuid'] ) ) { + return new WP_Error( + 'rest_cannot_edit_application_password', + __( 'Sorry, you are not allowed to edit this application password.' ), + array( 'status' => rest_authorization_required_code() ) + ); + } + + return true; } /** @@ -308,7 +364,21 @@ class WP_REST_Application_Passwords_Controller extends WP_REST_Controller { * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. */ public function delete_items_permissions_check( $request ) { - return $this->do_permissions_check( $request ); + $user = $this->get_user( $request ); + + if ( is_wp_error( $user ) ) { + return $user; + } + + if ( ! current_user_can( 'delete_app_passwords', $user->ID ) ) { + return new WP_Error( + 'rest_cannot_delete_application_passwords', + __( 'Sorry, you are not allowed to delete application passwords for this user.' ), + array( 'status' => rest_authorization_required_code() ) + ); + } + + return true; } /** @@ -349,7 +419,21 @@ class WP_REST_Application_Passwords_Controller extends WP_REST_Controller { * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. */ public function delete_item_permissions_check( $request ) { - return $this->do_permissions_check( $request ); + $user = $this->get_user( $request ); + + if ( is_wp_error( $user ) ) { + return $user; + } + + if ( ! current_user_can( 'delete_app_password', $user->ID, $request['uuid'] ) ) { + return new WP_Error( + 'rest_cannot_delete_application_password', + __( 'Sorry, you are not allowed to delete this application password.' ), + array( 'status' => rest_authorization_required_code() ) + ); + } + + return true; } /** @@ -457,11 +541,14 @@ class WP_REST_Application_Passwords_Controller extends WP_REST_Controller { * Performs a permissions check for the request. * * @since 5.6.0 + * @deprecated 5.7.0 Use `edit_user` directly or one of the specific meta capabilities introduced in 5.7.0. * * @param WP_REST_Request $request * @return true|WP_Error */ protected function do_permissions_check( $request ) { + _deprecated_function( __METHOD__, '5.7.0' ); + $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { diff --git a/wp-includes/version.php b/wp-includes/version.php index 58bd3cac77..17f94ea6de 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -13,7 +13,7 @@ * * @global string $wp_version */ -$wp_version = '5.7-alpha-50113'; +$wp_version = '5.7-alpha-50114'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.