Browse Source

implemented brute force protection

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
devel
Stephan Richter 1 month ago
parent
commit
a10224a23e
  1. 21
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/UserService.java
  2. 12
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/data/Lock.java
  3. 6
      de.srsoftware.oidc.datastore.encrypted/src/main/java/de/srsoftware/oidc/datastore/encrypted/EncryptedUserService.java

21
de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/UserService.java

@ -4,13 +4,13 @@ package de.srsoftware.oidc.api; @@ -4,13 +4,13 @@ package de.srsoftware.oidc.api;
import static java.util.Optional.empty;
import de.srsoftware.oidc.api.data.AccessToken;
import de.srsoftware.oidc.api.data.FailedLogin;
import de.srsoftware.oidc.api.data.Lock;
import de.srsoftware.oidc.api.data.User;
import java.time.Instant;
import java.util.*;
public interface UserService {
Map<String, FailedLogin> failedLogins = new HashMap<>();
Map<String, Lock> failedLogins = new HashMap<>();
/**
* create a new access token for a given user
@ -30,25 +30,20 @@ public interface UserService { @@ -30,25 +30,20 @@ public interface UserService {
public UserService init(User defaultUser);
public List<User> list();
public Set<User> find(String idOrEmail);
public default Optional<FailedLogin> getLock(String id) {
var failedLogin = failedLogins.get(id);
public default Optional<Lock> getLock(String key) {
var failedLogin = failedLogins.get(key);
if (failedLogin == null || failedLogin.releaseTime().isBefore(Instant.now())) return empty();
return Optional.of(failedLogin);
}
public Optional<User> load(String id);
public Optional<User> login(String username, String password);
public default UserService lock(String id) {
var failedLogin = failedLogins.get(id);
if (failedLogin == null) {
failedLogins.put(id, failedLogin = new FailedLogin(id));
}
return this;
public default Lock lock(String key) {
return failedLogins.computeIfAbsent(key,k -> new Lock()).count();
}
public boolean passwordMatches(String plaintextPassword, User user);
public UserService save(User user);
public default UserService unlock(String id) {
failedLogins.remove(id);
public default UserService unlock(String key) {
failedLogins.remove(key);
return this;
}
public UserService updatePassword(User user, String plaintextPassword);

12
de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/data/FailedLogin.java → de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/data/Lock.java

@ -3,23 +3,21 @@ package de.srsoftware.oidc.api.data; @@ -3,23 +3,21 @@ package de.srsoftware.oidc.api.data;
import java.time.Instant;
public class FailedLogin {
private final String userId;
public class Lock {
private int attempts;
private Instant releaseTime;
public FailedLogin(String userId) {
this.userId = userId;
public Lock() {
this.attempts = 0;
count();
}
public void count() {
public Lock count() {
attempts++;
if (attempts > 13) attempts = 13;
var seconds = 1;
var seconds = 5;
for (long i = 0; i < attempts; i++) seconds *= 2;
releaseTime = Instant.now().plusSeconds(seconds);
return this;
}
public int attempts() {

6
de.srsoftware.oidc.datastore.encrypted/src/main/java/de/srsoftware/oidc/datastore/encrypted/EncryptedUserService.java

@ -98,7 +98,7 @@ public class EncryptedUserService extends EncryptedConfig implements UserService @@ -98,7 +98,7 @@ public class EncryptedUserService extends EncryptedConfig implements UserService
var optLock = getLock(username);
if (optLock.isPresent()) {
var lock = optLock.get();
LOG.log(WARNING, "{} is locked after {} failed logins. Lock will be released at {}", username, lock.attempts(), lock.releaseTime());
LOG.log(WARNING, "{0} is locked after {1} failed logins. Lock will be released at {2}", username, lock.attempts(), lock.releaseTime());
return empty();
}
for (var encryptedUser : backend.list()) {
@ -109,7 +109,9 @@ public class EncryptedUserService extends EncryptedConfig implements UserService @@ -109,7 +109,9 @@ public class EncryptedUserService extends EncryptedConfig implements UserService
return Optional.of(decryptedUser);
}
}
lock(username);
var lock = lock(username);
LOG.log(WARNING,"Login failed for {0} → locking account until {1}",username,lock.releaseTime());
return empty();
}

Loading…
Cancel
Save