From ea1430ffc3b5b9982a5e647813826437a0654776 Mon Sep 17 00:00:00 2001 From: Samat Gatin <55357468+Samatgator@users.noreply.github.com> Date: Sun, 9 Feb 2025 14:56:39 +0000 Subject: [PATCH 1/3] Add PasswordLockoutRequirement --- Main.java | 6 +++ PasswordLockoutRequirement.java | 85 +++++++++++++++++++++++++++++++++ PasswordMinimumLength.java | 2 +- PasswordPolicy.java | 6 +-- 4 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 PasswordLockoutRequirement.java diff --git a/Main.java b/Main.java index 41c20e2..689e3b1 100644 --- a/Main.java +++ b/Main.java @@ -10,6 +10,7 @@ public static void main(String[] args) { while (true) { System.out.println("\nChoose an action:"); + System.out.println("0. Simulate correct login attempt"); System.out.println("1. Simulate failed login attempt"); System.out.println("2. Reset failed attempts"); System.out.println("3. Check lockout status"); @@ -18,6 +19,11 @@ public static void main(String[] args) { int choice = scanner.nextInt(); switch (choice) { + case 0: + lockoutRequirement.recordCorrectAttempt(); + System.out.println("Correct attempt recorded."); + break; + case 1: lockoutRequirement.recordFailedAttempt(); System.out.println("Failed attempt recorded."); diff --git a/PasswordLockoutRequirement.java b/PasswordLockoutRequirement.java new file mode 100644 index 0000000..2a4c3dd --- /dev/null +++ b/PasswordLockoutRequirement.java @@ -0,0 +1,85 @@ +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 (15 minutes) + 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() { + this.resetFailedAttempts(); + 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; From d055762befc6ac21199ac8a86196f6b3e3d71bd0 Mon Sep 17 00:00:00 2001 From: Samat Gatin <55357468+Samatgator@users.noreply.github.com> Date: Mon, 10 Feb 2025 07:07:19 +0000 Subject: [PATCH 2/3] Update PasswordLockoutRequirement --- Main.java | 10 +++++----- PasswordLockoutRequirement.java | 11 +++++------ 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Main.java b/Main.java index 689e3b1..b5c920a 100644 --- a/Main.java +++ b/Main.java @@ -10,7 +10,7 @@ public static void main(String[] args) { while (true) { System.out.println("\nChoose an action:"); - System.out.println("0. Simulate correct login attempt"); + // System.out.println("0. Simulate correct login attempt"); System.out.println("1. Simulate failed login attempt"); System.out.println("2. Reset failed attempts"); System.out.println("3. Check lockout status"); @@ -19,10 +19,10 @@ public static void main(String[] args) { int choice = scanner.nextInt(); switch (choice) { - case 0: - lockoutRequirement.recordCorrectAttempt(); - System.out.println("Correct attempt recorded."); - break; + // case 0: + // lockoutRequirement.recordCorrectAttempt(); + // System.out.println("Correct attempt recorded."); + // break; case 1: lockoutRequirement.recordFailedAttempt(); diff --git a/PasswordLockoutRequirement.java b/PasswordLockoutRequirement.java index 2a4c3dd..4f42cf0 100644 --- a/PasswordLockoutRequirement.java +++ b/PasswordLockoutRequirement.java @@ -4,7 +4,7 @@ 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 (15 minutes) + 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; @@ -31,10 +31,10 @@ public Checkable.CheckStatus check() { : Checkable.CheckStatus.PASS; } - public void recordCorrectAttempt() { - if (this.check() != Checkable.CheckStatus.FAIL) - userStatusMap.get(username).resetFailedAttempts(); - } + // public void recordCorrectAttempt() { + // if (this.check() != Checkable.CheckStatus.FAIL) + // userStatusMap.get(username).resetFailedAttempts(); + // } public void recordFailedAttempt() { userStatusMap.get(username).incrementFailedAttempts(); @@ -78,7 +78,6 @@ public long getLockoutStartTime() { } public void resetLockout() { - this.resetFailedAttempts(); lockoutStartTime = 0; } } From 2bab6a34c3e6f3a4db7618d66f37945a9d719c6c Mon Sep 17 00:00:00 2001 From: Samat Gatin <55357468+Samatgator@users.noreply.github.com> Date: Mon, 10 Feb 2025 07:17:56 +0000 Subject: [PATCH 3/3] Update Main.java --- Main.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Main.java b/Main.java index b5c920a..ec07735 100644 --- a/Main.java +++ b/Main.java @@ -10,7 +10,6 @@ public static void main(String[] args) { while (true) { System.out.println("\nChoose an action:"); - // System.out.println("0. Simulate correct login attempt"); System.out.println("1. Simulate failed login attempt"); System.out.println("2. Reset failed attempts"); System.out.println("3. Check lockout status"); @@ -19,11 +18,6 @@ public static void main(String[] args) { int choice = scanner.nextInt(); switch (choice) { - // case 0: - // lockoutRequirement.recordCorrectAttempt(); - // System.out.println("Correct attempt recorded."); - // break; - case 1: lockoutRequirement.recordFailedAttempt(); System.out.println("Failed attempt recorded."); @@ -37,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: