WordPress.org

Make WordPress Core

Changeset 40106


Ignore:
Timestamp:
02/23/17 22:36:54 (10 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.