From 4b0e870890c32ca39ae113eecbc218385d71eb73 Mon Sep 17 00:00:00 2001
From: Lee Rowlands <lee.rowlands@previousnext.com.au>
Date: Thu, 20 Jul 2023 17:43:53 +1000
Subject: [PATCH] Issue #2414187 by BramDriesen, cussack: User email disclosure
 in /user/password

---
 core/modules/user/src/Form/UserLoginForm.php        |  8 +-------
 .../tests/src/Functional/UserPasswordResetTest.php  | 13 +++++++++----
 2 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/core/modules/user/src/Form/UserLoginForm.php b/core/modules/user/src/Form/UserLoginForm.php
index cde450c11222..bf1357007a12 100644
--- a/core/modules/user/src/Form/UserLoginForm.php
+++ b/core/modules/user/src/Form/UserLoginForm.php
@@ -249,13 +249,7 @@ public function validateFinal(array &$form, FormStateInterface $form_state) {
         $form_state->setResponse($response);
       }
       else {
-        // Use $form_state->getUserInput() in the error message to guarantee
-        // that we send exactly what the user typed in. The value from
-        // $form_state->getValue() may have been modified by validation
-        // handlers that ran earlier than this one.
-        $user_input = $form_state->getUserInput();
-        $query = isset($user_input['name']) ? ['name' => $user_input['name']] : [];
-        $form_state->setErrorByName('name', $this->t('Unrecognized username or password. <a href=":password">Forgot your password?</a>', [':password' => Url::fromRoute('user.pass', [], ['query' => $query])->toString()]));
+        $form_state->setErrorByName('name', $this->t('Unrecognized username or password. <a href=":password">Forgot your password?</a>', [':password' => Url::fromRoute('user.pass')->toString()]));
         $accounts = $this->userStorage->loadByProperties(['name' => $form_state->getValue('name')]);
         if (!empty($accounts)) {
           $this->logger('user')->notice('Login attempt failed for %user.', ['%user' => $form_state->getValue('name')]);
diff --git a/core/modules/user/tests/src/Functional/UserPasswordResetTest.php b/core/modules/user/tests/src/Functional/UserPasswordResetTest.php
index 0afa8df352ef..7d386d095545 100644
--- a/core/modules/user/tests/src/Functional/UserPasswordResetTest.php
+++ b/core/modules/user/tests/src/Functional/UserPasswordResetTest.php
@@ -371,9 +371,9 @@ public function testUserPasswordResetLoggedIn() {
   }
 
   /**
-   * Prefill the text box on incorrect login via link to password reset page.
+   * Tests the text box on incorrect login via link to password reset page.
    */
-  public function testUserResetPasswordTextboxFilled() {
+  public function testUserResetPasswordTextboxNotFilled() {
     $this->drupalGet('user/login');
     $edit = [
       'name' => $this->randomMachineName(),
@@ -383,11 +383,16 @@ public function testUserResetPasswordTextboxFilled() {
     $this->submitForm($edit, 'Log in');
     $this->assertSession()->pageTextContains("Unrecognized username or password. Forgot your password?");
     $this->assertSession()->linkExists("Forgot your password?");
-    $this->assertSession()->linkByHrefExists(Url::fromRoute('user.pass', [], ['query' => ['name' => $edit['name']]])->toString());
+    // Verify we don't pass the username as a query parameter.
+    $this->assertSession()->linkByHrefNotExists(Url::fromRoute('user.pass', [], ['query' => ['name' => $edit['name']]])->toString());
+    $this->assertSession()->linkByHrefExists(Url::fromRoute('user.pass')->toString());
     unset($edit['pass']);
+    // Verify the field is empty by default.
+    $this->drupalGet('user/password');
+    $this->assertSession()->fieldValueEquals('name', '');
+    // Ensure the name field value is not cached.
     $this->drupalGet('user/password', ['query' => ['name' => $edit['name']]]);
     $this->assertSession()->fieldValueEquals('name', $edit['name']);
-    // Ensure the name field value is not cached.
     $this->drupalGet('user/password');
     $this->assertSession()->fieldValueNotEquals('name', $edit['name']);
   }
-- 
GitLab