Skip to content
This repository was archived by the owner on Aug 15, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 35 additions & 9 deletions lib/class-wp-rest-plugins-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,30 @@ public function register_routes() {
* @return WP_Error|boolean
*/
public function get_items_permissions_check( $request ) {

if ( ! current_user_can( 'manage_options' ) ) { // TODO: Something related to plugins. activate_plugin capability seems to not be available for multi-site superadmin (?)
return new WP_Error( 'rest_forbidden', __( 'Sorry, you cannot view the list of plugins' ), array( 'status' => rest_authorization_required_code() ) );
if ( is_multisite() ) {
/**
* The menu items option determines whether a site admin who is not
* a super admin can work with plugins for their site. This is a
* core feature. wp-admin\network\settings.php
*/
$menu_permissions = get_site_option( 'menu_items' );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I'm not sure if I understand the rational behind using this option value, maybe I'm misunderstanding but it looks like you're looking at what is present in the menu to decide what they have permissions to?

Copy link
Member Author

@BE-Webdesign BE-Webdesign Aug 18, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a multisite install, regular site admins (non super admins), can view and manage plugins specific to their site, when this option is enabled. I wanted to reflect that core capability in the permissions check here. I will work on making the conditionals more clear. If it is not apparent then it is bad code. I will try to make the intent more clear. Should I maybe add in a doc block explaining all of that or should we not support this?

Copy link
Member

@joehoyle joehoyle Aug 19, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh I see, menu_items is a site level option, one of which is whether admins are allowed to manage plugins on their site? In that case, let's just add some inline docs explaining what that is. I think it's a good thing to support. Also, if it's possible to break the conditionals down more to be more readable, I'd be +1 on that

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do!

// Check if the user cannot manage network plugins.
if ( current_user_can( 'manage_network_plugins' ) ) {
return true;
} else {
// Check if the plugins menu is active for site administators.
if ( isset( $menu_permissions['plugins'] ) && '1' === $menu_permissions['plugins'] && current_user_can( 'activate_plugins' ) ) {
return true;
}
}
} else {
if ( current_user_can( 'activate_plugins' ) ) {
return true;
}
}

return true;

// White list approach. This does not follow rest endpoint conventions.
return new WP_Error( 'rest_forbidden', __( 'Sorry, you cannot view plugins.', 'be-rest-endpoints' ), array( 'status' => rest_authorization_required_code() ) );
}

public function get_items( $request ) {
Expand Down Expand Up @@ -131,13 +148,22 @@ public function get_items( $request ) {
* @return WP_Error|boolean
*/
public function get_item_permissions_check( $request ) {

if ( ! current_user_can( 'manage_options' ) ) { // TODO: Something related to plugins. activate_plugin capability seems to not be available for multi-site superadmin (?)
return new WP_Error( 'rest_forbidden', __( 'Sorry, you do not have access to this resource' ), array( 'status' => rest_authorization_required_code() ) );
if ( is_multisite() ) {
$menu_permissions = get_site_option( 'menu_items' );
// Check if the user cannot manage network plugins but site admins have access to
if ( ! current_user_can( 'manage_network_plugins' ) && ! isset( $menu_permissions['plugins'] ) && '1' !== $menu_permissions['plugins'] ) {
return new WP_Error( 'rest_forbidden', __( 'Sorry, you cannot view plugins.', 'be-rest-endpoints' ), array( 'status' => rest_authorization_required_code() ) );
}
if ( isset( $menu_permissions['plugins'] ) && '1' === $menu_permissions['plugins'] && ! current_user_can( 'activate_plugins' ) ) {
return new WP_Error( 'rest_forbidden', __( 'Sorry, you cannot view the list of plugins' ), array( 'status' => rest_authorization_required_code() ) );
}
} else {
if ( ! current_user_can( 'activate_plugins' ) ) {
return new WP_Error( 'rest_forbidden', __( 'Sorry, you cannot view the list of plugins' ), array( 'status' => rest_authorization_required_code() ) );
}
}

return true;

}

public function get_item( $request ) {
Expand Down
141 changes: 134 additions & 7 deletions tests/test-rest-plugins-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ public function setUp() {
$this->admin_id = $this->factory->user->create( array(
'role' => 'administrator',
) );

$this->super_admin = $this->factory->user->create( array(
'role' => 'administrator',
) );

$this->subscriber = $this->factory->user->create( array(
'role' => 'subscriber',
) );
}

public function test_register_routes() {
Expand All @@ -27,16 +35,23 @@ public function test_delete_item_without_permission() {

$this->assertErrorResponse( 'rest_forbidden', $response, 401 );

wp_set_current_user( $this->subscriber );

$response = $this->server->dispatch( $request );

$this->assertErrorResponse( 'rest_forbidden', $response, 403 );
}

public function test_context_param() {

}

public function test_get_items() {
wp_set_current_user( $this->admin_id );
$this->set_user_with_priviledges();

$request = new WP_REST_Request( 'GET', '/wp/v2/plugins' );
$response = $this->server->dispatch( $request );

$this->assertEquals( 200, $response->get_status() );
$data = $response->get_data();
$this->assertEquals( 2, count( $data ) );
Expand All @@ -49,8 +64,8 @@ public function test_get_items() {
*/
public function test_get_items_pagination_headers() {
// Skipped until more plugins are added into wordpress-develop repo.
$this->set_user_with_priviledges();

wp_set_current_user( $this->admin_id );
// One plugin installed by default.
$request = new WP_REST_Request( 'GET', '/wp/v2/plugins' );
$request->set_param( 'per_page', 1 );
Expand Down Expand Up @@ -114,7 +129,7 @@ public function test_get_items_pagination_headers() {
}

public function test_get_items_per_page() {
wp_set_current_user( $this->admin_id );
$this->set_user_with_priviledges();

$request = new WP_REST_Request( 'GET', '/wp/v2/plugins' );
$response = $this->server->dispatch( $request );
Expand All @@ -127,7 +142,7 @@ public function test_get_items_per_page() {
}

public function test_get_items_page() {
wp_set_current_user( $this->admin_id );
$this->set_user_with_priviledges();

$request = new WP_REST_Request( 'GET', '/wp/v2/plugins' );
$request->set_param( 'per_page', 1 );
Expand All @@ -144,7 +159,7 @@ public function test_get_items_page() {
}

public function test_get_items_offset() {
wp_set_current_user( $this->admin_id );
$this->set_user_with_priviledges();

// 2 Plugins installed by default.
$request = new WP_REST_Request( 'GET', '/wp/v2/plugins' );
Expand All @@ -169,16 +184,99 @@ public function test_get_items_offset() {
$this->assertCount( 0, $response->get_data() );
}

public function test_get_item() {
public function test_get_items_multisite_permissions() {
if ( is_multisite() ) {
wp_set_current_user( $this->admin_id );

wp_set_current_user( $this->admin_id );
// By default an admin cannot check plugins on a multisite install.
$request = new WP_REST_Request( 'GET', '/wp/v2/plugins' );

$response = $this->server->dispatch( $request );

$this->assertErrorResponse( 'rest_forbidden', $response, 403 );

// Now check when it is enabled for admins.
$menu_permissions = get_site_option( 'menu_items' );
$menu_permissions['plugins'] = '1';
update_site_option( 'menu_items', $menu_permissions );

// This should return a positive result now.
$response = $this->server->dispatch( $request );

$this->assertEquals( 200, $response->get_status() );

// Check to make sure lower users can still not access plugins.
wp_set_current_user( $this->subscriber );

$response = $this->server->dispatch( $request );

$this->assertErrorResponse( 'rest_forbidden', $response, 403 );

// Clean up.
$menu_permissions['plugins'] = '0';
update_site_option( 'menu_items', $menu_permissions );
}
}

public function test_get_item() {
$this->set_user_with_priviledges();

$request = new WP_REST_Request( 'GET', '/wp/v2/plugins/hello-dolly' );
$response = $this->server->dispatch( $request );

$this->check_get_plugin_response( $response, 'view' );
}

public function test_get_item_without_permissions() {
wp_set_current_user( 0 );

$request = new WP_REST_Request( 'GET', '/wp/v2/plugins/hello-dolly' );

$response = $this->server->dispatch( $request );

$this->assertErrorResponse( 'rest_forbidden', $response, 401 );

wp_set_current_user( $this->subscriber );

$response = $this->server->dispatch( $request );

$this->assertErrorResponse( 'rest_forbidden', $response, 403 );
}

public function test_get_item_multisite_permissions() {
if ( is_multisite() ) {
wp_set_current_user( $this->admin_id );

// By default an admin cannot check plugins on a multisite install.
$request = new WP_REST_Request( 'GET', '/wp/v2/plugins/hello-dolly' );

$response = $this->server->dispatch( $request );

$this->assertErrorResponse( 'rest_forbidden', $response, 403 );

// Now check when it is enabled for admins.
$menu_permissions = get_site_option( 'menu_items' );
$menu_permissions['plugins'] = '1';
update_site_option( 'menu_items', $menu_permissions );

// This should return a positive result now.
$response = $this->server->dispatch( $request );

$this->assertEquals( 200, $response->get_status() );

// Check to make sure lower users can still not access plugins.
wp_set_current_user( $this->subscriber );

$response = $this->server->dispatch( $request );

$this->assertErrorResponse( 'rest_forbidden', $response, 403 );

// Clean up.
$menu_permissions['plugins'] = '0';
update_site_option( 'menu_items', $menu_permissions );
}
}

public function test_create_item() {

}
Expand Down Expand Up @@ -222,6 +320,12 @@ public function test_get_items_without_permissions() {
$response = $this->server->dispatch( $request );

$this->assertErrorResponse( 'rest_forbidden', $response, 401 );

wp_set_current_user( $this->subscriber );

$response = $this->server->dispatch( $request );

$this->assertErrorResponse( 'rest_forbidden', $response, 403 );
}

/**
Expand Down Expand Up @@ -283,4 +387,27 @@ protected function check_plugin_data( $data, $context, $links ) {
// @TODO Handle active, parent, update, autoupdate.
// @TODO Handle context params.
}

protected function allow_user_to_manage_multisite() {
wp_set_current_user( $this->super_admin );
$user = wp_get_current_user();

if ( is_multisite() ) {
update_site_option( 'site_admins', array( $user->user_login ) );
}

return;
}

/**
* Handles the difference between multisite and single site users.
*
* Special cases need to be handled in the tests still.
*/
protected function set_user_with_priviledges() {
wp_set_current_user( $this->admin_id );
if ( is_multisite() ) {
$this->allow_user_to_manage_multisite();
}
}
}