From 6b13284a52af0ae38168af20c4967757ed281371 Mon Sep 17 00:00:00 2001 From: binsky Date: Thu, 17 Feb 2022 17:41:00 +0100 Subject: [PATCH 01/11] add PasswordGenerator class --- src/main/java/PasswordGenerator.java | 5 +++++ src/test/java/PasswordGeneratorTest.java | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/main/java/PasswordGenerator.java create mode 100644 src/test/java/PasswordGeneratorTest.java diff --git a/src/main/java/PasswordGenerator.java b/src/main/java/PasswordGenerator.java new file mode 100644 index 0000000..b36bbbb --- /dev/null +++ b/src/main/java/PasswordGenerator.java @@ -0,0 +1,5 @@ +public class PasswordGenerator { + public String generateRandomPassword() { + return ""; + } +} diff --git a/src/test/java/PasswordGeneratorTest.java b/src/test/java/PasswordGeneratorTest.java new file mode 100644 index 0000000..8f3d4b2 --- /dev/null +++ b/src/test/java/PasswordGeneratorTest.java @@ -0,0 +1,19 @@ +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class PasswordGeneratorTest { + + static PasswordGenerator passwordGenerator; + + @BeforeAll + static void init() { + passwordGenerator = new PasswordGenerator(); + } + + @Test + void generateRandomPassword() { + assertSame("", passwordGenerator.generateRandomPassword()); + } +} \ No newline at end of file From 963c58967d97a4c8e65e733c5f046000f2972744 Mon Sep 17 00:00:00 2001 From: binsky Date: Thu, 17 Feb 2022 17:55:17 +0100 Subject: [PATCH 02/11] implement generating lowercase passwords with a customizable length --- src/main/java/PasswordGenerator.java | 23 ++++++++++++++++++++++- src/test/java/PasswordGeneratorTest.java | 15 +++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/main/java/PasswordGenerator.java b/src/main/java/PasswordGenerator.java index b36bbbb..1a092a8 100644 --- a/src/main/java/PasswordGenerator.java +++ b/src/main/java/PasswordGenerator.java @@ -1,5 +1,26 @@ +import java.security.SecureRandom; + public class PasswordGenerator { + + final String lowercaseCharacters = "abcdefghjkmnpqrstuvwxyz"; + + int length = 12; + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + public String generateRandomPassword() { - return ""; + StringBuilder generatedPassword = new StringBuilder(); + SecureRandom rand = new SecureRandom(); + + for (int generatorPosition = 0; generatorPosition < getLength(); generatorPosition++) { + generatedPassword.append(lowercaseCharacters.charAt(rand.nextInt(lowercaseCharacters.length()))); + } + return generatedPassword.toString(); } } diff --git a/src/test/java/PasswordGeneratorTest.java b/src/test/java/PasswordGeneratorTest.java index 8f3d4b2..8e35b3f 100644 --- a/src/test/java/PasswordGeneratorTest.java +++ b/src/test/java/PasswordGeneratorTest.java @@ -1,6 +1,8 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import java.util.regex.Pattern; + import static org.junit.jupiter.api.Assertions.*; class PasswordGeneratorTest { @@ -14,6 +16,15 @@ class PasswordGeneratorTest { @Test void generateRandomPassword() { - assertSame("", passwordGenerator.generateRandomPassword()); + assertNotSame("", passwordGenerator.generateRandomPassword()); + assertEquals(passwordGenerator.generateRandomPassword().length(), passwordGenerator.getLength()); + + // test length requirement + passwordGenerator.setLength(33); + assertEquals(passwordGenerator.getLength(), 33); + assertEquals(passwordGenerator.generateRandomPassword().length(), passwordGenerator.getLength()); + + // test lowercase requirement + assertTrue(Pattern.compile("^(?=.*[a-z]).+$").matcher(passwordGenerator.generateRandomPassword()).matches()); } -} \ No newline at end of file +} From bb0e14c26f6841eab504611ac1e0a6e4024c5daf Mon Sep 17 00:00:00 2001 From: binsky Date: Thu, 17 Feb 2022 18:09:58 +0100 Subject: [PATCH 03/11] refactor PasswordGeneratorTest --- src/test/java/PasswordGeneratorTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/test/java/PasswordGeneratorTest.java b/src/test/java/PasswordGeneratorTest.java index 8e35b3f..8c14fe6 100644 --- a/src/test/java/PasswordGeneratorTest.java +++ b/src/test/java/PasswordGeneratorTest.java @@ -15,16 +15,17 @@ class PasswordGeneratorTest { } @Test - void generateRandomPassword() { + void testGeneratedPasswordLength() { assertNotSame("", passwordGenerator.generateRandomPassword()); assertEquals(passwordGenerator.generateRandomPassword().length(), passwordGenerator.getLength()); - // test length requirement passwordGenerator.setLength(33); assertEquals(passwordGenerator.getLength(), 33); assertEquals(passwordGenerator.generateRandomPassword().length(), passwordGenerator.getLength()); + } - // test lowercase requirement + @Test + void testPasswordLowercaseRequirement() { assertTrue(Pattern.compile("^(?=.*[a-z]).+$").matcher(passwordGenerator.generateRandomPassword()).matches()); } } From 7e9f3d179f83b50f24d5bbc520fb7008376b5dbf Mon Sep 17 00:00:00 2001 From: binsky Date: Thu, 17 Feb 2022 18:11:58 +0100 Subject: [PATCH 04/11] implement generating passwords with uppercase letters --- src/main/java/PasswordGenerator.java | 7 ++++++- src/test/java/PasswordGeneratorTest.java | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/PasswordGenerator.java b/src/main/java/PasswordGenerator.java index 1a092a8..bab7e6f 100644 --- a/src/main/java/PasswordGenerator.java +++ b/src/main/java/PasswordGenerator.java @@ -3,6 +3,7 @@ import java.security.SecureRandom; public class PasswordGenerator { final String lowercaseCharacters = "abcdefghjkmnpqrstuvwxyz"; + final String uppercaseCharacters = "ABCDEFGHJKMNPQRSTUVWXYZ"; int length = 12; @@ -17,9 +18,13 @@ public class PasswordGenerator { public String generateRandomPassword() { StringBuilder generatedPassword = new StringBuilder(); SecureRandom rand = new SecureRandom(); + String characterPool = ""; + + characterPool += lowercaseCharacters; + characterPool += uppercaseCharacters; for (int generatorPosition = 0; generatorPosition < getLength(); generatorPosition++) { - generatedPassword.append(lowercaseCharacters.charAt(rand.nextInt(lowercaseCharacters.length()))); + generatedPassword.append(characterPool.charAt(rand.nextInt(characterPool.length()))); } return generatedPassword.toString(); } diff --git a/src/test/java/PasswordGeneratorTest.java b/src/test/java/PasswordGeneratorTest.java index 8c14fe6..57192f3 100644 --- a/src/test/java/PasswordGeneratorTest.java +++ b/src/test/java/PasswordGeneratorTest.java @@ -28,4 +28,9 @@ class PasswordGeneratorTest { void testPasswordLowercaseRequirement() { assertTrue(Pattern.compile("^(?=.*[a-z]).+$").matcher(passwordGenerator.generateRandomPassword()).matches()); } + + @Test + void testPasswordUppercaseRequirement() { + assertTrue(Pattern.compile("^(?=.*[A-Z]).+$").matcher(passwordGenerator.generateRandomPassword()).matches()); + } } From 5eb63ea2b3c5e48b9a64e218f3215b676d1c1a0d Mon Sep 17 00:00:00 2001 From: binsky Date: Thu, 17 Feb 2022 18:13:47 +0100 Subject: [PATCH 05/11] implement generating passwords with digits --- src/main/java/PasswordGenerator.java | 2 ++ src/test/java/PasswordGeneratorTest.java | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/main/java/PasswordGenerator.java b/src/main/java/PasswordGenerator.java index bab7e6f..0744c31 100644 --- a/src/main/java/PasswordGenerator.java +++ b/src/main/java/PasswordGenerator.java @@ -4,6 +4,7 @@ public class PasswordGenerator { final String lowercaseCharacters = "abcdefghjkmnpqrstuvwxyz"; final String uppercaseCharacters = "ABCDEFGHJKMNPQRSTUVWXYZ"; + final String digits = "0123456789"; int length = 12; @@ -22,6 +23,7 @@ public class PasswordGenerator { characterPool += lowercaseCharacters; characterPool += uppercaseCharacters; + characterPool += digits; for (int generatorPosition = 0; generatorPosition < getLength(); generatorPosition++) { generatedPassword.append(characterPool.charAt(rand.nextInt(characterPool.length()))); diff --git a/src/test/java/PasswordGeneratorTest.java b/src/test/java/PasswordGeneratorTest.java index 57192f3..7f9874c 100644 --- a/src/test/java/PasswordGeneratorTest.java +++ b/src/test/java/PasswordGeneratorTest.java @@ -33,4 +33,9 @@ class PasswordGeneratorTest { void testPasswordUppercaseRequirement() { assertTrue(Pattern.compile("^(?=.*[A-Z]).+$").matcher(passwordGenerator.generateRandomPassword()).matches()); } + + @Test + void testPasswordDigitsRequirement() { + assertTrue(Pattern.compile("^(?=.*\\d).+$").matcher(passwordGenerator.generateRandomPassword()).matches()); + } } From 408d189ac4f30766a61c6354d35236b4c5e139a9 Mon Sep 17 00:00:00 2001 From: binsky Date: Thu, 17 Feb 2022 18:21:42 +0100 Subject: [PATCH 06/11] make password generator requirements configurable --- src/main/java/PasswordGenerator.java | 56 +++++++++++++++++++----- src/test/java/PasswordGeneratorTest.java | 9 ++++ 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/main/java/PasswordGenerator.java b/src/main/java/PasswordGenerator.java index 0744c31..fd122a5 100644 --- a/src/main/java/PasswordGenerator.java +++ b/src/main/java/PasswordGenerator.java @@ -6,28 +6,62 @@ public class PasswordGenerator { final String uppercaseCharacters = "ABCDEFGHJKMNPQRSTUVWXYZ"; final String digits = "0123456789"; - int length = 12; + private int length = 12; + private boolean useUppercase = true; + private boolean useLowercase = true; + private boolean useDigits = true; - public int getLength() { - return length; - } - - public void setLength(int length) { - this.length = length; - } public String generateRandomPassword() { StringBuilder generatedPassword = new StringBuilder(); SecureRandom rand = new SecureRandom(); String characterPool = ""; - characterPool += lowercaseCharacters; - characterPool += uppercaseCharacters; - characterPool += digits; + if (isUseLowercase()) { + characterPool += lowercaseCharacters; + } + if (isUseUppercase()) { + characterPool += uppercaseCharacters; + } + if (isUseDigits()) { + characterPool += digits; + } for (int generatorPosition = 0; generatorPosition < getLength(); generatorPosition++) { generatedPassword.append(characterPool.charAt(rand.nextInt(characterPool.length()))); } return generatedPassword.toString(); } + + public boolean isUseUppercase() { + return useUppercase; + } + + public void setUseUppercase(boolean useUppercase) { + this.useUppercase = useUppercase; + } + + public boolean isUseLowercase() { + return useLowercase; + } + + public void setUseLowercase(boolean useLowercase) { + this.useLowercase = useLowercase; + } + + public boolean isUseDigits() { + return useDigits; + } + + public void setUseDigits(boolean useDigits) { + this.useDigits = useDigits; + } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } } diff --git a/src/test/java/PasswordGeneratorTest.java b/src/test/java/PasswordGeneratorTest.java index 7f9874c..6ff1dc1 100644 --- a/src/test/java/PasswordGeneratorTest.java +++ b/src/test/java/PasswordGeneratorTest.java @@ -26,16 +26,25 @@ class PasswordGeneratorTest { @Test void testPasswordLowercaseRequirement() { + passwordGenerator.setUseLowercase(false); + assertFalse(Pattern.compile("^(?=.*[a-z]).+$").matcher(passwordGenerator.generateRandomPassword()).matches()); + passwordGenerator.setUseLowercase(true); assertTrue(Pattern.compile("^(?=.*[a-z]).+$").matcher(passwordGenerator.generateRandomPassword()).matches()); } @Test void testPasswordUppercaseRequirement() { + passwordGenerator.setUseUppercase(false); + assertFalse(Pattern.compile("^(?=.*[A-Z]).+$").matcher(passwordGenerator.generateRandomPassword()).matches()); + passwordGenerator.setUseUppercase(true); assertTrue(Pattern.compile("^(?=.*[A-Z]).+$").matcher(passwordGenerator.generateRandomPassword()).matches()); } @Test void testPasswordDigitsRequirement() { + passwordGenerator.setUseDigits(false); + assertFalse(Pattern.compile("^(?=.*\\d).+$").matcher(passwordGenerator.generateRandomPassword()).matches()); + passwordGenerator.setUseDigits(true); assertTrue(Pattern.compile("^(?=.*\\d).+$").matcher(passwordGenerator.generateRandomPassword()).matches()); } } From 4c458fb7103da2e5efe7601e2f20258d0500a855 Mon Sep 17 00:00:00 2001 From: binsky Date: Thu, 17 Feb 2022 18:25:37 +0100 Subject: [PATCH 07/11] implement generating passwords with special characters --- src/main/java/PasswordGenerator.java | 13 +++++++++++++ src/test/java/PasswordGeneratorTest.java | 8 ++++++++ 2 files changed, 21 insertions(+) diff --git a/src/main/java/PasswordGenerator.java b/src/main/java/PasswordGenerator.java index fd122a5..f57d346 100644 --- a/src/main/java/PasswordGenerator.java +++ b/src/main/java/PasswordGenerator.java @@ -5,11 +5,13 @@ public class PasswordGenerator { final String lowercaseCharacters = "abcdefghjkmnpqrstuvwxyz"; final String uppercaseCharacters = "ABCDEFGHJKMNPQRSTUVWXYZ"; final String digits = "0123456789"; + final String specialCharacters = ".!?=@#$()%^&/*_-+"; private int length = 12; private boolean useUppercase = true; private boolean useLowercase = true; private boolean useDigits = true; + private boolean useSpecialCharacters = true; public String generateRandomPassword() { @@ -26,6 +28,9 @@ public class PasswordGenerator { if (isUseDigits()) { characterPool += digits; } + if (isUseSpecialCharacters()) { + characterPool += specialCharacters; + } for (int generatorPosition = 0; generatorPosition < getLength(); generatorPosition++) { generatedPassword.append(characterPool.charAt(rand.nextInt(characterPool.length()))); @@ -57,6 +62,14 @@ public class PasswordGenerator { this.useDigits = useDigits; } + public boolean isUseSpecialCharacters() { + return useSpecialCharacters; + } + + public void setUseSpecialCharacters(boolean useSpecialCharacters) { + this.useSpecialCharacters = useSpecialCharacters; + } + public int getLength() { return length; } diff --git a/src/test/java/PasswordGeneratorTest.java b/src/test/java/PasswordGeneratorTest.java index 6ff1dc1..17baabd 100644 --- a/src/test/java/PasswordGeneratorTest.java +++ b/src/test/java/PasswordGeneratorTest.java @@ -47,4 +47,12 @@ class PasswordGeneratorTest { passwordGenerator.setUseDigits(true); assertTrue(Pattern.compile("^(?=.*\\d).+$").matcher(passwordGenerator.generateRandomPassword()).matches()); } + + @Test + void testPasswordSpecialCharactersRequirement() { + passwordGenerator.setUseSpecialCharacters(false); + assertFalse(Pattern.compile("^(?=.*[.!?=@#$()%^&/*_\\-+]).+$").matcher(passwordGenerator.generateRandomPassword()).matches()); + passwordGenerator.setUseSpecialCharacters(true); + assertTrue(Pattern.compile("^(?=.*[.!?=@#$()%^&/*_\\-+]).+$").matcher(passwordGenerator.generateRandomPassword()).matches()); + } } From fd4e570204286b91b54481af4004be625fe58317 Mon Sep 17 00:00:00 2001 From: binsky Date: Thu, 17 Feb 2022 18:38:20 +0100 Subject: [PATCH 08/11] implement requiring every configured character type in password generator --- src/main/java/PasswordGenerator.java | 27 +++++++++++++++++++++++- src/test/java/PasswordGeneratorTest.java | 7 ++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/main/java/PasswordGenerator.java b/src/main/java/PasswordGenerator.java index f57d346..c9c6784 100644 --- a/src/main/java/PasswordGenerator.java +++ b/src/main/java/PasswordGenerator.java @@ -12,6 +12,7 @@ public class PasswordGenerator { private boolean useLowercase = true; private boolean useDigits = true; private boolean useSpecialCharacters = true; + private boolean requireEveryConfiguredCharacterType = true; public String generateRandomPassword() { @@ -33,7 +34,23 @@ public class PasswordGenerator { } for (int generatorPosition = 0; generatorPosition < getLength(); generatorPosition++) { - generatedPassword.append(characterPool.charAt(rand.nextInt(characterPool.length()))); + String customCharacterPool = characterPool; + + if (isRequireEveryConfiguredCharacterType()) { + if (generatorPosition == 0 && isUseLowercase()) { + customCharacterPool += lowercaseCharacters; + } else if (generatorPosition == 1 && isUseUppercase()) { + customCharacterPool += uppercaseCharacters; + } else if (generatorPosition == 2 && isUseDigits()) { + customCharacterPool += digits; + } else if (generatorPosition == 3 && isUseSpecialCharacters()) { + customCharacterPool += specialCharacters; + } else { + customCharacterPool = characterPool; + } + } + + generatedPassword.append(customCharacterPool.charAt(rand.nextInt(customCharacterPool.length()))); } return generatedPassword.toString(); } @@ -70,6 +87,14 @@ public class PasswordGenerator { this.useSpecialCharacters = useSpecialCharacters; } + public boolean isRequireEveryConfiguredCharacterType() { + return requireEveryConfiguredCharacterType; + } + + public void setRequireEveryConfiguredCharacterType(boolean requireEveryConfiguredCharacterType) { + this.requireEveryConfiguredCharacterType = requireEveryConfiguredCharacterType; + } + public int getLength() { return length; } diff --git a/src/test/java/PasswordGeneratorTest.java b/src/test/java/PasswordGeneratorTest.java index 17baabd..91590db 100644 --- a/src/test/java/PasswordGeneratorTest.java +++ b/src/test/java/PasswordGeneratorTest.java @@ -55,4 +55,11 @@ class PasswordGeneratorTest { passwordGenerator.setUseSpecialCharacters(true); assertTrue(Pattern.compile("^(?=.*[.!?=@#$()%^&/*_\\-+]).+$").matcher(passwordGenerator.generateRandomPassword()).matches()); } + + @Test + void testPasswordForEveryRequiredCharacter() { + passwordGenerator.setRequireEveryConfiguredCharacterType(true); + PasswordValidator passwordValidator = new PasswordValidator(); + assertTrue(passwordValidator.validate(passwordGenerator.generateRandomPassword())); + } } From 00fc1ee00ea600f67318549fe3706673b1177fa7 Mon Sep 17 00:00:00 2001 From: binsky Date: Thu, 17 Feb 2022 18:47:15 +0100 Subject: [PATCH 09/11] implement method to shuffle password characters --- src/main/java/PasswordGenerator.java | 15 ++++++++++++++- src/test/java/PasswordGeneratorTest.java | 7 +++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/java/PasswordGenerator.java b/src/main/java/PasswordGenerator.java index c9c6784..178ef78 100644 --- a/src/main/java/PasswordGenerator.java +++ b/src/main/java/PasswordGenerator.java @@ -6,6 +6,7 @@ public class PasswordGenerator { final String uppercaseCharacters = "ABCDEFGHJKMNPQRSTUVWXYZ"; final String digits = "0123456789"; final String specialCharacters = ".!?=@#$()%^&/*_-+"; + final SecureRandom rand = new SecureRandom(); private int length = 12; private boolean useUppercase = true; @@ -17,7 +18,6 @@ public class PasswordGenerator { public String generateRandomPassword() { StringBuilder generatedPassword = new StringBuilder(); - SecureRandom rand = new SecureRandom(); String characterPool = ""; if (isUseLowercase()) { @@ -55,6 +55,19 @@ public class PasswordGenerator { return generatedPassword.toString(); } + public String shufflePassword(String password) { + StringBuilder shuffledPassword = new StringBuilder(); + StringBuilder passwordCopy = new StringBuilder(password); + + while (passwordCopy.length() != 0) { + int index = rand.nextInt(passwordCopy.length()); + char c = passwordCopy.charAt(index); + shuffledPassword.append(c); + passwordCopy.deleteCharAt(index); + } + return shuffledPassword.toString(); + } + public boolean isUseUppercase() { return useUppercase; } diff --git a/src/test/java/PasswordGeneratorTest.java b/src/test/java/PasswordGeneratorTest.java index 91590db..1e5f427 100644 --- a/src/test/java/PasswordGeneratorTest.java +++ b/src/test/java/PasswordGeneratorTest.java @@ -62,4 +62,11 @@ class PasswordGeneratorTest { PasswordValidator passwordValidator = new PasswordValidator(); assertTrue(passwordValidator.validate(passwordGenerator.generateRandomPassword())); } + + @Test + void testShufflePassword() { + String testInput = "ABcdefgh123"; + assertNotEquals(passwordGenerator.shufflePassword(testInput), testInput); + assertEquals(passwordGenerator.shufflePassword(testInput).length(), testInput.length()); + } } From cbd3124ac290e5e7a641a0ad63cc5463a13d0af6 Mon Sep 17 00:00:00 2001 From: binsky Date: Thu, 17 Feb 2022 18:53:20 +0100 Subject: [PATCH 10/11] fix password generator requirement implementation for every configured character --- src/main/java/PasswordGenerator.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/PasswordGenerator.java b/src/main/java/PasswordGenerator.java index 178ef78..5afed60 100644 --- a/src/main/java/PasswordGenerator.java +++ b/src/main/java/PasswordGenerator.java @@ -38,13 +38,13 @@ public class PasswordGenerator { if (isRequireEveryConfiguredCharacterType()) { if (generatorPosition == 0 && isUseLowercase()) { - customCharacterPool += lowercaseCharacters; + customCharacterPool = lowercaseCharacters; } else if (generatorPosition == 1 && isUseUppercase()) { - customCharacterPool += uppercaseCharacters; + customCharacterPool = uppercaseCharacters; } else if (generatorPosition == 2 && isUseDigits()) { - customCharacterPool += digits; + customCharacterPool = digits; } else if (generatorPosition == 3 && isUseSpecialCharacters()) { - customCharacterPool += specialCharacters; + customCharacterPool = specialCharacters; } else { customCharacterPool = characterPool; } From 312a9046ac859bf82a99be3e6374e99132892268 Mon Sep 17 00:00:00 2001 From: binsky Date: Thu, 17 Feb 2022 18:54:03 +0100 Subject: [PATCH 11/11] shuffle every generated password by default --- src/main/java/PasswordGenerator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/PasswordGenerator.java b/src/main/java/PasswordGenerator.java index 5afed60..2e23683 100644 --- a/src/main/java/PasswordGenerator.java +++ b/src/main/java/PasswordGenerator.java @@ -52,7 +52,8 @@ public class PasswordGenerator { generatedPassword.append(customCharacterPool.charAt(rand.nextInt(customCharacterPool.length()))); } - return generatedPassword.toString(); + + return shufflePassword(generatedPassword.toString()); } public String shufflePassword(String password) {