Make WordPress Core

Changeset 40111 for branches/4.7


Ignore:
Timestamp:
02/24/2017 08:45:52 PM (8 years ago)
Author:
SergeyBiryukov
Message:

REST API: Do not allow access to users from a different site in multisite.

It has been unintendedly possible to both view and edit users from a different site than the current site in multisite environments. Moreover, when passing roles to a user in an update request, that user would implicitly be added to the current site.

This changeset removes the incorrect behavior for now in order to be able to provide a proper REST API workflow for managing multisite users in the near future. Related unit tests have been adjusted as well.

Props jnylen0, jeremyfelt, johnjamesjacoby.
Merges [40106] to the 4.7 branch.
Fixes #39701.

Location:
branches/4.7
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • branches/4.7

  • branches/4.7/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php

    r39957 r40111  
    351351        }
    352352
     353        if ( is_multisite() && ! is_user_member_of_blog( $user->ID ) ) {
     354            return $error;
     355        }
     356
    353357        return $user;
    354358    }
     
    638642        /* This action is documented in lib/endpoints/class-wp-rest-users-controller.php */
    639643        do_action( 'rest_insert_user', $user, $request, false );
    640 
    641         if ( is_multisite() && ! is_user_member_of_blog( $id ) ) {
    642             add_user_to_blog( get_current_blog_id(), $id, '' );
    643         }
    644644
    645645        if ( ! empty( $request['roles'] ) ) {
  • branches/4.7/tests/phpunit/tests/rest-api/rest-users-controller.php

    r39957 r40111  
    686686        $request->set_param( 'context', 'edit' );
    687687        $response = $this->server->dispatch( $request );
    688         $data = $response->get_data();
    689 
    690         $this->assertEquals( $data['capabilities'], new stdClass() );
    691         $this->assertEquals( $data['extra_capabilities'], new stdClass() );
     688
     689        if ( is_multisite() ) {
     690            $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
     691        } else {
     692            $data = $response->get_data();
     693
     694            $this->assertEquals( $data['capabilities'], new stdClass() );
     695            $this->assertEquals( $data['extra_capabilities'], new stdClass() );
     696        }
    692697    }
    693698
     
    9971002            }
    9981003        }
    999     }
    1000 
    1001     public function test_update_existing_network_user_on_sub_site_adds_user_to_site() {
    1002         if ( ! is_multisite() ) {
    1003             $this->markTestSkipped( 'Test requires multisite.' );
    1004         }
    1005 
    1006         $this->allow_user_to_manage_multisite();
    1007 
    1008         $params = array(
    1009             'username' => 'testuser123',
    1010             'password' => 'testpassword',
    1011             'email'    => 'test@example.com',
    1012             'name'     => 'Test User 123',
    1013             'roles'    => array( 'editor' ),
    1014         );
    1015 
    1016         $request = new WP_REST_Request( 'POST', '/wp/v2/users' );
    1017         $request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
    1018         $request->set_body_params( $params );
    1019         $response = $this->server->dispatch( $request );
    1020         $data = $response->get_data();
    1021         $user_id = $data['id'];
    1022 
    1023         switch_to_blog( self::$site );
    1024 
    1025         $request = new WP_REST_Request( 'PUT', '/wp/v2/users/' . $user_id );
    1026         $request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
    1027         $request->set_body_params( $params );
    1028         $this->server->dispatch( $request );
    1029 
    1030         restore_current_blog();
    1031 
    1032         $user_is_member = is_user_member_of_blog( $user_id, self::$site );
    1033 
    1034         wpmu_delete_user( $user_id );
    1035 
    1036         $this->assertTrue( $user_is_member );
    10371004    }
    10381005
     
    21522119    }
    21532120
     2121    /**
     2122     * @ticket 39701
     2123     */
     2124    public function test_get_item_from_different_site_as_site_administrator() {
     2125        if ( ! is_multisite() ) {
     2126            $this->markTestSkipped( 'Test only runs in multisite' );
     2127        }
     2128
     2129        switch_to_blog( self::$site );
     2130        $user_id = $this->factory->user->create( array(
     2131            'role' => 'author',
     2132        ) );
     2133        restore_current_blog();
     2134
     2135        wp_set_current_user( self::$user );
     2136        $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', $user_id ) );
     2137
     2138        $response = $this->server->dispatch( $request );
     2139        $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
     2140    }
     2141
     2142    /**
     2143     * @ticket 39701
     2144     */
     2145    public function test_get_item_from_different_site_as_network_administrator() {
     2146        if ( ! is_multisite() ) {
     2147            $this->markTestSkipped( 'Test only runs in multisite' );
     2148        }
     2149
     2150        switch_to_blog( self::$site );
     2151        $user_id = $this->factory->user->create( array(
     2152            'role' => 'author',
     2153        ) );
     2154        restore_current_blog();
     2155
     2156        wp_set_current_user( self::$superadmin );
     2157        $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', $user_id ) );
     2158
     2159        $response = $this->server->dispatch( $request );
     2160        $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
     2161    }
     2162
     2163    /**
     2164     * @ticket 39701
     2165     */
     2166    public function test_update_item_from_different_site_as_site_administrator() {
     2167        if ( ! is_multisite() ) {
     2168            $this->markTestSkipped( 'Test only runs in multisite' );
     2169        }
     2170
     2171        switch_to_blog( self::$site );
     2172        $user_id = $this->factory->user->create( array(
     2173            'role' => 'author',
     2174        ) );
     2175        restore_current_blog();
     2176
     2177        wp_set_current_user( self::$user );
     2178        $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', $user_id ) );
     2179        $request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
     2180        $request->set_body_params( array( 'first_name' => 'New Name' ) );
     2181
     2182        $response = $this->server->dispatch( $request );
     2183        $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
     2184    }
     2185
     2186    /**
     2187     * @ticket 39701
     2188     */
     2189    public function test_update_item_from_different_site_as_network_administrator() {
     2190        if ( ! is_multisite() ) {
     2191            $this->markTestSkipped( 'Test only runs in multisite' );
     2192        }
     2193
     2194        switch_to_blog( self::$site );
     2195        $user_id = $this->factory->user->create( array(
     2196            'role' => 'author',
     2197        ) );
     2198        restore_current_blog();
     2199
     2200        wp_set_current_user( self::$superadmin );
     2201        $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', $user_id ) );
     2202        $request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
     2203        $request->set_body_params( array( 'first_name' => 'New Name' ) );
     2204
     2205        $response = $this->server->dispatch( $request );
     2206        $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
     2207    }
     2208
     2209    /**
     2210     * @ticket 39701
     2211     */
     2212    public function test_delete_item_from_different_site_as_site_administrator() {
     2213        if ( ! is_multisite() ) {
     2214            $this->markTestSkipped( 'Test only runs in multisite' );
     2215        }
     2216
     2217        switch_to_blog( self::$site );
     2218        $user_id = $this->factory->user->create( array(
     2219            'role' => 'author',
     2220        ) );
     2221        restore_current_blog();
     2222
     2223        wp_set_current_user( self::$user );
     2224        $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d', $user_id ) );
     2225        $request->set_param( 'force', true );
     2226        $request->set_param( 'reassign', false );
     2227
     2228        $response = $this->server->dispatch( $request );
     2229        $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
     2230    }
     2231
     2232    /**
     2233     * @ticket 39701
     2234     */
     2235    public function test_delete_item_from_different_site_as_network_administrator() {
     2236        if ( ! is_multisite() ) {
     2237            $this->markTestSkipped( 'Test only runs in multisite' );
     2238        }
     2239
     2240        switch_to_blog( self::$site );
     2241        $user_id = $this->factory->user->create( array(
     2242            'role' => 'author',
     2243        ) );
     2244        restore_current_blog();
     2245
     2246        wp_set_current_user( self::$superadmin );
     2247        $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d', $user_id ) );
     2248        $request->set_param( 'force', true );
     2249        $request->set_param( 'reassign', false );
     2250
     2251        $response = $this->server->dispatch( $request );
     2252        $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
     2253    }
     2254
    21542255    public function additional_field_get_callback( $object ) {
    21552256        return get_user_meta( $object['id'], 'my_custom_int', true );
Note: See TracChangeset for help on using the changeset viewer.