From b16c8874f2bd3271dc0eb4d4c0ee4df1efaaaf21 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Fri, 13 Jul 2018 06:28:29 +0000 Subject: [PATCH] REST API: Tweak permission checks for taxonomy and term endpoints To match behaviour in the Classic Editor, we need to slightly loosen permissions on taxonomy and term endpoints. This allows users to create terms to assign to a post that they're editing. Merges [43440] to the 4.9 branch. Props danielbachhuber. Fixes #44096. git-svn-id: https://develop.svn.wordpress.org/branches/4.9@43443 602fd350-edb4-49c9-b593-d223f7449a82 --- .../class-wp-rest-taxonomies-controller.php | 6 +- .../class-wp-rest-terms-controller.php | 5 +- .../rest-api/rest-categories-controller.php | 30 ++++++++-- .../tests/rest-api/rest-tags-controller.php | 56 ++++++++++++++----- .../rest-api/rest-taxonomies-controller.php | 17 ++++++ 5 files changed, 91 insertions(+), 23 deletions(-) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php index 9720a20945..0af4ec4e97 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php @@ -80,7 +80,7 @@ class WP_REST_Taxonomies_Controller extends WP_REST_Controller { $taxonomies = get_taxonomies( '', 'objects' ); } foreach ( $taxonomies as $taxonomy ) { - if ( ! empty( $taxonomy->show_in_rest ) && current_user_can( $taxonomy->cap->manage_terms ) ) { + if ( ! empty( $taxonomy->show_in_rest ) && current_user_can( $taxonomy->cap->assign_terms ) ) { return true; } } @@ -109,7 +109,7 @@ class WP_REST_Taxonomies_Controller extends WP_REST_Controller { } $data = array(); foreach ( $taxonomies as $tax_type => $value ) { - if ( empty( $value->show_in_rest ) || ( 'edit' === $request['context'] && ! current_user_can( $value->cap->manage_terms ) ) ) { + if ( empty( $value->show_in_rest ) || ( 'edit' === $request['context'] && ! current_user_can( $value->cap->assign_terms ) ) ) { continue; } $tax = $this->prepare_item_for_response( $value, $request ); @@ -141,7 +141,7 @@ class WP_REST_Taxonomies_Controller extends WP_REST_Controller { if ( empty( $tax_obj->show_in_rest ) ) { return false; } - if ( 'edit' === $request['context'] && ! current_user_can( $tax_obj->cap->manage_terms ) ) { + if ( 'edit' === $request['context'] && ! current_user_can( $tax_obj->cap->assign_terms ) ) { return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to manage terms in this taxonomy.' ), array( 'status' => rest_authorization_required_code() ) ); } } diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php index 477df8ba48..3342742b93 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php @@ -376,7 +376,10 @@ class WP_REST_Terms_Controller extends WP_REST_Controller { } $taxonomy_obj = get_taxonomy( $this->taxonomy ); - if ( ! current_user_can( $taxonomy_obj->cap->edit_terms ) ) { + if ( ( is_taxonomy_hierarchical( $this->taxonomy ) + && ! current_user_can( $taxonomy_obj->cap->edit_terms ) ) + || ( ! is_taxonomy_hierarchical( $this->taxonomy ) + && ! current_user_can( $taxonomy_obj->cap->assign_terms ) ) ) { return new WP_Error( 'rest_cannot_create', __( 'Sorry, you are not allowed to create new terms.' ), array( 'status' => rest_authorization_required_code() ) ); } diff --git a/tests/phpunit/tests/rest-api/rest-categories-controller.php b/tests/phpunit/tests/rest-api/rest-categories-controller.php index 664533cf22..86d72e4c84 100644 --- a/tests/phpunit/tests/rest-api/rest-categories-controller.php +++ b/tests/phpunit/tests/rest-api/rest-categories-controller.php @@ -12,15 +12,25 @@ */ class WP_Test_REST_Categories_Controller extends WP_Test_REST_Controller_Testcase { protected static $administrator; + protected static $contributor; protected static $subscriber; public static function wpSetUpBeforeClass( $factory ) { - self::$administrator = $factory->user->create( array( - 'role' => 'administrator', - ) ); - self::$subscriber = $factory->user->create( array( - 'role' => 'subscriber', - ) ); + self::$administrator = $factory->user->create( + array( + 'role' => 'administrator', + ) + ); + self::$contributor = $factory->user->create( + array( + 'role' => 'subscriber', + ) + ); + self::$subscriber = $factory->user->create( + array( + 'role' => 'subscriber', + ) + ); } public static function wpTearDownAfterClass() { @@ -653,6 +663,14 @@ class WP_Test_REST_Categories_Controller extends WP_Test_REST_Controller_Testcas $this->assertErrorResponse( 'rest_cannot_create', $response, 403 ); } + public function test_create_item_incorrect_permissions_contributor() { + wp_set_current_user( self::$contributor ); + $request = new WP_REST_Request( 'POST', '/wp/v2/categories' ); + $request->set_param( 'name', 'Incorrect permissions' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_cannot_create', $response, 403 ); + } + public function test_create_item_missing_arguments() { wp_set_current_user( self::$administrator ); $request = new WP_REST_Request( 'POST', '/wp/v2/categories' ); diff --git a/tests/phpunit/tests/rest-api/rest-tags-controller.php b/tests/phpunit/tests/rest-api/rest-tags-controller.php index 904e826751..8702801767 100644 --- a/tests/phpunit/tests/rest-api/rest-tags-controller.php +++ b/tests/phpunit/tests/rest-api/rest-tags-controller.php @@ -13,22 +13,36 @@ class WP_Test_REST_Tags_Controller extends WP_Test_REST_Controller_Testcase { protected static $superadmin; protected static $administrator; protected static $editor; + protected static $contributor; protected static $subscriber; public static function wpSetUpBeforeClass( $factory ) { - self::$superadmin = $factory->user->create( array( - 'role' => 'administrator', - 'user_login' => 'superadmin', - ) ); - self::$administrator = $factory->user->create( array( - 'role' => 'administrator', - ) ); - self::$editor = $factory->user->create( array( - 'role' => 'editor', - ) ); - self::$subscriber = $factory->user->create( array( - 'role' => 'subscriber', - ) ); + self::$superadmin = $factory->user->create( + array( + 'role' => 'administrator', + 'user_login' => 'superadmin', + ) + ); + self::$administrator = $factory->user->create( + array( + 'role' => 'administrator', + ) + ); + self::$editor = $factory->user->create( + array( + 'role' => 'editor', + ) + ); + self::$contributor = $factory->user->create( + array( + 'role' => 'contributor', + ) + ); + self::$subscriber = $factory->user->create( + array( + 'role' => 'subscriber', + ) + ); if ( is_multisite() ) { update_site_option( 'site_admins', array( 'superadmin' ) ); } @@ -561,6 +575,22 @@ class WP_Test_REST_Tags_Controller extends WP_Test_REST_Controller_Testcase { $this->assertEquals( 'so-awesome', $data['slug'] ); } + public function test_create_item_contributor() { + wp_set_current_user( self::$contributor ); + $request = new WP_REST_Request( 'POST', '/wp/v2/tags' ); + $request->set_param( 'name', 'My Awesome Term' ); + $request->set_param( 'description', 'This term is so awesome.' ); + $request->set_param( 'slug', 'so-awesome' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertEquals( 201, $response->get_status() ); + $headers = $response->get_headers(); + $data = $response->get_data(); + $this->assertContains( '/wp/v2/tags/' . $data['id'], $headers['Location'] ); + $this->assertEquals( 'My Awesome Term', $data['name'] ); + $this->assertEquals( 'This term is so awesome.', $data['description'] ); + $this->assertEquals( 'so-awesome', $data['slug'] ); + } + public function test_create_item_incorrect_permissions() { wp_set_current_user( self::$subscriber ); $request = new WP_REST_Request( 'POST', '/wp/v2/tags' ); diff --git a/tests/phpunit/tests/rest-api/rest-taxonomies-controller.php b/tests/phpunit/tests/rest-api/rest-taxonomies-controller.php index d3806979f5..9e400074f3 100644 --- a/tests/phpunit/tests/rest-api/rest-taxonomies-controller.php +++ b/tests/phpunit/tests/rest-api/rest-taxonomies-controller.php @@ -62,6 +62,23 @@ class WP_Test_REST_Taxonomies_Controller extends WP_Test_REST_Controller_Testcas $this->assertEquals( 'tags', $data['post_tag']['rest_base'] ); } + public function test_get_items_context_edit() { + wp_set_current_user( self::$contributor_id ); + $request = new WP_REST_Request( 'GET', '/wp/v2/taxonomies' ); + $request->set_param( 'context', 'edit' ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + $taxonomies = $this->get_public_taxonomies( get_taxonomies( '', 'objects' ) ); + $this->assertEquals( count( $taxonomies ), count( $data ) ); + $this->assertEquals( 'Categories', $data['category']['name'] ); + $this->assertEquals( 'category', $data['category']['slug'] ); + $this->assertEquals( true, $data['category']['hierarchical'] ); + $this->assertEquals( 'Tags', $data['post_tag']['name'] ); + $this->assertEquals( 'post_tag', $data['post_tag']['slug'] ); + $this->assertEquals( false, $data['post_tag']['hierarchical'] ); + $this->assertEquals( 'tags', $data['post_tag']['rest_base'] ); + } + public function test_get_items_invalid_permission_for_context() { wp_set_current_user( 0 ); $request = new WP_REST_Request( 'GET', '/wp/v2/taxonomies' );