diff --git a/src/wp-includes/user.php b/src/wp-includes/user.php index 6222e932a9015..635f82c5ed353 100644 --- a/src/wp-includes/user.php +++ b/src/wp-includes/user.php @@ -2780,8 +2780,6 @@ function wp_update_user( $userdata ) { $current_user = wp_get_current_user(); if ( $current_user->ID === $user_id ) { if ( isset( $plaintext_pass ) ) { - wp_clear_auth_cookie(); - /* * Here we calculate the expiration length of the current auth cookie and compare it to the default expiration. * If it's greater than this, then we know the user checked 'Remember Me' when they logged in. @@ -2790,13 +2788,20 @@ function wp_update_user( $userdata ) { /** This filter is documented in wp-includes/pluggable.php */ $default_cookie_life = apply_filters( 'auth_cookie_expiration', ( 2 * DAY_IN_SECONDS ), $user_id, false ); + wp_clear_auth_cookie(); + $remember = false; + $token = ''; + + if ( false !== $logged_in_cookie ) { + $token = $logged_in_cookie['token']; + } if ( false !== $logged_in_cookie && ( (int) $logged_in_cookie['expiration'] - time() ) > $default_cookie_life ) { $remember = true; } - wp_set_auth_cookie( $user_id, $remember ); + wp_set_auth_cookie( $user_id, $remember, '', $token ); } } diff --git a/tests/phpunit/tests/user.php b/tests/phpunit/tests/user.php index 884200530f1d9..9e1faa2dca3f0 100644 --- a/tests/phpunit/tests/user.php +++ b/tests/phpunit/tests/user.php @@ -63,9 +63,37 @@ public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) { public function set_up() { parent::set_up(); + add_action( 'set_auth_cookie', array( $this, 'action_set_auth_cookie' ), 10, 6 ); + add_action( 'set_logged_in_cookie', array( $this, 'action_set_logged_in_cookie' ), 10 ); + add_action( 'clear_auth_cookie', array( $this, 'action_clear_auth_cookie' ) ); + + $_COOKIE = array(); + $this->author = clone self::$_author; } + final public function action_set_auth_cookie( + string $cookie, + int $expire, + int $expiration, + int $user_id, + string $scheme, + string $token + ): void { + $_COOKIE[ SECURE_AUTH_COOKIE ] = $cookie; + $_COOKIE[ AUTH_COOKIE ] = $cookie; + } + + final public function action_set_logged_in_cookie( string $cookie ): void { + $_COOKIE[ LOGGED_IN_COOKIE ] = $cookie; + } + + final public function action_clear_auth_cookie(): void { + unset( $_COOKIE[ LOGGED_IN_COOKIE ] ); + unset( $_COOKIE[ SECURE_AUTH_COOKIE ] ); + unset( $_COOKIE[ AUTH_COOKIE ] ); + } + public function test_get_users_of_blog() { // Add one of each user role. $nusers = array( @@ -1122,6 +1150,50 @@ public function test_changing_password_invalidates_password_reset_key() { $this->assertEmpty( $user->user_activation_key ); } + /** + * @ticket 61366 + * @dataProvider data_remember_user + */ + public function test_changing_own_password_retains_current_session( bool $remember ) { + $user = $this->author; + $manager = WP_Session_Tokens::get_instance( $user->ID ); + $expiry = $remember ? ( 2 * WEEK_IN_SECONDS ) : ( 2 * DAY_IN_SECONDS ); + $token = $manager->create( time() + $expiry ); + $pass = $user->user_pass; + + wp_set_current_user( $user->ID ); + wp_set_auth_cookie( $user->ID, $remember, '', $token ); + + $cookie = $_COOKIE[ AUTH_COOKIE ]; + $userdata = array( + 'ID' => $user->ID, + 'user_pass' => 'my_new_password', + ); + $updated = wp_update_user( $userdata, $manager ); + $parsed = wp_parse_auth_cookie(); + + // Check the prerequisites: + $this->assertNotWPError( $updated ); + $this->assertNotSame( $pass, get_userdata( $user->ID )->user_pass ); + + // Check the session token: + $this->assertSame( $token, $parsed['token'] ); + $this->assertCount( 1, $manager->get_all() ); + + // Check that the newly set auth cookie is valid: + $this->assertSame( $user->ID, wp_validate_auth_cookie() ); + + // Check that, despite the session token reuse, the old auth cookie should now be invalid because the password changed: + $this->assertFalse( wp_validate_auth_cookie( $cookie ) ); + } + + public function data_remember_user() { + return array( + array( true ), + array( false ), + ); + } + public function test_search_users_login() { $users = get_users( array(