Add: Make Login Attempt Service deactivatable (#1747)

This commit is contained in:
Ludy 2024-08-23 15:46:09 +02:00 committed by GitHub
parent cdf31622e2
commit 33c7bb7e13
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 20 additions and 7 deletions

View file

@ -237,7 +237,7 @@ The Current list of settings is
security: security:
enableLogin: false # set to 'true' to enable login enableLogin: false # set to 'true' to enable login
csrfDisabled: true # Set to 'true' to disable CSRF protection (not recommended for production) csrfDisabled: true # Set to 'true' to disable CSRF protection (not recommended for production)
loginAttemptCount: 5 # lock user account after 5 tries loginAttemptCount: 5 # lock user account after 5 tries; when using e.g. Fail2Ban you can deactivate the function with -1
loginResetTimeMinutes: 120 # lock account for 2 hours after x attempts loginResetTimeMinutes: 120 # lock account for 2 hours after x attempts
loginMethod: all # 'all' (Login Username/Password and OAuth2[must be enabled and configured]), 'normal'(only Login with Username/Password) or 'oauth2'(only Login with OAuth2) loginMethod: all # 'all' (Login Username/Password and OAuth2[must be enabled and configured]), 'normal'(only Login with Username/Password) or 'oauth2'(only Login with OAuth2)
initialLogin: initialLogin:

View file

@ -7,21 +7,28 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.AttemptCounter; import stirling.software.SPDF.model.AttemptCounter;
@Service @Service
@Slf4j
public class LoginAttemptService { public class LoginAttemptService {
@Autowired ApplicationProperties applicationProperties; @Autowired private ApplicationProperties applicationProperties;
private int MAX_ATTEMPT; private int MAX_ATTEMPT;
private long ATTEMPT_INCREMENT_TIME; private long ATTEMPT_INCREMENT_TIME;
private ConcurrentHashMap<String, AttemptCounter> attemptsCache; private ConcurrentHashMap<String, AttemptCounter> attemptsCache;
private boolean isBlockedEnabled = true;
@PostConstruct @PostConstruct
public void init() { public void init() {
MAX_ATTEMPT = applicationProperties.getSecurity().getLoginAttemptCount(); MAX_ATTEMPT = applicationProperties.getSecurity().getLoginAttemptCount();
if (MAX_ATTEMPT == -1) {
isBlockedEnabled = false;
log.info("Login attempt tracking is disabled.");
}
ATTEMPT_INCREMENT_TIME = ATTEMPT_INCREMENT_TIME =
TimeUnit.MINUTES.toMillis( TimeUnit.MINUTES.toMillis(
applicationProperties.getSecurity().getLoginResetTimeMinutes()); applicationProperties.getSecurity().getLoginResetTimeMinutes());
@ -29,14 +36,16 @@ public class LoginAttemptService {
} }
public void loginSucceeded(String key) { public void loginSucceeded(String key) {
if (key == null || key.trim().isEmpty()) { if (!isBlockedEnabled || key == null || key.trim().isEmpty()) {
return; return;
} }
attemptsCache.remove(key.toLowerCase()); attemptsCache.remove(key.toLowerCase());
} }
public void loginFailed(String key) { public void loginFailed(String key) {
if (key == null || key.trim().isEmpty()) return; if (!isBlockedEnabled || key == null || key.trim().isEmpty()) {
return;
}
AttemptCounter attemptCounter = attemptsCache.get(key.toLowerCase()); AttemptCounter attemptCounter = attemptsCache.get(key.toLowerCase());
if (attemptCounter == null) { if (attemptCounter == null) {
@ -51,7 +60,9 @@ public class LoginAttemptService {
} }
public boolean isBlocked(String key) { public boolean isBlocked(String key) {
if (key == null || key.trim().isEmpty()) return false; if (!isBlockedEnabled || key == null || key.trim().isEmpty()) {
return false;
}
AttemptCounter attemptCounter = attemptsCache.get(key.toLowerCase()); AttemptCounter attemptCounter = attemptsCache.get(key.toLowerCase());
if (attemptCounter == null) { if (attemptCounter == null) {
return false; return false;
@ -61,7 +72,9 @@ public class LoginAttemptService {
} }
public int getRemainingAttempts(String key) { public int getRemainingAttempts(String key) {
if (key == null || key.trim().isEmpty()) return MAX_ATTEMPT; if (!isBlockedEnabled || key == null || key.trim().isEmpty()) {
return Integer.MAX_VALUE; // Arbitrarily high number if tracking is disabled
}
AttemptCounter attemptCounter = attemptsCache.get(key.toLowerCase()); AttemptCounter attemptCounter = attemptsCache.get(key.toLowerCase());
if (attemptCounter == null) { if (attemptCounter == null) {

View file

@ -14,7 +14,7 @@
security: security:
enableLogin: false # set to 'true' to enable login enableLogin: false # set to 'true' to enable login
csrfDisabled: true # Set to 'true' to disable CSRF protection (not recommended for production) csrfDisabled: true # Set to 'true' to disable CSRF protection (not recommended for production)
loginAttemptCount: 5 # lock user account after 5 tries loginAttemptCount: 5 # lock user account after 5 tries; when using e.g. Fail2Ban you can deactivate the function with -1
loginResetTimeMinutes: 120 # lock account for 2 hours after x attempts loginResetTimeMinutes: 120 # lock account for 2 hours after x attempts
loginMethod: all # 'all' (Login Username/Password and OAuth2[must be enabled and configured]), 'normal'(only Login with Username/Password) or 'oauth2'(only Login with OAuth2) loginMethod: all # 'all' (Login Username/Password and OAuth2[must be enabled and configured]), 'normal'(only Login with Username/Password) or 'oauth2'(only Login with OAuth2)
initialLogin: initialLogin: