From 897c2a904bd906f7ef2f3b51fac9587c277b805c Mon Sep 17 00:00:00 2001 From: Florian Kostenzer Date: Tue, 6 Jun 2017 04:10:23 +0200 Subject: [PATCH] Added: Random Passwords --- .../java/com/kinancity/core/CliOptions.java | 1 + .../java/com/kinancity/core/KinanCityCli.java | 32 ++++++-- .../account/SequenceAccountGenerator.java | 7 -- .../password/RandomPasswordGenerator.java | 76 +++++++++++++++++++ .../impl/SequenceAccountGeneratorTest.java | 20 ++++- 5 files changed, 121 insertions(+), 15 deletions(-) create mode 100644 KinanCity-core/src/main/java/com/kinancity/core/generator/password/RandomPasswordGenerator.java diff --git a/KinanCity-core/src/main/java/com/kinancity/core/CliOptions.java b/KinanCity-core/src/main/java/com/kinancity/core/CliOptions.java index fec485f..eee5c6d 100644 --- a/KinanCity-core/src/main/java/com/kinancity/core/CliOptions.java +++ b/KinanCity-core/src/main/java/com/kinancity/core/CliOptions.java @@ -13,6 +13,7 @@ public enum CliOptions { EMAIL("m", "mail", true, "account email address"), SINGLE_USERNAME("u", "username", true, "account username/login"), PASSWORD("p", "password", true, "account password"), + PASSWORD_LENGTH("pl", "passwordLength", true, "random account password length"), SEQ_ACCOUNTS_COUNT("c", "count", true, "number of accounts to generate"), SEQ_ACCOUNTS_START("s", "startnum", true, "number of the first one"), diff --git a/KinanCity-core/src/main/java/com/kinancity/core/KinanCityCli.java b/KinanCity-core/src/main/java/com/kinancity/core/KinanCityCli.java index 8ef9ff4..0da680b 100644 --- a/KinanCity-core/src/main/java/com/kinancity/core/KinanCityCli.java +++ b/KinanCity-core/src/main/java/com/kinancity/core/KinanCityCli.java @@ -10,9 +10,12 @@ import org.slf4j.LoggerFactory; import com.kinancity.api.model.AccountData; +import com.kinancity.core.generator.PasswordGenerator; import com.kinancity.core.generator.account.CsvReaderAccountGenerator; import com.kinancity.core.generator.account.SequenceAccountGenerator; import com.kinancity.core.generator.account.SingleAccountGenerator; +import com.kinancity.core.generator.password.RandomPasswordGenerator; +import com.kinancity.core.generator.password.SinglePasswordGenerator; import com.kinancity.core.proxy.bottleneck.ProxyNoBottleneck; import com.kinancity.core.proxy.policies.UnlimitedUsePolicy; @@ -106,22 +109,36 @@ private static Configuration updateConfiguration(Configuration config, Options o // 3 types of generation : unique, csv and sequence - if (cmd.hasOption(CliOptions.SEQ_ACCOUNTS_FORMAT.shortName) && cmd.hasOption(CliOptions.SEQ_ACCOUNTS_COUNT.shortName) && cmd.hasOption(CliOptions.EMAIL.shortName) && cmd.hasOption(CliOptions.PASSWORD.shortName)) { + if (cmd.hasOption(CliOptions.SEQ_ACCOUNTS_FORMAT.shortName) && cmd.hasOption(CliOptions.SEQ_ACCOUNTS_COUNT.shortName) && cmd.hasOption(CliOptions.EMAIL.shortName)) { LOGGER.info("Use a Sequence Account Generator"); SequenceAccountGenerator sequenceGenerator = new SequenceAccountGenerator(); sequenceGenerator.setBaseEmail(cmd.getOptionValue(CliOptions.EMAIL.shortName)); - sequenceGenerator.setStaticPassword(cmd.getOptionValue(CliOptions.PASSWORD.shortName)); sequenceGenerator.setUsernamePattern(cmd.getOptionValue(CliOptions.SEQ_ACCOUNTS_FORMAT.shortName)); sequenceGenerator.setNbAccounts(Integer.parseInt(cmd.getOptionValue(CliOptions.SEQ_ACCOUNTS_COUNT.shortName))); sequenceGenerator.setStartFrom(Integer.parseInt(cmd.getOptionValue(CliOptions.SEQ_ACCOUNTS_START.shortName, "0"))); + if (cmd.hasOption(CliOptions.PASSWORD.shortName)) { + sequenceGenerator.setPasswordGenerator(new SinglePasswordGenerator(cmd.getOptionValue(CliOptions.PASSWORD.shortName))); + } + else { + Integer length = Integer.valueOf(cmd.getOptionValue(CliOptions.PASSWORD_LENGTH.shortName, "-1")); + sequenceGenerator.setPasswordGenerator(new RandomPasswordGenerator(length)); + } config.setAccountGenerator(sequenceGenerator); - - } else if (cmd.hasOption(CliOptions.EMAIL.shortName) && cmd.hasOption(CliOptions.SINGLE_USERNAME.shortName) && cmd.hasOption(CliOptions.PASSWORD.shortName)) { + } + else if (cmd.hasOption(CliOptions.EMAIL.shortName) && cmd.hasOption(CliOptions.SINGLE_USERNAME.shortName)) { LOGGER.info("Create a single account"); AccountData account = new AccountData(); account.setEmail(cmd.getOptionValue(CliOptions.EMAIL.shortName)); account.setUsername(cmd.getOptionValue(CliOptions.SINGLE_USERNAME.shortName)); - account.setPassword(cmd.getOptionValue(CliOptions.PASSWORD.shortName)); + PasswordGenerator pwGen; + if (cmd.hasOption(CliOptions.PASSWORD.shortName)) { + pwGen = new SinglePasswordGenerator(cmd.getOptionValue(CliOptions.PASSWORD.shortName)); + } + else { + Integer length = Integer.valueOf(cmd.getOptionValue(CliOptions.PASSWORD_LENGTH.shortName, "-1")); + pwGen = new RandomPasswordGenerator(length); + } + account.setPassword(pwGen.generatePassword()); config.setAccountGenerator(new SingleAccountGenerator(account)); // No need to use multiple thread for 1 account only @@ -134,9 +151,9 @@ private static Configuration updateConfiguration(Configuration config, Options o HelpFormatter formatter = new HelpFormatter(); String cmdLineSyntax = " one of \n" - + " -m -u -p \n" + + " -m -u (-p -pl ) \n" + " -a \n" - + " -m -c <#ofAccounts> -f -p (-s )\n" + + " -m -c <#ofAccounts> -f (-p -pl -s )\n" + " and optional : -ck \n\n"; formatter.setWidth(180); formatter.printHelp(cmdLineSyntax, options); @@ -157,6 +174,7 @@ private static Options setupCliOptions() { options.addOption(CliOptions.EMAIL.asOption()); options.addOption(CliOptions.SINGLE_USERNAME.asOption()); options.addOption(CliOptions.PASSWORD.asOption()); + options.addOption(CliOptions.PASSWORD_LENGTH.asOption()); // Create Multiple accounts options.addOption(CliOptions.CSV_ACCOUNTS.asOption()); diff --git a/KinanCity-core/src/main/java/com/kinancity/core/generator/account/SequenceAccountGenerator.java b/KinanCity-core/src/main/java/com/kinancity/core/generator/account/SequenceAccountGenerator.java index 756638c..4c9c45b 100644 --- a/KinanCity-core/src/main/java/com/kinancity/core/generator/account/SequenceAccountGenerator.java +++ b/KinanCity-core/src/main/java/com/kinancity/core/generator/account/SequenceAccountGenerator.java @@ -6,7 +6,6 @@ import com.kinancity.core.generator.PasswordGenerator; import com.kinancity.core.generator.UsernameGenerator; import com.kinancity.core.generator.email.PlusTrickEmailGenerator; -import com.kinancity.core.generator.password.SinglePasswordGenerator; import com.kinancity.core.generator.username.SequenceUsernameGenerator; import lombok.Setter; @@ -23,9 +22,6 @@ public class SequenceAccountGenerator implements AccountGenerator { // Format with prefix and suffix. use * instead of the number sequence private String usernamePattern; - @Setter - private String staticPassword; - @Setter private String baseEmail; @@ -59,9 +55,6 @@ public void init() { throw new IllegalArgumentException("Sequence would overflow format, use more *"); } usernameGenerator = seqUsernameGenerator; - - passwordGenerator = new SinglePasswordGenerator(staticPassword); - initDone = true; } diff --git a/KinanCity-core/src/main/java/com/kinancity/core/generator/password/RandomPasswordGenerator.java b/KinanCity-core/src/main/java/com/kinancity/core/generator/password/RandomPasswordGenerator.java new file mode 100644 index 0000000..6955c4a --- /dev/null +++ b/KinanCity-core/src/main/java/com/kinancity/core/generator/password/RandomPasswordGenerator.java @@ -0,0 +1,76 @@ +package com.kinancity.core.generator.password; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.kinancity.core.KinanCityCli; +import com.kinancity.core.generator.PasswordGenerator; + +/** + * Random Password generator + * @author 0815Flo0815 + * + */ +public class RandomPasswordGenerator implements PasswordGenerator { + + private static final char[][] CHAR_POOL = { + {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}, + {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'}, + {'1','2','3','4','5','6','7','8','9','0'}, + {'#','?','!','@','$','%','%','^','&','>','<','+','`','*','(',')','-',']'} + }; + private static final int MIN_LENGTH = 8; + private static final int MAX_LENGTH = 50; + + private static Logger LOGGER = LoggerFactory.getLogger(KinanCityCli.class); + + private int length; + + public RandomPasswordGenerator(Integer length) { + super(); + if (length == null) { + LOGGER.warn("Password length must be a number! Using a random length!"); + this.length = -1; + } + else if (length < 0) { + this.length = -1; + } + else if (length < MIN_LENGTH) { + LOGGER.warn("The minimum password length is " + MIN_LENGTH + "! Using " + MIN_LENGTH + "!"); + this.length = MIN_LENGTH; + } + else if (length > MAX_LENGTH) { + LOGGER.warn("The maximum password length is " + MAX_LENGTH + "! Using " + MAX_LENGTH + "!"); + this.length = MAX_LENGTH; + } + else { + this.length = length; + } + } + + @Override + public String generatePassword() { + int length; + if (this.length == -1) { + length = ThreadLocalRandom.current().nextInt(MIN_LENGTH, MAX_LENGTH + 1); + } + else { + length = this.length; + } + + ArrayList passwordPool = new ArrayList(); + for (int i = 0; i < length; i++) { + char[] currentPool = CHAR_POOL[i % CHAR_POOL.length]; + int randomIndexPool = ThreadLocalRandom.current().nextInt(currentPool.length); + int randomIndexPosition = ThreadLocalRandom.current().nextInt(passwordPool.size() + 1); + passwordPool.add(randomIndexPosition, currentPool[randomIndexPool]); + } + Collections.shuffle(passwordPool); + return String.valueOf(passwordPool.stream().map(e->e.toString()).collect(Collectors.joining())); + } +} diff --git a/KinanCity-core/src/test/java/com/kinancity/core/generator/impl/SequenceAccountGeneratorTest.java b/KinanCity-core/src/test/java/com/kinancity/core/generator/impl/SequenceAccountGeneratorTest.java index 6abb4df..f54c7d9 100644 --- a/KinanCity-core/src/test/java/com/kinancity/core/generator/impl/SequenceAccountGeneratorTest.java +++ b/KinanCity-core/src/test/java/com/kinancity/core/generator/impl/SequenceAccountGeneratorTest.java @@ -6,6 +6,8 @@ import com.kinancity.api.model.AccountData; import com.kinancity.core.generator.account.SequenceAccountGenerator; +import com.kinancity.core.generator.password.RandomPasswordGenerator; +import com.kinancity.core.generator.password.SinglePasswordGenerator; public class SequenceAccountGeneratorTest { @@ -16,21 +18,37 @@ public void sequenceTest() { generator.setBaseEmail("myname@domain.fr"); generator.setUsernamePattern("pref*****suf"); generator.setStartFrom(1234); - generator.setNbAccounts(3); + generator.setNbAccounts(4); AccountData data; + generator.setPasswordGenerator(new SinglePasswordGenerator("Test")); + data = generator.next(); assertThat(data).isNotNull(); assertThat(data.getUsername()).isEqualTo("pref01234suf"); + assertThat(data.getPassword()).isEqualTo("Test"); + + generator.setPasswordGenerator(new RandomPasswordGenerator(-1)); data = generator.next(); assertThat(data).isNotNull(); assertThat(data.getUsername()).isEqualTo("pref01235suf"); + assertThat(data.getPassword().length()).isBetween(8, 50); + + generator.setPasswordGenerator(new RandomPasswordGenerator(5)); data = generator.next(); assertThat(data).isNotNull(); assertThat(data.getUsername()).isEqualTo("pref01236suf"); + assertThat(data.getPassword().length()).isEqualTo(8); + + generator.setPasswordGenerator(new RandomPasswordGenerator(100)); + + data = generator.next(); + assertThat(data).isNotNull(); + assertThat(data.getUsername()).isEqualTo("pref01237suf"); + assertThat(data.getPassword().length()).isEqualTo(50); data = generator.next(); assertThat(data).isNull();