diff --git a/core/modules/user/lib/Drupal/user/Tests/UserPasswordResetTest.php b/core/modules/user/lib/Drupal/user/Tests/UserPasswordResetTest.php index bb70f78..b33d82c 100644 --- a/core/modules/user/lib/Drupal/user/Tests/UserPasswordResetTest.php +++ b/core/modules/user/lib/Drupal/user/Tests/UserPasswordResetTest.php @@ -35,6 +35,28 @@ function testUserPasswordReset() { $this->drupalPost('user/password', $edit, t('E-mail new password')); // Confirm the password reset. $this->assertText(t('Further instructions have been sent to your e-mail address.'), 'Password reset instructions mailed message displayed.'); + + // Log in the user using password reset url. + $account = $this->drupalCreateUser(); + $edit = array(); + $user_pass_reset_url = function($account) { + $timestamp = REQUEST_TIME; + return "user/reset/$account->uid/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login); + }; + $this->drupalPost($user_pass_reset_url($account), $edit, t('Log in')); + $this->assertText(t('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.'), 'One time login completed.'); + $this->drupalLogout(); + + $account = $this->drupalCreateUser(); + $new_password = user_password(); + $edit = array( + 'pass[pass1]' => $new_password, + 'pass[pass2]' => $new_password, + ); + $this->drupalPost($user_pass_reset_url($account), $edit, t('Log in')); + $this->assertText(t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Your password has been updated.'), 'One time login with password reset completed.'); + $account = user_load($account->uid, TRUE); + $this->assertTrue(user_check_password($new_password, $account), 'Password reset successful.'); } /** diff --git a/core/modules/user/user.module b/core/modules/user/user.module index 6911853..5c254b4 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -1163,8 +1163,8 @@ function user_menu() { ); $items['user/reset/%/%/%'] = array( 'title' => 'Reset password', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('user_pass_reset', 2, 3, 4), + 'page callback' => 'user_pass_reset', + 'page arguments' => array(2, 3, 4), 'access callback' => TRUE, 'type' => MENU_CALLBACK, 'file' => 'user.pages.inc', diff --git a/core/modules/user/user.pages.inc b/core/modules/user/user.pages.inc index 20af863..989ece7 100644 --- a/core/modules/user/user.pages.inc +++ b/core/modules/user/user.pages.inc @@ -95,7 +95,7 @@ function user_pass_submit($form, &$form_state) { /** * Menu callback; process one time login link and redirects to the user page on success. */ -function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $action = NULL) { +function user_pass_reset($uid, $timestamp, $hashed_pass, $action = NULL) { global $user; // When processing the one-time login link, we have to make sure that a user @@ -131,28 +131,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a drupal_goto('user/password'); } elseif ($account->uid && $timestamp >= $account->login && $timestamp <= $current && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) { - // First stage is a confirmation form, then login - if ($action == 'login') { - // Set the new user. - $user = $account; - // user_login_finalize() also updates the login timestamp of the - // user, which invalidates further use of the one-time login link. - user_login_finalize(); - watchdog('user', 'User %name used one-time login link at time %timestamp.', array('%name' => $account->name, '%timestamp' => $timestamp)); - drupal_set_message(t('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.')); - // Let the user's password be changed without the current password check. - $token = drupal_hash_base64(drupal_random_bytes(55)); - $_SESSION['pass_reset_' . $user->uid] = $token; - drupal_goto('user/' . $user->uid . '/edit', array('query' => array('pass-reset-token' => $token))); - } - else { - $form['message'] = array('#markup' => t('

This is a one-time login for %user_name and will expire on %expiration_date.

Click on this button to log in to the site and change your password.

', array('%user_name' => $account->name, '%expiration_date' => format_date($timestamp + $timeout)))); - $form['help'] = array('#markup' => '

' . t('This login can be used only once.') . '

'); - $form['actions'] = array('#type' => 'actions'); - $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Log in')); - $form['#action'] = url("user/reset/$uid/$timestamp/$hashed_pass/login"); - return $form; - } + return drupal_get_form('user_pass_reset_form', $account, $timestamp, $timeout); } else { drupal_set_message(t('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.')); @@ -168,6 +147,55 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a } /** + * One time login form to log in the user. + */ +function user_pass_reset_form($form, &$form_state, $account, $timestamp, $timeout) { + $form['#account'] = $account; + $form['message'] = array( + '#markup' => t('

This is a one-time login for %user_name and will expire on %expiration_date.

Click on this button to log in to the site.

', array('%user_name' => $account->name, '%expiration_date' => format_date($timestamp + $timeout))), + ); + $form['help'] = array( + '#markup' => '

' . t('This login can be used only once.') . '

' + ); + $form['pass'] = array( + '#type' => 'password_confirm', + ); + $form['actions'] = array( + '#type' => 'actions', + ); + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Log in'), + ); + return $form; +} + +/** + * Logs in the user and changes the password if provided. + */ +function user_pass_reset_form_submit($form, &$form_state) { + global $user; + $user = $form['#account']; + // user_login_finalize() also updates the login timestamp of the + // user, which invalidates further use of the one-time login link. + user_login_finalize(); + watchdog('user', 'User %name used one-time login link.', array('%name' => $form['#account']->name)); + if (empty($form_state['values']['pass'])) { + drupal_set_message(t('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.')); + // Let the user's password be changed without the current password check. + $token = drupal_hash_base64(drupal_random_bytes(55)); + $_SESSION['pass_reset_' . $user->uid] = $token; + drupal_goto('user/' . $user->uid . '/edit', array('query' => array('pass-reset-token' => $token))); + } + else { + $user->pass = $form_state['values']['pass']; + $user->save(); + drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Your password has been updated.')); + drupal_goto(); + } +} + +/** * Menu callback; logs the current user out, and redirects to the home page. */ function user_logout() {