diff --git a/Main.java b/Main.java index 41c20e2..ec07735 100644 --- a/Main.java +++ b/Main.java @@ -31,6 +31,8 @@ public static void main(String[] args) { case 3: Checkable.CheckStatus status = lockoutRequirement.check(); System.out.println("Password lockout requirement check: " + status); + if (status == Checkable.CheckStatus.FAIL) + System.out.println("Account is locked."); break; case 4: diff --git a/PasswordLockoutRequirement.java b/PasswordLockoutRequirement.java new file mode 100644 index 0000000..4f42cf0 --- /dev/null +++ b/PasswordLockoutRequirement.java @@ -0,0 +1,84 @@ +import java.util.HashMap; +import java.util.Map; + +public class PasswordLockoutRequirement extends Requirement { + + private static final int MAX_FAILED_ATTEMPTS = 5; // Maximum allowed failed attempts + private static final long LOCKOUT_DURATION_MS = 1 * 10 * 1000; // Lockout duration in milliseconds (10 seconds) + private final Map userStatusMap = new HashMap<>(); + private final String username; + + public PasswordLockoutRequirement(String username) { + this.username = username; + userStatusMap.putIfAbsent(username, new UserLoginStatus()); + } + + + @Override + public Checkable.CheckStatus check() { + UserLoginStatus status = userStatusMap.get(username); + + if (status.isLocked()) { + if (System.currentTimeMillis() - status.getLockoutStartTime() > LOCKOUT_DURATION_MS) { + status.resetLockout(); // Unlock after the lockout period + } else { + return Checkable.CheckStatus.FAIL; + } + } + + return status.getFailedAttempts() >= MAX_FAILED_ATTEMPTS + ? Checkable.CheckStatus.FAIL + : Checkable.CheckStatus.PASS; + } + + // public void recordCorrectAttempt() { + // if (this.check() != Checkable.CheckStatus.FAIL) + // userStatusMap.get(username).resetFailedAttempts(); + // } + + public void recordFailedAttempt() { + userStatusMap.get(username).incrementFailedAttempts(); + } + + public void resetFailedAttempts() { + userStatusMap.get(username).resetFailedAttempts(); + } + + @Override + public String toString() { + return "The system must lock a user’s account after " + MAX_FAILED_ATTEMPTS + " consecutive failed login attempts."; + } + + private static class UserLoginStatus { + private int failedAttempts = 0; + private long lockoutStartTime = 0; + + public int getFailedAttempts() { + return failedAttempts; + } + + public void incrementFailedAttempts() { + failedAttempts++; + if (failedAttempts >= MAX_FAILED_ATTEMPTS) { + lockoutStartTime = System.currentTimeMillis(); + } + } + + public void resetFailedAttempts() { + failedAttempts = 0; + lockoutStartTime = 0; + } + + public boolean isLocked() { + return lockoutStartTime > 0; + } + + public long getLockoutStartTime() { + return lockoutStartTime; + } + + public void resetLockout() { + lockoutStartTime = 0; + } + } +} diff --git a/PasswordMinimumLength.java b/PasswordMinimumLength.java index e3262ca..e2847b5 100644 --- a/PasswordMinimumLength.java +++ b/PasswordMinimumLength.java @@ -1,5 +1,5 @@ -import rqcode.concepts.Requirement; +// import rqcode.concepts.Requirement; public class PasswordMinimumLength extends Requirement { private static final int MIN_LENGTH = 8; diff --git a/PasswordPolicy.java b/PasswordPolicy.java index 251ba3b..2b99f10 100644 --- a/PasswordPolicy.java +++ b/PasswordPolicy.java @@ -1,6 +1,6 @@ -package rqcode.tutorial.tutorial_new; -import rqcode.concepts.CombinedRequirements; -import rqcode.concepts.Requirement; +// package rqcode.tutorial.tutorial_new; +// import rqcode.concepts.CombinedRequirements; +// import rqcode.concepts.Requirement; import java.util.Arrays; import java.util.List;