From 3500618ee24e0f355711075d55555cbc843583ce Mon Sep 17 00:00:00 2001 From: Douglas Palmer Date: Tue, 16 Apr 2024 12:05:22 -0700 Subject: [PATCH] Failure reset time is applied to Permanent Lockout Closes #28821 Signed-off-by: Douglas Palmer --- .../managers/DefaultBruteForceProtector.java | 2 +- .../testsuite/forms/BruteForceTest.java | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/services/src/main/java/org/keycloak/services/managers/DefaultBruteForceProtector.java b/services/src/main/java/org/keycloak/services/managers/DefaultBruteForceProtector.java index d10a5c974343..b8c797208d28 100644 --- a/services/src/main/java/org/keycloak/services/managers/DefaultBruteForceProtector.java +++ b/services/src/main/java/org/keycloak/services/managers/DefaultBruteForceProtector.java @@ -168,7 +168,7 @@ protected void failure(KeycloakSession session, LoginEvent event) { } userLoginFailure.setLastFailure(currentTime); - if (deltaTime > 0) { + if (!(realm.isPermanentLockout() && realm.getMaxTemporaryLockouts() == 0) && deltaTime > 0) { // if last failure was more than MAX_DELTA clear failures if (deltaTime > (long) realm.getMaxDeltaTimeSeconds() * 1000L) { userLoginFailure.clearFailures(); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java index c88a66adfac8..f1f59ec3efac 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java @@ -402,6 +402,47 @@ public void testBrowserInvalidPassword() throws Exception { loginSuccess(); } + @Test + public void testFailureResetForTemporaryLockout() throws Exception { + RealmRepresentation realm = testRealm().toRepresentation(); + try { + realm.setMaxDeltaTimeSeconds(5); + testRealm().update(realm); + loginInvalidPassword(); + + testingClient.testing().setTimeOffset(Collections.singletonMap("offset", String.valueOf(5))); + + loginInvalidPassword(); + loginSuccess(); + } finally { + realm.setMaxDeltaTimeSeconds(20); + testRealm().update(realm); + } + } + + @Test + public void testNoFailureResetForPermanentLockout() throws Exception { + RealmRepresentation realm = testRealm().toRepresentation(); + try { + realm.setMaxDeltaTimeSeconds(5); + realm.setPermanentLockout(true); + testRealm().update(realm); + loginInvalidPassword(); + + testingClient.testing().setTimeOffset(Collections.singletonMap("offset", String.valueOf(5))); + + loginInvalidPassword(); + expectPermanentlyDisabled(); + } finally { + realm.setPermanentLockout(false); + realm.setMaxDeltaTimeSeconds(20); + testRealm().update(realm); + UserRepresentation user = adminClient.realm("test").users().search("test-user@localhost", 0, 1).get(0); + user.setEnabled(true); + updateUser(user); + } + } + @Test public void testWait() throws Exception { loginSuccess();