From 877a59a843946196faaee062928a2e9faafe592c Mon Sep 17 00:00:00 2001 From: "Dominik Schilling (ocean90)" Date: Mon, 19 Mar 2018 20:28:28 +0000 Subject: [PATCH] Users: Use `promote_users` for role updates in `edit_user()`. `edit_user()` can also update user roles but was still using the `edit_users` capability instead of the newer `promote_users` capability introduced in [14176]. This makes the role handling consistent with the bulk dropdown menu for role changes. Props flixos90, johnjamesjacoby, ocean90. Fixes #42564. git-svn-id: https://develop.svn.wordpress.org/trunk@42855 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/user.php | 29 ++++++++++++++++--------- tests/phpunit/tests/user.php | 39 ++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/src/wp-admin/includes/user.php b/src/wp-admin/includes/user.php index 4a22e9541f..403fbdcf30 100644 --- a/src/wp-admin/includes/user.php +++ b/src/wp-admin/includes/user.php @@ -30,9 +30,10 @@ function add_user() { function edit_user( $user_id = 0 ) { $wp_roles = wp_roles(); $user = new stdClass; + $user_id = (int) $user_id; if ( $user_id ) { $update = true; - $user->ID = (int) $user_id; + $user->ID = $user_id; $userdata = get_userdata( $user_id ); $user->user_login = wp_slash( $userdata->user_login ); } else { @@ -51,20 +52,28 @@ function edit_user( $user_id = 0 ) { $pass2 = $_POST['pass2']; } - if ( isset( $_POST['role'] ) && current_user_can( 'edit_users' ) ) { - $new_role = sanitize_text_field( $_POST['role'] ); - $potential_role = isset( $wp_roles->role_objects[ $new_role ] ) ? $wp_roles->role_objects[ $new_role ] : false; - // Don't let anyone with 'edit_users' (admins) edit their own role to something without it. - // Multisite super admins can freely edit their blog roles -- they possess all caps. - if ( ( is_multisite() && current_user_can( 'manage_sites' ) ) || $user_id != get_current_user_id() || ( $potential_role && $potential_role->has_cap( 'edit_users' ) ) ) { - $user->role = $new_role; - } + if ( isset( $_POST['role'] ) && current_user_can( 'promote_users' ) && ( ! $user_id || current_user_can( 'promote_user', $user_id ) ) ) { + $new_role = sanitize_text_field( $_POST['role'] ); - // If the new role isn't editable by the logged-in user die with error + // If the new role isn't editable by the logged-in user die with error. $editable_roles = get_editable_roles(); if ( ! empty( $new_role ) && empty( $editable_roles[ $new_role ] ) ) { wp_die( __( 'Sorry, you are not allowed to give users that role.' ), 403 ); } + + $potential_role = isset( $wp_roles->role_objects[ $new_role ] ) ? $wp_roles->role_objects[ $new_role ] : false; + + /* + * Don't let anyone with 'promote_users' edit their own role to something without it. + * Multisite super admins can freely edit their roles, they possess all caps. + */ + if ( + ( is_multisite() && current_user_can( 'manage_network_users' ) ) || + $user_id !== get_current_user_id() || + ( $potential_role && $potential_role->has_cap( 'promote_users' ) ) + ) { + $user->role = $new_role; + } } if ( isset( $_POST['email'] ) ) { diff --git a/tests/phpunit/tests/user.php b/tests/phpunit/tests/user.php index bcfa036d37..09a5a0628a 100644 --- a/tests/phpunit/tests/user.php +++ b/tests/phpunit/tests/user.php @@ -1541,4 +1541,43 @@ class Tests_User extends WP_UnitTestCase { $this->assertContains( '\'Test\' blog\'s "name" has &', $email->subject, 'Email subject does not contain the decoded HTML entities' ); $this->assertNotContains( ''Test' blog's "name" has <html entities> &', $email->subject, 'Email subject does contains HTML entities' ); } + + /** + * @ticket 42564 + */ + function test_edit_user_role_update() { + $_POST = $_GET = $_REQUEST = array(); + + $administrator = self::factory()->user->create( + array( + 'role' => 'administrator', + ) + ); + + wp_set_current_user( $administrator ); + + // Don't let anyone with 'promote_users' (administrator) edit their own role to something without it (subscriber). + $_POST['role'] = 'subscriber'; + $_POST['email'] = 'subscriber@subscriber.test'; + $_POST['nickname'] = 'subscriber'; + $this->assertSame( $administrator, edit_user( $administrator ) ); + + // Should still have the old role. + $this->assertSame( array( 'administrator' ), get_userdata( $administrator )->roles ); + + // Promote an editor to an administrator. + $editor = self::factory()->user->create( + array( + 'role' => 'editor', + ) + ); + + $_POST['role'] = 'administrator'; + $_POST['email'] = 'administrator@administrator.test'; + $_POST['nickname'] = 'administrator'; + $this->assertSame( $editor, edit_user( $editor ) ); + + // Should have the new role. + $this->assertSame( array( 'administrator' ), get_userdata( $editor )->roles ); + } }