diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 048bb2fbd40..26034be6b46 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -23,6 +23,8 @@ Drupal 7.50, xxxx-xx-xx (development version) - Improved performance of queries on authmap table. - Numerous small bugfixes. - Numerous API documentation improvements. +- Fixed that following a password reset link while logged in leaves users unable + to change their password Drupal 7.44, 2016-06-15 ----------------------- diff --git a/modules/user/user.pages.inc b/modules/user/user.pages.inc index 2d3c13d00b2..1ae63fb15f6 100644 --- a/modules/user/user.pages.inc +++ b/modules/user/user.pages.inc @@ -44,6 +44,12 @@ function user_pass() { $form['name']['#value'] = $user->mail; $form['mail'] = array( '#prefix' => '
', + // As of https://www.drupal.org/node/889772 the user no longer must log + // out (if they are still logged in when using the password reset link, + // they will be logged out automatically then), but this text is kept as + // is to avoid breaking translations as well as to encourage the user to + // log out manually at a time of their own choosing (when it will not + // interrupt anything else they may have been in the middle of doing). '#markup' => t('Password reset instructions will be mailed to %email. You must log out to use the password reset link in the e-mail.', array('%email' => $user->mail)), '#suffix' => '
', ); @@ -96,9 +102,20 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a // When processing the one-time login link, we have to make sure that a user // isn't already logged in. if ($user->uid) { - // The existing user is already logged in. + // The existing user is already logged in. Log them out and reload the + // current page so the password reset process can continue. if ($user->uid == $uid) { - drupal_set_message(t('You are logged in as %user. Change your password.', array('%user' => $user->name, '!user_edit' => url("user/$user->uid/edit")))); + // Preserve the current destination (if any) and ensure the redirect goes + // back to the current page; any custom destination set in + // hook_user_logout() and intended for regular logouts would not be + // appropriate here. + $destination = array(); + if (isset($_GET['destination'])) { + $destination = drupal_get_destination(); + } + user_logout_current_user(); + unset($_GET['destination']); + drupal_goto(current_path(), array('query' => drupal_get_query_parameters() + $destination)); } // A different user is already logged in on the computer. else { @@ -110,8 +127,8 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a // Invalid one-time link specifies an unknown user. drupal_set_message(t('The one-time login link you clicked is invalid.'), 'error'); } + drupal_goto(); } - drupal_goto(); } else { // Time out, in seconds, until login URL expires. Defaults to 24 hours = @@ -168,6 +185,14 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a * Menu callback; logs the current user out, and redirects to the home page. */ function user_logout() { + user_logout_current_user(); + drupal_goto(); +} + +/** + * Logs the current user out. + */ +function user_logout_current_user() { global $user; watchdog('user', 'Session closed for %name.', array('%name' => $user->name)); @@ -176,8 +201,6 @@ function user_logout() { // Destroy the current session, and reset $user to the anonymous user. session_destroy(); - - drupal_goto(); } /** diff --git a/modules/user/user.test b/modules/user/user.test index b9729c507f6..136f3c7e2e5 100644 --- a/modules/user/user.test +++ b/modules/user/user.test @@ -480,6 +480,34 @@ class UserPasswordResetTestCase extends DrupalWebTestCase { $this->assertText(t('Further instructions have been sent to your e-mail address.'), 'Password reset instructions mailed message displayed.'); } + /** + * Test user password reset while logged in. + */ + function testUserPasswordResetLoggedIn() { + $account = $this->drupalCreateUser(); + $this->drupalLogin($account); + // Make sure the test account has a valid password. + user_save($account, array('pass' => user_password())); + + // Generate one time login link. + $reset_url = user_pass_reset_url($account); + $this->drupalGet($reset_url); + + $this->assertText('Reset password'); + $this->drupalPost(NULL, NULL, t('Log in')); + + $this->assertText('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'); + + $pass = user_password(); + $edit = array( + 'pass[pass1]' => $pass, + 'pass[pass2]' => $pass, + ); + $this->drupalPost(NULL, $edit, t('Save')); + + $this->assertText('The changes have been saved.'); + } + /** * Attempts login using an expired password reset link. */