Failure reset time is applied to Permanent Lockout
Closes #28821 Signed-off-by: Douglas Palmer <dpalmer@redhat.com>
This commit is contained in:
parent
b08c644601
commit
ed22530d16
2 changed files with 76 additions and 1 deletions
|
@ -70,7 +70,7 @@ public class DefaultBruteForceProtector implements BruteForceProtector {
|
|||
}
|
||||
userLoginFailure.setLastFailure(failureTime);
|
||||
|
||||
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();
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.keycloak.OAuth2Constants;
|
|||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.Errors;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.executors.ExecutorsProvider;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.TimeBasedOTP;
|
||||
|
@ -51,8 +52,11 @@ import org.keycloak.testsuite.util.RealmRepUtil;
|
|||
import org.keycloak.testsuite.util.UserBuilder;
|
||||
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
@ -402,6 +406,77 @@ public class BruteForceTest extends AbstractTestRealmKeycloakTest {
|
|||
loginSuccess();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailureResetForTemporaryLockout() throws Exception {
|
||||
RealmRepresentation realm = testRealm().toRepresentation();
|
||||
try {
|
||||
realm.setMaxDeltaTimeSeconds(5);
|
||||
testRealm().update(realm);
|
||||
long numExecutors = getNumExecutors();
|
||||
loginInvalidPassword();
|
||||
|
||||
//Wait for brute force executor to process the login and then wait for delta time
|
||||
waitForExecutors(numExecutors+1);
|
||||
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);
|
||||
long numExecutors = getNumExecutors();
|
||||
loginInvalidPassword();
|
||||
|
||||
//Wait for brute force executor to process the login and then wait for delta time
|
||||
waitForExecutors(numExecutors+1);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private long getNumExecutors() {
|
||||
String numExecutors = testingClient.server().fetchString(session -> {
|
||||
ExecutorsProvider provider = session.getProvider(ExecutorsProvider.class);
|
||||
ExecutorService executor = provider.getExecutor("bruteforce");
|
||||
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
|
||||
return threadPoolExecutor.getTaskCount();
|
||||
});
|
||||
return Long.valueOf(numExecutors);
|
||||
}
|
||||
|
||||
private void waitForExecutors(long numExecutors) {
|
||||
testingClient.server().run(session -> {
|
||||
ExecutorsProvider provider = session.getProvider(ExecutorsProvider.class);
|
||||
ExecutorService executor = provider.getExecutor("bruteforce");
|
||||
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
|
||||
while(!threadPoolExecutor.getQueue().isEmpty()) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
assertEquals(numExecutors, threadPoolExecutor.getCompletedTaskCount());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWait() throws Exception {
|
||||
loginSuccess();
|
||||
|
|
Loading…
Reference in a new issue