Skip to content

Commit c8f974f

Browse files
App Passwords: Introduce fine grained capabilities.
Previously, all permission checks for using app passwords were implemented using `edit_user`. This commit introduces a series of more fine grained meta capabilities that should be used instead: `create_app_password`, `list_app_passwords`, `read_app_password`, `edit_app_password`, `delete_app_password` and `delete_app_passwords`. These capabilities all map to `edit_user` by default, but may now be customized by developers. Props johnbillion, TimothyBlynJacobs. Fixes #51703. git-svn-id: https://develop.svn.wordpress.org/trunk@50114 602fd350-edb4-49c9-b593-d223f7449a82
1 parent dad20f8 commit c8f974f

File tree

4 files changed

+114
-13
lines changed

4 files changed

+114
-13
lines changed

src/wp-includes/capabilities.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,14 @@ function map_meta_cap( $cap, $user_id, ...$args ) {
592592
case 'manage_privacy_options':
593593
$caps[] = is_multisite() ? 'manage_network' : 'manage_options';
594594
break;
595+
case 'create_app_password':
596+
case 'list_app_passwords':
597+
case 'read_app_password':
598+
case 'edit_app_password':
599+
case 'delete_app_passwords':
600+
case 'delete_app_password':
601+
$caps = map_meta_cap( 'edit_user', $user_id, $args[0] );
602+
break;
595603
default:
596604
// Handle meta capabilities for custom post types.
597605
global $post_type_meta_caps;

src/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php

Lines changed: 93 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,21 @@ public function register_routes() {
110110
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
111111
*/
112112
public function get_items_permissions_check( $request ) {
113-
return $this->do_permissions_check( $request );
113+
$user = $this->get_user( $request );
114+
115+
if ( is_wp_error( $user ) ) {
116+
return $user;
117+
}
118+
119+
if ( ! current_user_can( 'list_app_passwords', $user->ID ) ) {
120+
return new WP_Error(
121+
'rest_cannot_list_application_passwords',
122+
__( 'Sorry, you are not allowed to list application passwords for this user.' ),
123+
array( 'status' => rest_authorization_required_code() )
124+
);
125+
}
126+
127+
return true;
114128
}
115129

116130
/**
@@ -149,7 +163,21 @@ public function get_items( $request ) {
149163
* @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
150164
*/
151165
public function get_item_permissions_check( $request ) {
152-
return $this->do_permissions_check( $request );
166+
$user = $this->get_user( $request );
167+
168+
if ( is_wp_error( $user ) ) {
169+
return $user;
170+
}
171+
172+
if ( ! current_user_can( 'read_app_password', $user->ID, $request['uuid'] ) ) {
173+
return new WP_Error(
174+
'rest_cannot_read_application_password',
175+
__( 'Sorry, you are not allowed to read this application password.' ),
176+
array( 'status' => rest_authorization_required_code() )
177+
);
178+
}
179+
180+
return true;
153181
}
154182

155183
/**
@@ -179,7 +207,21 @@ public function get_item( $request ) {
179207
* @return true|WP_Error True if the request has access to create items, WP_Error object otherwise.
180208
*/
181209
public function create_item_permissions_check( $request ) {
182-
return $this->do_permissions_check( $request );
210+
$user = $this->get_user( $request );
211+
212+
if ( is_wp_error( $user ) ) {
213+
return $user;
214+
}
215+
216+
if ( ! current_user_can( 'create_app_password', $user->ID ) ) {
217+
return new WP_Error(
218+
'rest_cannot_create_application_passwords',
219+
__( 'Sorry, you are not allowed to create application passwords for this user.' ),
220+
array( 'status' => rest_authorization_required_code() )
221+
);
222+
}
223+
224+
return true;
183225
}
184226

185227
/**
@@ -248,7 +290,21 @@ public function create_item( $request ) {
248290
* @return true|WP_Error True if the request has access to create items, WP_Error object otherwise.
249291
*/
250292
public function update_item_permissions_check( $request ) {
251-
return $this->do_permissions_check( $request );
293+
$user = $this->get_user( $request );
294+
295+
if ( is_wp_error( $user ) ) {
296+
return $user;
297+
}
298+
299+
if ( ! current_user_can( 'edit_app_password', $user->ID, $request['uuid'] ) ) {
300+
return new WP_Error(
301+
'rest_cannot_edit_application_password',
302+
__( 'Sorry, you are not allowed to edit this application password.' ),
303+
array( 'status' => rest_authorization_required_code() )
304+
);
305+
}
306+
307+
return true;
252308
}
253309

254310
/**
@@ -308,7 +364,21 @@ public function update_item( $request ) {
308364
* @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise.
309365
*/
310366
public function delete_items_permissions_check( $request ) {
311-
return $this->do_permissions_check( $request );
367+
$user = $this->get_user( $request );
368+
369+
if ( is_wp_error( $user ) ) {
370+
return $user;
371+
}
372+
373+
if ( ! current_user_can( 'delete_app_passwords', $user->ID ) ) {
374+
return new WP_Error(
375+
'rest_cannot_delete_application_passwords',
376+
__( 'Sorry, you are not allowed to delete application passwords for this user.' ),
377+
array( 'status' => rest_authorization_required_code() )
378+
);
379+
}
380+
381+
return true;
312382
}
313383

314384
/**
@@ -349,7 +419,21 @@ public function delete_items( $request ) {
349419
* @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise.
350420
*/
351421
public function delete_item_permissions_check( $request ) {
352-
return $this->do_permissions_check( $request );
422+
$user = $this->get_user( $request );
423+
424+
if ( is_wp_error( $user ) ) {
425+
return $user;
426+
}
427+
428+
if ( ! current_user_can( 'delete_app_password', $user->ID, $request['uuid'] ) ) {
429+
return new WP_Error(
430+
'rest_cannot_delete_application_password',
431+
__( 'Sorry, you are not allowed to delete this application password.' ),
432+
array( 'status' => rest_authorization_required_code() )
433+
);
434+
}
435+
436+
return true;
353437
}
354438

355439
/**
@@ -457,11 +541,14 @@ public function get_current_item( $request ) {
457541
* Performs a permissions check for the request.
458542
*
459543
* @since 5.6.0
544+
* @deprecated 5.7.0 Use `edit_user` directly or one of the specific meta capabilities introduced in 5.7.0.
460545
*
461546
* @param WP_REST_Request $request
462547
* @return true|WP_Error
463548
*/
464549
protected function do_permissions_check( $request ) {
550+
_deprecated_function( __METHOD__, '5.7.0' );
551+
465552
$user = $this->get_user( $request );
466553

467554
if ( is_wp_error( $user ) ) {

tests/phpunit/tests/rest-api/rest-application-passwords-controller.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ public function test_get_items_other_user_id_invalid_permission() {
190190
wp_set_current_user( self::$subscriber_id );
191191

192192
$response = rest_do_request( sprintf( '/wp/v2/users/%d/application-passwords', self::$admin ) );
193-
$this->assertErrorResponse( 'rest_cannot_manage_application_passwords', $response, 403 );
193+
$this->assertErrorResponse( 'rest_cannot_list_application_passwords', $response, 403 );
194194
}
195195

196196
/**
@@ -272,7 +272,7 @@ public function test_get_item_other_user_id_invalid_permission() {
272272

273273
$uuid = $item['uuid'];
274274
$response = rest_do_request( sprintf( '/wp/v2/users/%d/application-passwords/%s', self::$admin, $uuid ) );
275-
$this->assertErrorResponse( 'rest_cannot_manage_application_passwords', $response, 403 );
275+
$this->assertErrorResponse( 'rest_cannot_read_application_password', $response, 403 );
276276
}
277277

278278
/**
@@ -394,7 +394,7 @@ public function test_create_item_other_user_id_invalid_permission() {
394394
$request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d/application-passwords', self::$admin ) );
395395
$request->set_body_params( array( 'name' => 'App' ) );
396396
$response = rest_do_request( $request );
397-
$this->assertErrorResponse( 'rest_cannot_manage_application_passwords', $response, 403 );
397+
$this->assertErrorResponse( 'rest_cannot_create_application_passwords', $response, 403 );
398398
}
399399

400400
/**
@@ -500,7 +500,7 @@ public function test_update_item_other_user_id_invalid_permission() {
500500
$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/application-passwords/%s', self::$admin, $uuid ) );
501501
$request->set_body_params( array( 'name' => 'New App' ) );
502502
$response = rest_do_request( $request );
503-
$this->assertErrorResponse( 'rest_cannot_manage_application_passwords', $response, 403 );
503+
$this->assertErrorResponse( 'rest_cannot_edit_application_password', $response, 403 );
504504
}
505505

506506
/**
@@ -643,7 +643,7 @@ public function test_delete_item_other_user_id_invalid_permission() {
643643
$uuid = $item['uuid'];
644644
$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d/application-passwords/%s', self::$admin, $uuid ) );
645645
$response = rest_do_request( $request );
646-
$this->assertErrorResponse( 'rest_cannot_manage_application_passwords', $response, 403 );
646+
$this->assertErrorResponse( 'rest_cannot_delete_application_password', $response, 403 );
647647
}
648648

649649
/**
@@ -747,7 +747,7 @@ public function test_delete_items_other_user_id_invalid_permission() {
747747

748748
$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d/application-passwords', self::$admin ) );
749749
$response = rest_do_request( $request );
750-
$this->assertErrorResponse( 'rest_cannot_manage_application_passwords', $response, 403 );
750+
$this->assertErrorResponse( 'rest_cannot_delete_application_passwords', $response, 403 );
751751
}
752752

753753
/**

tests/phpunit/tests/user/capabilities.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,13 @@ public function testMetaCapsTestsAreCorrect() {
522522
$expected['delete_user'],
523523
$expected['edit_user_meta'],
524524
$expected['delete_user_meta'],
525-
$expected['add_user_meta']
525+
$expected['add_user_meta'],
526+
$expected['create_app_password'],
527+
$expected['list_app_passwords'],
528+
$expected['read_app_password'],
529+
$expected['edit_app_password'],
530+
$expected['delete_app_passwords'],
531+
$expected['delete_app_password']
526532
);
527533

528534
$expected = array_keys( $expected );

0 commit comments

Comments
 (0)