WordPress.org

Make WordPress Core

Changeset 40106


Ignore:
Timestamp:
02/23/2017 10:36:54 PM (15 months ago)
Author:
flixos90
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.
Fixes #39701.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php

    r39954 r40106  
    352352        }
    353353
     354        if ( is_multisite() && ! is_user_member_of_blog( $user->ID ) ) {
     355            return $error;
     356        }
     357
    354358        return $user;
    355359    }
     
    639643        /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php */
    640644        do_action( 'rest_insert_user', $user, $request, false );
    641 
    642         if ( is_multisite() && ! is_user_member_of_blog( $id ) ) {
    643             add_user_to_blog( get_current_blog_id(), $id, '' );
    644         }
    645645
    646646        if ( ! empty( $request['roles'] ) ) {
  • trunk/tests/phpunit/tests/rest-api/rest-users-controller.php

    r39954 r40106  
    676676        $request->set_param( 'context', 'edit' );
    677677        $response = $this->server->dispatch( $request );
    678         $data = $response->get_data();
    679 
    680         $this->assertEquals( $data['capabilities'], new stdClass() );
    681         $this->assertEquals( $data['extra_capabilities'], new stdClass() );
     678
     679        if ( is_multisite() ) {
     680            $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
     681        } else {
     682            $data = $response->get_data();
     683
     684            $this->assertEquals( $data['capabilities'], new stdClass() );
     685            $this->assertEquals( $data['extra_capabilities'], new stdClass() );
     686        }
    682687    }
    683688
     
    10351040            }
    10361041        }
    1037     }
    1038 
    1039     public function test_update_existing_network_user_on_sub_site_adds_user_to_site() {
    1040         if ( ! is_multisite() ) {
    1041             $this->markTestSkipped( 'Test requires multisite.' );
    1042         }
    1043 
    1044         $this->allow_user_to_manage_multisite();
    1045 
    1046         $params = array(
    1047             'username' => 'testuser123',
    1048             'password' => 'testpassword',
    1049             'email'    => 'test@example.com',
    1050             'name'     => 'Test User 123',
    1051             'roles'    => array( 'editor' ),
    1052         );
    1053 
    1054         $request = new WP_REST_Request( 'POST', '/wp/v2/users' );
    1055         $request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
    1056         $request->set_body_params( $params );
    1057         $response = $this->server->dispatch( $request );
    1058         $data = $response->get_data();
    1059         $user_id = $data['id'];
    1060 
    1061         switch_to_blog( self::$site );
    1062 
    1063         $request = new WP_REST_Request( 'PUT', '/wp/v2/users/' . $user_id );
    1064         $request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
    1065         $request->set_body_params( $params );
    1066         $this->server->dispatch( $request );
    1067 
    1068         restore_current_blog();
    1069 
    1070         $user_is_member = is_user_member_of_blog( $user_id, self::$site );
    1071 
    1072         wpmu_delete_user( $user_id );
    1073 
    1074         $this->assertTrue( $user_is_member );
    10751042    }
    10761043
     
    21902157    }
    21912158
     2159    /**
     2160     * @ticket 39701
     2161     */
     2162    public function test_get_item_from_different_site_as_site_administrator() {
     2163        if ( ! is_multisite() ) {
     2164            $this->markTestSkipped( 'Test only runs in multisite' );
     2165        }
     2166
     2167        switch_to_blog( self::$site );
     2168        $user_id = $this->factory->user->create( array(
     2169            'role' => 'author',
     2170        ) );
     2171        restore_current_blog();
     2172
     2173        wp_set_current_user( self::$user );
     2174        $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', $user_id ) );
     2175
     2176        $response = $this->server->dispatch( $request );
     2177        $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
     2178    }
     2179
     2180    /**
     2181     * @ticket 39701
     2182     */
     2183    public function test_get_item_from_different_site_as_network_administrator() {
     2184        if ( ! is_multisite() ) {
     2185            $this->markTestSkipped( 'Test only runs in multisite' );
     2186        }
     2187
     2188        switch_to_blog( self::$site );
     2189        $user_id = $this->factory->user->create( array(
     2190            'role' => 'author',
     2191        ) );
     2192        restore_current_blog();
     2193
     2194        wp_set_current_user( self::$superadmin );
     2195        $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d', $user_id ) );
     2196
     2197        $response = $this->server->dispatch( $request );
     2198        $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
     2199    }
     2200
     2201    /**
     2202     * @ticket 39701
     2203     */
     2204    public function test_update_item_from_different_site_as_site_administrator() {
     2205        if ( ! is_multisite() ) {
     2206            $this->markTestSkipped( 'Test only runs in multisite' );
     2207        }
     2208
     2209        switch_to_blog( self::$site );
     2210        $user_id = $this->factory->user->create( array(
     2211            'role' => 'author',
     2212        ) );
     2213        restore_current_blog();
     2214
     2215        wp_set_current_user( self::$user );
     2216        $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', $user_id ) );
     2217        $request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
     2218        $request->set_body_params( array( 'first_name' => 'New Name' ) );
     2219
     2220        $response = $this->server->dispatch( $request );
     2221        $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
     2222    }
     2223
     2224    /**
     2225     * @ticket 39701
     2226     */
     2227    public function test_update_item_from_different_site_as_network_administrator() {
     2228        if ( ! is_multisite() ) {
     2229            $this->markTestSkipped( 'Test only runs in multisite' );
     2230        }
     2231
     2232        switch_to_blog( self::$site );
     2233        $user_id = $this->factory->user->create( array(
     2234            'role' => 'author',
     2235        ) );
     2236        restore_current_blog();
     2237
     2238        wp_set_current_user( self::$superadmin );
     2239        $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d', $user_id ) );
     2240        $request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
     2241        $request->set_body_params( array( 'first_name' => 'New Name' ) );
     2242
     2243        $response = $this->server->dispatch( $request );
     2244        $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
     2245    }
     2246
     2247    /**
     2248     * @ticket 39701
     2249     */
     2250    public function test_delete_item_from_different_site_as_site_administrator() {
     2251        if ( ! is_multisite() ) {
     2252            $this->markTestSkipped( 'Test only runs in multisite' );
     2253        }
     2254
     2255        switch_to_blog( self::$site );
     2256        $user_id = $this->factory->user->create( array(
     2257            'role' => 'author',
     2258        ) );
     2259        restore_current_blog();
     2260
     2261        wp_set_current_user( self::$user );
     2262        $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d', $user_id ) );
     2263        $request->set_param( 'force', true );
     2264        $request->set_param( 'reassign', false );
     2265
     2266        $response = $this->server->dispatch( $request );
     2267        $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
     2268    }
     2269
     2270    /**
     2271     * @ticket 39701
     2272     */
     2273    public function test_delete_item_from_different_site_as_network_administrator() {
     2274        if ( ! is_multisite() ) {
     2275            $this->markTestSkipped( 'Test only runs in multisite' );
     2276        }
     2277
     2278        switch_to_blog( self::$site );
     2279        $user_id = $this->factory->user->create( array(
     2280            'role' => 'author',
     2281        ) );
     2282        restore_current_blog();
     2283
     2284        wp_set_current_user( self::$superadmin );
     2285        $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d', $user_id ) );
     2286        $request->set_param( 'force', true );
     2287        $request->set_param( 'reassign', false );
     2288
     2289        $response = $this->server->dispatch( $request );
     2290        $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 );
     2291    }
     2292
    21922293    public function additional_field_get_callback( $object ) {
    21932294        return get_user_meta( $object['id'], 'my_custom_int', true );
Note: See TracChangeset for help on using the changeset viewer.