diff --git a/core/modules/user/src/Controller/UserController.php b/core/modules/user/src/Controller/UserController.php index 74d59da..183650b 100644 --- a/core/modules/user/src/Controller/UserController.php +++ b/core/modules/user/src/Controller/UserController.php @@ -99,7 +99,7 @@ public function resetPass($uid, $timestamp, $hash) { /** * Redirects to the user password reset form. * - * In order to never disclose a redirect link via a referrer header this + * In order to never disclose a reset link via a referrer header this * controller must always return a redirect response. * * @param \Symfony\Component\HttpFoundation\Request $request @@ -113,18 +113,8 @@ public function resetPass($uid, $timestamp, $hash) { * * @return \Symfony\Component\HttpFoundation\RedirectResponse * The redirect response. - * - * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException - * If the login link is for a blocked user or invalid user ID. */ public function resetPassRedirect(Request $request, $uid, $timestamp, $hash) { - $reset_link_user = $this->userStorage->load($uid); - if ($reset_link_user === NULL || !$reset_link_user->isActive()) { - // Blocked or invalid user ID, so deny access. The parameters will be in the - // watchdog's URL for the administrator to check. - throw new AccessDeniedHttpException(); - } - $account = $this->currentUser(); // When processing the one-time login link, we have to make sure that a user // isn't already logged in. @@ -145,9 +135,17 @@ public function resetPassRedirect(Request $request, $uid, $timestamp, $hash) { } // A different user is already logged in on the computer. else { - drupal_set_message($this->t('Another user (%other_user) is already logged into the site on this computer, but you tried to use a one-time link for user %resetting_user. Please log out and try using the link again.', - array('%other_user' => $account->getUsername(), '%resetting_user' => $reset_link_user->getUsername(), ':logout' => $this->url('user.logout'))), 'warning'); - + /** @var \Drupal\user\UserInterface $reset_link_user */ + if ($reset_link_user = $this->userStorage->load($uid)) { + drupal_set_message($this->t( + 'Another user (%other_user) is already logged into the site on this computer, but you tried to use a one-time link for user %resetting_user. Please log out and try using the link again.', + ['%other_user' => $account->getUsername(), '%resetting_user' => $reset_link_user->getUsername(), ':logout' => $this->url('user.logout')] + ), 'warning'); + } + else { + // Invalid one-time link specifies an unknown user. + drupal_set_message($this->t('The one-time login link you clicked is invalid.'), 'error'); + } return $this->redirect(''); } } @@ -185,11 +183,15 @@ public function getResetPassForm($uid, Request $request) { // the user does not click on the log in button on the form. $session->remove('pass_reset_timeout'); $session->remove('pass_reset_hash'); + if (!$hash || !$timestamp) { + throw new AccessDeniedHttpException(); + } /** @var \Drupal\user\UserInterface $user */ $user = $this->userStorage->load($uid); - - if (!$hash || !$timestamp || $user === NULL || !$user->isActive()) { + if ($user === NULL || !$user->isActive()) { + // Blocked or invalid user ID, so deny access. The parameters will be in + // the watchdog's URL for the administrator to check. throw new AccessDeniedHttpException(); } diff --git a/core/modules/user/src/Tests/UserPasswordResetTest.php b/core/modules/user/src/Tests/UserPasswordResetTest.php index 979be75..a26790d 100644 --- a/core/modules/user/src/Tests/UserPasswordResetTest.php +++ b/core/modules/user/src/Tests/UserPasswordResetTest.php @@ -2,6 +2,7 @@ namespace Drupal\user\Tests; +use Drupal\Component\Render\FormattableMarkup; use Drupal\Core\Url; use Drupal\system\Tests\Cache\PageCacheTagsTestBase; use Drupal\user\Entity\User; @@ -217,6 +218,25 @@ public function getResetURL() { * Test user password reset while logged in. */ public function testUserPasswordResetLoggedIn() { + $another_account = $this->drupalCreateUser(); + $this->drupalLogin($another_account); + $this->drupalGet('user/password'); + $this->drupalPostForm(NULL, NULL, t('Submit')); + + // Click the reset URL while logged and change our password. + $resetURL = $this->getResetURL(); + // Log in as a different user. + $this->drupalLogin($this->account); + $this->drupalGet($resetURL); + $this->assertRaw(new FormattableMarkup( + 'Another user (%other_user) is already logged into the site on this computer, but you tried to use a one-time link for user %resetting_user. Please log out and try using the link again.', + ['%other_user' => $this->account->getUsername(), '%resetting_user' => $another_account->getUsername(), ':logout' => Url::fromRoute('user.logout')->toString()] + )); + + $another_account->delete(); + $this->drupalGet($resetURL); + $this->assertText('The one-time login link you clicked is invalid.'); + // Log in. $this->drupalLogin($this->account); @@ -234,6 +254,8 @@ public function testUserPasswordResetLoggedIn() { $edit = array('pass[pass1]' => $password, 'pass[pass2]' => $password); $this->drupalPostForm(NULL, $edit, t('Save')); $this->assertText(t('The changes have been saved.'), 'Password changed.'); + + $this->drupalLogin($this->drupalCreateUser()); } /**