Skip to content

Commit 964c5d3

Browse files
committed
Users: Retain the current session when a user changes their password.
Prior to this change a new session was unnecessarily created when a user changed their own password. Existing authentication cookies for the user will still be invalidated regardless of whether they share the same session token because session cookie keys contain a substring of the password hash. Props snicco, narenin, johnbillion Fixes #61366 git-svn-id: https://develop.svn.wordpress.org/trunk@59633 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 8aea1ba commit 964c5d3

File tree

2 files changed

+80
-3
lines changed

2 files changed

+80
-3
lines changed

src/wp-includes/user.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2780,8 +2780,6 @@ function wp_update_user( $userdata ) {
27802780
$current_user = wp_get_current_user();
27812781
if ( $current_user->ID === $user_id ) {
27822782
if ( isset( $plaintext_pass ) ) {
2783-
wp_clear_auth_cookie();
2784-
27852783
/*
27862784
* Here we calculate the expiration length of the current auth cookie and compare it to the default expiration.
27872785
* 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 ) {
27902788
/** This filter is documented in wp-includes/pluggable.php */
27912789
$default_cookie_life = apply_filters( 'auth_cookie_expiration', ( 2 * DAY_IN_SECONDS ), $user_id, false );
27922790

2791+
wp_clear_auth_cookie();
2792+
27932793
$remember = false;
2794+
$token = '';
2795+
2796+
if ( false !== $logged_in_cookie ) {
2797+
$token = $logged_in_cookie['token'];
2798+
}
27942799

27952800
if ( false !== $logged_in_cookie && ( (int) $logged_in_cookie['expiration'] - time() ) > $default_cookie_life ) {
27962801
$remember = true;
27972802
}
27982803

2799-
wp_set_auth_cookie( $user_id, $remember );
2804+
wp_set_auth_cookie( $user_id, $remember, '', $token );
28002805
}
28012806
}
28022807

tests/phpunit/tests/user.php

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,37 @@ public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
6363
public function set_up() {
6464
parent::set_up();
6565

66+
add_action( 'set_auth_cookie', array( $this, 'action_set_auth_cookie' ), 10, 6 );
67+
add_action( 'set_logged_in_cookie', array( $this, 'action_set_logged_in_cookie' ), 10 );
68+
add_action( 'clear_auth_cookie', array( $this, 'action_clear_auth_cookie' ) );
69+
70+
$_COOKIE = array();
71+
6672
$this->author = clone self::$_author;
6773
}
6874

75+
final public function action_set_auth_cookie(
76+
string $cookie,
77+
int $expire,
78+
int $expiration,
79+
int $user_id,
80+
string $scheme,
81+
string $token
82+
): void {
83+
$_COOKIE[ SECURE_AUTH_COOKIE ] = $cookie;
84+
$_COOKIE[ AUTH_COOKIE ] = $cookie;
85+
}
86+
87+
final public function action_set_logged_in_cookie( string $cookie ): void {
88+
$_COOKIE[ LOGGED_IN_COOKIE ] = $cookie;
89+
}
90+
91+
final public function action_clear_auth_cookie(): void {
92+
unset( $_COOKIE[ LOGGED_IN_COOKIE ] );
93+
unset( $_COOKIE[ SECURE_AUTH_COOKIE ] );
94+
unset( $_COOKIE[ AUTH_COOKIE ] );
95+
}
96+
6997
public function test_get_users_of_blog() {
7098
// Add one of each user role.
7199
$nusers = array(
@@ -1122,6 +1150,50 @@ public function test_changing_password_invalidates_password_reset_key() {
11221150
$this->assertEmpty( $user->user_activation_key );
11231151
}
11241152

1153+
/**
1154+
* @ticket 61366
1155+
* @dataProvider data_remember_user
1156+
*/
1157+
public function test_changing_own_password_retains_current_session( bool $remember ) {
1158+
$user = $this->author;
1159+
$manager = WP_Session_Tokens::get_instance( $user->ID );
1160+
$expiry = $remember ? ( 2 * WEEK_IN_SECONDS ) : ( 2 * DAY_IN_SECONDS );
1161+
$token = $manager->create( time() + $expiry );
1162+
$pass = $user->user_pass;
1163+
1164+
wp_set_current_user( $user->ID );
1165+
wp_set_auth_cookie( $user->ID, $remember, '', $token );
1166+
1167+
$cookie = $_COOKIE[ AUTH_COOKIE ];
1168+
$userdata = array(
1169+
'ID' => $user->ID,
1170+
'user_pass' => 'my_new_password',
1171+
);
1172+
$updated = wp_update_user( $userdata, $manager );
1173+
$parsed = wp_parse_auth_cookie();
1174+
1175+
// Check the prerequisites:
1176+
$this->assertNotWPError( $updated );
1177+
$this->assertNotSame( $pass, get_userdata( $user->ID )->user_pass );
1178+
1179+
// Check the session token:
1180+
$this->assertSame( $token, $parsed['token'] );
1181+
$this->assertCount( 1, $manager->get_all() );
1182+
1183+
// Check that the newly set auth cookie is valid:
1184+
$this->assertSame( $user->ID, wp_validate_auth_cookie() );
1185+
1186+
// Check that, despite the session token reuse, the old auth cookie should now be invalid because the password changed:
1187+
$this->assertFalse( wp_validate_auth_cookie( $cookie ) );
1188+
}
1189+
1190+
public function data_remember_user() {
1191+
return array(
1192+
array( true ),
1193+
array( false ),
1194+
);
1195+
}
1196+
11251197
public function test_search_users_login() {
11261198
$users = get_users(
11271199
array(

0 commit comments

Comments
 (0)