From f7b910aafdf9a3e69cc9e00237b8404ff541ffcf Mon Sep 17 00:00:00 2001 From: catch Date: Tue, 10 Jan 2023 15:02:09 +0000 Subject: [PATCH] Issue #992540 by valthebald, ndobromirov, jec006, kid_icarus, rickmanelius, mr.baileys, pguillard, joseph.olstad, vijaycs85, paulocs, voleger, Matt V., aerozeppelin, ravi.shankar, quietone, Munavijayalakshmi, ranjith_kumar_k_u, evilehk, swentel, gaurav.kapoor, yogeshmpawar, klidifia, pradhumanjainOSL, louis-cuny, catch, Everett Zufelt, alexpott, cilefen, xjm, grendzy, cashwilliams, borisson_, lachezar.valchev, tstoeckler, Heine: Nothing clears the "5 failed login attempts" security message when a user resets their own password (cherry picked from commit a8729aad07ec430e0c2173bac458cda40f044e2c) --- .../user/src/Controller/UserController.php | 11 +++++ .../tests/src/Functional/UserLoginTest.php | 40 ++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/core/modules/user/src/Controller/UserController.php b/core/modules/user/src/Controller/UserController.php index ec5b1ccfad0..05be8f9db87 100644 --- a/core/modules/user/src/Controller/UserController.php +++ b/core/modules/user/src/Controller/UserController.php @@ -235,6 +235,17 @@ class UserController extends ControllerBase { return $redirect; } + $flood_config = $this->config('user.flood'); + if ($flood_config->get('uid_only')) { + $identifier = $user->id(); + } + else { + $identifier = $user->id() . '-' . $request->getClientIP(); + } + + $this->flood->clear('user.failed_login_user', $identifier); + $this->flood->clear('user.http_login', $identifier); + user_login_finalize($user); $this->logger->notice('User %name used one-time login link at time %timestamp.', ['%name' => $user->getDisplayName(), '%timestamp' => $timestamp]); $this->messenger()->addStatus($this->t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please set your password.')); diff --git a/core/modules/user/tests/src/Functional/UserLoginTest.php b/core/modules/user/tests/src/Functional/UserLoginTest.php index d2a892fe3fe..3284dc9ce0c 100644 --- a/core/modules/user/tests/src/Functional/UserLoginTest.php +++ b/core/modules/user/tests/src/Functional/UserLoginTest.php @@ -2,6 +2,7 @@ namespace Drupal\Tests\user\Functional; +use Drupal\Core\Test\AssertMailTrait; use Drupal\Core\Url; use Drupal\Tests\BrowserTestBase; use Drupal\user\Entity\User; @@ -14,6 +15,10 @@ use Drupal\user\UserInterface; */ class UserLoginTest extends BrowserTestBase { + use AssertMailTrait { + getMails as drupalGetMails; + } + /** * {@inheritdoc} */ @@ -75,6 +80,13 @@ class UserLoginTest extends BrowserTestBase { // A login with the correct password should also result in a flood error // message. $this->assertFailedLogin($user1, 'ip'); + + // A login attempt after resetting the password should still fail, since the + // IP-based flood control count is not cleared after a password reset. + $this->resetUserPassword($user1); + $this->drupalLogout(); + $this->assertFailedLogin($user1, 'ip'); + $this->assertSession()->responseContains('Too many failed login attempts from your IP address.'); } /** @@ -98,7 +110,8 @@ class UserLoginTest extends BrowserTestBase { $this->assertFailedLogin($incorrect_user1); } - // A successful login will reset the per-user flood control count. + // We're not going to test resetting the password which should clear the + // flood table and allow the user to log in again. $this->drupalLogin($user1); $this->drupalLogout(); @@ -115,6 +128,12 @@ class UserLoginTest extends BrowserTestBase { // Try one more attempt for user 1, it should be rejected, even if the // correct password has been used. $this->assertFailedLogin($user1, 'user'); + $this->resetUserPassword($user1); + $this->drupalLogout(); + + // Try to log in as user 1, it should be successful. + $this->drupalLogin($user1); + $this->assertSession()->responseContains('Member for'); } /** @@ -300,4 +319,23 @@ class UserLoginTest extends BrowserTestBase { } } + /** + * Reset user password. + * + * @param object $user + * A user object. + */ + public function resetUserPassword($user) { + $this->drupalGet('user/password'); + $edit['name'] = $user->getDisplayName(); + $this->submitForm($edit, 'Submit'); + $_emails = $this->drupalGetMails(); + $email = end($_emails); + $urls = []; + preg_match('#.+user/reset/.+#', $email['body'], $urls); + $resetURL = $urls[0]; + $this->drupalGet($resetURL); + $this->submitForm([], 'Log in'); + } + }