diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/AbstractUsernameFormAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/AbstractUsernameFormAuthenticator.java
index 72c10f5..6b6da56 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/AbstractUsernameFormAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/AbstractUsernameFormAuthenticator.java
@@ -125,7 +125,9 @@ public abstract class AbstractUsernameFormAuthenticator extends AbstractFormAuth
context.getEvent().user(user);
context.getEvent().error(Errors.USER_DISABLED);
Response challengeResponse = disabledUser(context);
- context.failureChallenge(AuthenticationFlowError.USER_DISABLED, challengeResponse);
+ // this is not a failure so don't call failureChallenge.
+ //context.failureChallenge(AuthenticationFlowError.USER_DISABLED, challengeResponse);
+ context.forceChallenge(challengeResponse);
return false;
}
if (context.getRealm().isBruteForceProtected()) {
@@ -133,7 +135,9 @@ public abstract class AbstractUsernameFormAuthenticator extends AbstractFormAuth
context.getEvent().user(user);
context.getEvent().error(Errors.USER_TEMPORARILY_DISABLED);
Response challengeResponse = temporarilyDisabledUser(context);
- context.failureChallenge(AuthenticationFlowError.USER_TEMPORARILY_DISABLED, challengeResponse);
+ // this is not a failure so don't call failureChallenge.
+ //context.failureChallenge(AuthenticationFlowError.USER_TEMPORARILY_DISABLED, challengeResponse);
+ context.forceChallenge(challengeResponse);
return false;
}
}
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 a8fe41b..7b65a0c 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
@@ -45,6 +45,7 @@ import org.keycloak.testsuite.util.RealmRepUtil;
import org.keycloak.testsuite.util.UserBuilder;
import java.net.MalformedURLException;
+import java.util.Collections;
import static org.junit.Assert.assertEquals;
@@ -67,6 +68,10 @@ public class BruteForceTest extends AbstractTestRealmKeycloakTest {
testRealm.setBruteForceProtected(true);
testRealm.setFailureFactor(2);
+ testRealm.setMaxDeltaTimeSeconds(20);
+ testRealm.setMaxFailureWaitSeconds(100);
+ testRealm.setWaitIncrementSeconds(5);
+ //testRealm.setQuickLoginCheckMilliSeconds(0L);
userId = user.getId();
@@ -76,11 +81,40 @@ public class BruteForceTest extends AbstractTestRealmKeycloakTest {
@Before
public void config() {
+ try {
+ clearUserFailures();
+ clearAllUserFailures();
+ RealmRepresentation realm = adminClient.realm("test").toRepresentation();
+ realm.setFailureFactor(2);
+ realm.setMaxDeltaTimeSeconds(20);
+ realm.setMaxFailureWaitSeconds(100);
+ realm.setWaitIncrementSeconds(5);
+ adminClient.realm("test").update(realm);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ events.clear();
}
@After
public void slowItDown() throws Exception {
+ try {
+ clearUserFailures();
+ clearAllUserFailures();
+ RealmRepresentation realm = adminClient.realm("test").toRepresentation();
+ realm.setMaxFailureWaitSeconds(900);
+ realm.setMinimumQuickLoginWaitSeconds(60);
+ realm.setWaitIncrementSeconds(60);
+ realm.setQuickLoginCheckMilliSeconds(1000L);
+ realm.setMaxDeltaTimeSeconds(60 * 60 * 12); // 12 hours
+ realm.setFailureFactor(30);
+ adminClient.realm("test").update(realm);
+ testingClient.testing().setTimeOffset(Collections.singletonMap("offset", String.valueOf(0)));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ events.clear();
Thread.sleep(100);
}
@@ -287,6 +321,23 @@ public class BruteForceTest extends AbstractTestRealmKeycloakTest {
}
@Test
+ public void testWait() throws Exception {
+ loginSuccess();
+ loginInvalidPassword();
+ loginInvalidPassword();
+ expectTemporarilyDisabled();
+ // KEYCLOAK-5420
+ // Test to make sure that temporarily disabled doesn't increment failure count
+ testingClient.testing().setTimeOffset(Collections.singletonMap("offset", String.valueOf(6)));
+ // should be unlocked now
+ loginSuccess();
+ clearUserFailures();
+ clearAllUserFailures();
+ loginSuccess();
+ testingClient.testing().setTimeOffset(Collections.singletonMap("offset", String.valueOf(0)));
+ }
+
+ @Test
public void testBrowserInvalidPasswordDifferentCase() throws Exception {
loginSuccess("test-user@localhost");
loginInvalidPassword("test-User@localhost");