From 045361ade510fb7ee712a9e6a76d5a8e255939b6 Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Fri, 12 Jul 2024 10:18:52 +0200 Subject: [PATCH] password hash --- .../hsadminng/hash/HashGenerator.java | 89 +++++++++++++++ .../hash/LinuxEtcShadowHashGenerator.java | 108 +++--------------- .../MySQLNativePasswordHashGenerator.java | 35 ++++++ .../HsMariaDbUserHostingAssetValidator.java | 4 +- .../HsUnixUserHostingAssetValidator.java | 5 +- .../hs/validation/PasswordProperty.java | 6 +- .../hsadminng/hash/HashGeneratorUnitTest.java | 56 +++++++++ .../LinuxEtcShadowHashGeneratorUnitTest.java | 51 --------- ...sHostingAssetControllerAcceptanceTest.java | 4 +- ...iaDbUserHostingAssetValidatorUnitTest.java | 9 +- ...UnixUserHostingAssetValidatorUnitTest.java | 6 +- .../validation/PasswordPropertyUnitTest.java | 8 +- 12 files changed, 217 insertions(+), 164 deletions(-) create mode 100644 src/main/java/net/hostsharing/hsadminng/hash/HashGenerator.java create mode 100644 src/main/java/net/hostsharing/hsadminng/hash/MySQLNativePasswordHashGenerator.java create mode 100644 src/test/java/net/hostsharing/hsadminng/hash/HashGeneratorUnitTest.java delete mode 100644 src/test/java/net/hostsharing/hsadminng/hash/LinuxEtcShadowHashGeneratorUnitTest.java diff --git a/src/main/java/net/hostsharing/hsadminng/hash/HashGenerator.java b/src/main/java/net/hostsharing/hsadminng/hash/HashGenerator.java new file mode 100644 index 00000000..345f0ed0 --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/hash/HashGenerator.java @@ -0,0 +1,89 @@ +package net.hostsharing.hsadminng.hash; + +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.PriorityQueue; +import java.util.Queue; +import java.util.function.BiFunction; +import java.util.random.RandomGenerator; + +import lombok.Getter; + +/** + * Usage-example to generate hash: + * HashGenerator.using(LINUX_SHA512).withRandomSalt().hash("plaintext password"); + * + * Usage-example to verify hash: + * HashGenerator.fromHash("hashed password).verify("plaintext password"); + */ +@Getter +public final class HashGenerator { + + private static final RandomGenerator random = new SecureRandom(); + private static final Queue predefinedSalts = new PriorityQueue<>(); + + public static final int RANDOM_SALT_LENGTH = 16; + private static final String RANDOM_SALT_CHARACTERS = + "abcdefghijklmnopqrstuvwxyz" + + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + "0123456789/."; + + public enum Algorithm { + LINUX_SHA512(LinuxEtcShadowHashGenerator::hash, "6"), + LINUX_YESCRYPT(LinuxEtcShadowHashGenerator::hash, "y"), + MYSQL_NATIVE(MySQLNativePasswordHashGenerator::hash, "*"); + + final BiFunction implementation; + final String prefix; + + Algorithm(BiFunction implementation, final String prefix) { + this.implementation = implementation; + this.prefix = prefix; + } + + static Algorithm byPrefix(final String prefix) { + return Arrays.stream(Algorithm.values()).filter(a -> a.prefix.equals(prefix)).findAny() + .orElseThrow(() -> new IllegalArgumentException("unknown hash algorithm: '" + prefix + "'")); + } + } + + private final Algorithm algorithm; + private String salt; + + public static HashGenerator using(final Algorithm algorithm) { + return new HashGenerator(algorithm); + } + + private HashGenerator(final Algorithm algorithm) { + this.algorithm = algorithm; + } + + public String hash(final String plaintextPassword) { + if (plaintextPassword == null) { + throw new IllegalStateException("no password given"); + } + + return algorithm.implementation.apply(this, plaintextPassword); + } + + public static void nextSalt(final String salt) { + predefinedSalts.add(salt); + } + + public HashGenerator withSalt(final String salt) { + this.salt = salt; + return this; + } + + public HashGenerator withRandomSalt() { + if (!predefinedSalts.isEmpty()) { + return withSalt(predefinedSalts.poll()); + } + final var stringBuilder = new StringBuilder(RANDOM_SALT_LENGTH); + for (int i = 0; i < RANDOM_SALT_LENGTH; ++i) { + int randomIndex = random.nextInt(RANDOM_SALT_CHARACTERS.length()); + stringBuilder.append(RANDOM_SALT_CHARACTERS.charAt(randomIndex)); + } + return withSalt(stringBuilder.toString()); + } +} diff --git a/src/main/java/net/hostsharing/hsadminng/hash/LinuxEtcShadowHashGenerator.java b/src/main/java/net/hostsharing/hsadminng/hash/LinuxEtcShadowHashGenerator.java index c030b830..aaed6fd0 100644 --- a/src/main/java/net/hostsharing/hsadminng/hash/LinuxEtcShadowHashGenerator.java +++ b/src/main/java/net/hostsharing/hsadminng/hash/LinuxEtcShadowHashGenerator.java @@ -1,107 +1,31 @@ package net.hostsharing.hsadminng.hash; -import java.security.SecureRandom; -import java.util.Arrays; -import java.util.PriorityQueue; -import java.util.Queue; -import java.util.random.RandomGenerator; - import com.sun.jna.Library; import com.sun.jna.Native; public class LinuxEtcShadowHashGenerator { - private static final RandomGenerator random = new SecureRandom(); - private static final Queue predefinedSalts = new PriorityQueue<>(); - - public static final int SALT_LENGTH = 16; - - private final String plaintextPassword; - private Algorithm algorithm; - - public enum Algorithm { - SHA512("6"), - YESCRYPT("y"); - - final String prefix; - - Algorithm(final String prefix) { - this.prefix = prefix; - } - - static Algorithm byPrefix(final String prefix) { - return Arrays.stream(Algorithm.values()).filter(a -> a.prefix.equals(prefix)).findAny() - .orElseThrow(() -> new IllegalArgumentException("unknown hash algorithm: '" + prefix + "'")); - } - } - - private static final String SALT_CHARACTERS = - "abcdefghijklmnopqrstuvwxyz" + - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + - "0123456789/."; - - private String salt; - - public static LinuxEtcShadowHashGenerator hash(final String plaintextPassword) { - return new LinuxEtcShadowHashGenerator(plaintextPassword); - } - - private LinuxEtcShadowHashGenerator(final String plaintextPassword) { - this.plaintextPassword = plaintextPassword; - } - - public LinuxEtcShadowHashGenerator using(final Algorithm algorithm) { - this.algorithm = algorithm; - return this; - } - - void verify(final String givenHash) { - final var parts = givenHash.split("\\$"); - if (parts.length < 3 || parts.length > 5) { - throw new IllegalArgumentException("not a " + algorithm.name() + " Linux hash: " + givenHash); - } - - algorithm = Algorithm.byPrefix(parts[1]); - salt = parts.length == 4 ? parts[2] : parts[2] + "$" + parts[3]; - - if (!generate().equals(givenHash)) { - throw new IllegalArgumentException("invalid password"); - } - } - - public String generate() { - if (salt == null) { + public static String hash(final HashGenerator generator, final String payload) { + if (generator.getSalt() == null) { throw new IllegalStateException("no salt given"); } - if (plaintextPassword == null) { - throw new IllegalStateException("no password given"); + + return NativeCryptLibrary.INSTANCE.crypt(payload, "$" + generator.getAlgorithm().prefix + "$" + generator.getSalt()); + } + + public static void verify(final String givenHash, final String payload) { + + final var parts = givenHash.split("\\$"); + if (parts.length < 3 || parts.length > 5) { + throw new IllegalArgumentException("hash with unknown hash method: " + givenHash); } - return NativeCryptLibrary.INSTANCE.crypt(plaintextPassword, "$" + algorithm.prefix + "$" + salt); - } - - public static void nextSalt(final String salt) { - predefinedSalts.add(salt); - } - - public LinuxEtcShadowHashGenerator withSalt(final String salt) { - this.salt = salt; - return this; - } - - public LinuxEtcShadowHashGenerator withRandomSalt() { - if (!predefinedSalts.isEmpty()) { - return withSalt(predefinedSalts.poll()); + final var algorithm = HashGenerator.Algorithm.byPrefix(parts[1]); + final var salt = parts.length == 4 ? parts[2] : parts[2] + "$" + parts[3]; + final var calcualatedHash = HashGenerator.using(algorithm).withSalt(salt).hash(payload); + if (!calcualatedHash.equals(givenHash)) { + throw new IllegalArgumentException("invalid password"); } - final var stringBuilder = new StringBuilder(SALT_LENGTH); - for (int i = 0; i < SALT_LENGTH; ++i) { - int randomIndex = random.nextInt(SALT_CHARACTERS.length()); - stringBuilder.append(SALT_CHARACTERS.charAt(randomIndex)); - } - return withSalt(stringBuilder.toString()); - } - public static void main(String[] args) { - System.out.println(NativeCryptLibrary.INSTANCE.crypt("given password", "$6$abcdefghijklmno")); } public interface NativeCryptLibrary extends Library { diff --git a/src/main/java/net/hostsharing/hsadminng/hash/MySQLNativePasswordHashGenerator.java b/src/main/java/net/hostsharing/hsadminng/hash/MySQLNativePasswordHashGenerator.java new file mode 100644 index 00000000..12eeed44 --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/hash/MySQLNativePasswordHashGenerator.java @@ -0,0 +1,35 @@ +package net.hostsharing.hsadminng.hash; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class MySQLNativePasswordHashGenerator { + + public static String hash(final HashGenerator generator, final String password) { + // TODO.impl: if a random salt is generated or not should be part of the algorithm definition +// if (generator.getSalt() != null) { +// throw new IllegalStateException("salt not supported"); +// } + + try { + final var sha1 = MessageDigest.getInstance("SHA-1"); + final var firstHash = sha1.digest(password.getBytes()); + final var secondHash = sha1.digest(firstHash); + return "*" + bytesToHex(secondHash).toUpperCase(); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("SHA-1 algorithm not found", e); + } + } + + private static String bytesToHex(byte[] bytes) { + final var hexString = new StringBuilder(); + for (byte b : bytes) { + final var hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + return hexString.toString(); + } +} diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbUserHostingAssetValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbUserHostingAssetValidator.java index 778bd7ba..0b99e56c 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbUserHostingAssetValidator.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbUserHostingAssetValidator.java @@ -1,6 +1,6 @@ package net.hostsharing.hsadminng.hs.hosting.asset.validators; -import net.hostsharing.hsadminng.hash.LinuxEtcShadowHashGenerator; +import net.hostsharing.hsadminng.hash.HashGenerator; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity; import java.util.regex.Pattern; @@ -22,7 +22,7 @@ class HsMariaDbUserHostingAssetValidator extends HostingAssetEntityValidator { // referenceProperty(assignedToAsset).isWriteOnce(), // ); - passwordProperty("password").minLength(8).maxLength(40).hashedUsing(LinuxEtcShadowHashGenerator.Algorithm.SHA512).writeOnly()); + passwordProperty("password").minLength(8).maxLength(40).hashedUsing(HashGenerator.Algorithm.MYSQL_NATIVE).writeOnly()); } @Override diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidator.java index 1d44f6ac..6a4299f1 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidator.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidator.java @@ -1,6 +1,6 @@ package net.hostsharing.hsadminng.hs.hosting.asset.validators; -import net.hostsharing.hsadminng.hash.LinuxEtcShadowHashGenerator; +import net.hostsharing.hsadminng.hash.HashGenerator; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType; import net.hostsharing.hsadminng.hs.validation.PropertiesProvider; @@ -30,7 +30,8 @@ class HsUnixUserHostingAssetValidator extends HostingAssetEntityValidator { .withDefault("/bin/false"), stringProperty("homedir").readOnly().computedBy(HsUnixUserHostingAssetValidator::computeHomedir), stringProperty("totpKey").matchesRegEx("^0x([0-9A-Fa-f]{2})+$").minLength(20).maxLength(256).undisclosed().writeOnly().optional(), - passwordProperty("password").minLength(8).maxLength(40).hashedUsing(LinuxEtcShadowHashGenerator.Algorithm.SHA512).writeOnly()); + passwordProperty("password").minLength(8).maxLength(40).hashedUsing(HashGenerator.Algorithm.LINUX_SHA512).writeOnly()); + // TODO.spec: private SSH keys? } @Override diff --git a/src/main/java/net/hostsharing/hsadminng/hs/validation/PasswordProperty.java b/src/main/java/net/hostsharing/hsadminng/hs/validation/PasswordProperty.java index 83cdf975..732151cd 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/validation/PasswordProperty.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/validation/PasswordProperty.java @@ -1,13 +1,13 @@ package net.hostsharing.hsadminng.hs.validation; -import net.hostsharing.hsadminng.hash.LinuxEtcShadowHashGenerator.Algorithm; +import net.hostsharing.hsadminng.hash.HashGenerator; +import net.hostsharing.hsadminng.hash.HashGenerator.Algorithm; import lombok.Setter; import java.util.List; import java.util.stream.Stream; import static java.util.Optional.ofNullable; -import static net.hostsharing.hsadminng.hash.LinuxEtcShadowHashGenerator.hash; import static net.hostsharing.hsadminng.mapper.Array.insertNewEntriesAfterExistingEntry; @Setter @@ -36,7 +36,7 @@ public class PasswordProperty extends StringProperty { this.hashedUsing = algorithm; computedBy((entity) -> ofNullable(entity.getDirectValue(propertyName, String.class)) - .map(password -> hash(password).using(algorithm).withRandomSalt().generate()) + .map(password -> HashGenerator.using(algorithm).withRandomSalt().hash(password)) .orElse(null)); return self(); } diff --git a/src/test/java/net/hostsharing/hsadminng/hash/HashGeneratorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hash/HashGeneratorUnitTest.java new file mode 100644 index 00000000..6c70bc8e --- /dev/null +++ b/src/test/java/net/hostsharing/hsadminng/hash/HashGeneratorUnitTest.java @@ -0,0 +1,56 @@ +package net.hostsharing.hsadminng.hash; + +import org.junit.jupiter.api.Test; + +import static net.hostsharing.hsadminng.hash.HashGenerator.Algorithm.LINUX_SHA512; +import static net.hostsharing.hsadminng.hash.HashGenerator.Algorithm.MYSQL_NATIVE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + +class HashGeneratorUnitTest { + + final String GIVEN_PASSWORD = "given password"; + final String WRONG_PASSWORD = "wrong password"; + final String GIVEN_SALT = "0123456789abcdef"; + + // generated via mkpasswd for plaintext password GIVEN_PASSWORD (see above) + final String GIVEN_LINUX_SHA512_HASH = "$6$ooei1HK6JXVaI7KC$sY5d9fEOr36hjh4CYwIKLMfRKL1539bEmbVCZ.zPiH0sv7jJVnoIXb5YEefEtoSM2WWgDi9hr7vXRe3Nw8zJP/"; + final String GIVEN_LINUX_YESCRYPT_HASH = "$y$j9T$wgYACPmBXvlMg2MzeZA0p1$KXUzd28nG.67GhPnBZ3aZsNNA5bWFdL/dyG4wS0iRw7"; + + @Test + void verifiesLinuxPasswordAgainstSha512HashFromMkpasswd() { + LinuxEtcShadowHashGenerator.verify(GIVEN_LINUX_SHA512_HASH, GIVEN_PASSWORD); // throws exception if wrong + } + + @Test + void verifiesLinuxPasswordAgainstYescryptHashFromMkpasswd() { + LinuxEtcShadowHashGenerator.verify(GIVEN_LINUX_YESCRYPT_HASH, GIVEN_PASSWORD); // throws exception if wrong + } + + @Test + void verifiesHashedLinuxPasswordWithRandomSalt() { + final var hash = HashGenerator.using(LINUX_SHA512).withRandomSalt().hash(GIVEN_PASSWORD); + LinuxEtcShadowHashGenerator.verify(hash, GIVEN_PASSWORD); // throws exception if wrong + } + + @Test + void verifiesLinuxHashedPasswordWithGivenSalt() { + final var hash = HashGenerator.using(LINUX_SHA512).withSalt(GIVEN_SALT).hash(GIVEN_PASSWORD); + LinuxEtcShadowHashGenerator.verify(hash, GIVEN_PASSWORD); // throws exception if wrong + } + + @Test + void throwsExceptionForInvalidLinuxPassword() { + final var hash = HashGenerator.using(LINUX_SHA512).withRandomSalt().hash(GIVEN_PASSWORD); + final var throwable = catchThrowable(() -> + LinuxEtcShadowHashGenerator.verify(hash, WRONG_PASSWORD) + ); + assertThat(throwable).hasMessage("invalid password"); + } + + @Test + void verifiesMySqlNativePassword() { + final var hash = HashGenerator.using(MYSQL_NATIVE).hash("Test1234"); + assertThat(hash).isEqualTo("*14F1A8C42F8B6D4662BB3ED290FD37BF135FE45C"); + } +} diff --git a/src/test/java/net/hostsharing/hsadminng/hash/LinuxEtcShadowHashGeneratorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hash/LinuxEtcShadowHashGeneratorUnitTest.java deleted file mode 100644 index c5abcc08..00000000 --- a/src/test/java/net/hostsharing/hsadminng/hash/LinuxEtcShadowHashGeneratorUnitTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package net.hostsharing.hsadminng.hash; - -import org.junit.jupiter.api.Test; - -import static net.hostsharing.hsadminng.hash.LinuxEtcShadowHashGenerator.Algorithm.SHA512; -import static net.hostsharing.hsadminng.hash.LinuxEtcShadowHashGenerator.hash; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.catchThrowable; - -class LinuxEtcShadowHashGeneratorUnitTest { - - final String GIVEN_PASSWORD = "given password"; - final String WRONG_PASSWORD = "wrong password"; - final String GIVEN_SALT = "0123456789abcdef"; - - // generated via mkpasswd for plaintext password GIVEN_PASSWORD (see above) - final String GIVEN_SHA512_HASH = "$6$ooei1HK6JXVaI7KC$sY5d9fEOr36hjh4CYwIKLMfRKL1539bEmbVCZ.zPiH0sv7jJVnoIXb5YEefEtoSM2WWgDi9hr7vXRe3Nw8zJP/"; - final String GIVEN_YESCRYPT_HASH = "$y$j9T$wgYACPmBXvlMg2MzeZA0p1$KXUzd28nG.67GhPnBZ3aZsNNA5bWFdL/dyG4wS0iRw7"; - - @Test - void verifiesPasswordAgainstSha512HashFromMkpasswd() { - hash(GIVEN_PASSWORD).verify(GIVEN_SHA512_HASH); // throws exception if wrong - } - - @Test - void verifiesPasswordAgainstYescryptHashFromMkpasswd() { - hash(GIVEN_PASSWORD).verify(GIVEN_YESCRYPT_HASH); // throws exception if wrong - } - - @Test - void verifiesHashedPasswordWithRandomSalt() { - final var hash = hash(GIVEN_PASSWORD).using(SHA512).withRandomSalt().generate(); - hash(GIVEN_PASSWORD).verify(hash); // throws exception if wrong - } - - @Test - void verifiesHashedPasswordWithGivenSalt() { - final var givenPasswordHash =hash(GIVEN_PASSWORD).using(SHA512).withSalt(GIVEN_SALT).generate(); - hash(GIVEN_PASSWORD).verify(givenPasswordHash); // throws exception if wrong - } - - @Test - void throwsExceptionForInvalidPassword() { - final var givenPasswordHash = hash(GIVEN_PASSWORD).using(SHA512).withRandomSalt().generate(); - - final var throwable = catchThrowable(() -> - hash(WRONG_PASSWORD).verify(givenPasswordHash) // throws exception if wrong); - ); - assertThat(throwable).hasMessage("invalid password"); - } -} diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java index e45a157b..28933662 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java @@ -3,7 +3,7 @@ package net.hostsharing.hsadminng.hs.hosting.asset; import io.restassured.RestAssured; import io.restassured.http.ContentType; import net.hostsharing.hsadminng.HsadminNgApplication; -import net.hostsharing.hsadminng.hash.LinuxEtcShadowHashGenerator; +import net.hostsharing.hsadminng.hash.HashGenerator; import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity; import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRepository; import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType; @@ -537,7 +537,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup .identifier("fir01-temp") .caption("some test-unix-user") .build()); - LinuxEtcShadowHashGenerator.nextSalt("Jr5w/Y8zo8pCkqg7"); + HashGenerator.nextSalt("Jr5w/Y8zo8pCkqg7"); RestAssured // @formatter:off .given() diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbUserHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbUserHostingAssetValidatorUnitTest.java index 18683a68..7406a6fe 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbUserHostingAssetValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsMariaDbUserHostingAssetValidatorUnitTest.java @@ -1,6 +1,5 @@ package net.hostsharing.hsadminng.hs.hosting.asset.validators; -import net.hostsharing.hsadminng.hash.LinuxEtcShadowHashGenerator; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity.HsHostingAssetEntityBuilder; import org.junit.jupiter.api.Test; @@ -33,7 +32,7 @@ class HsMariaDbUserHostingAssetValidatorUnitTest { .identifier("xyz00_temp") .caption("some valid test MariaDB-User") .config(new HashMap<>(ofEntries( - entry("password", "Hallo Datenbank, lass mich rein!") + entry("password", "Test1234") ))); } @@ -47,7 +46,7 @@ class HsMariaDbUserHostingAssetValidatorUnitTest { // then assertThat(props).extracting(Object::toString).containsExactlyInAnyOrder( - "{type=password, propertyName=password, minLength=8, maxLength=40, writeOnly=true, computed=true, hashedUsing=SHA512, undisclosed=true}" + "{type=password, propertyName=password, minLength=8, maxLength=40, writeOnly=true, computed=true, hashedUsing=MYSQL_NATIVE, undisclosed=true}" ); } @@ -58,12 +57,12 @@ class HsMariaDbUserHostingAssetValidatorUnitTest { final var validator = HostingAssetEntityValidatorRegistry.forType(givenMariaDbUserHostingAsset.getType()); // when - LinuxEtcShadowHashGenerator.nextSalt("Ly3LbsArtL5u4EVt"); // FIXME + // HashGenerator.nextSalt("Ly3LbsArtL5u4EVt"); // not needed for mysql_native_password validator.prepareProperties(givenMariaDbUserHostingAsset); // then assertThat(givenMariaDbUserHostingAsset.getConfig()).containsExactlyInAnyOrderEntriesOf(ofEntries( - entry("password", "$6$Ly3LbsArtL5u4EVt$T7VM5uCq7I1cKttipCX4TQdyawdpLcSmjApreI4fZcORPOkEkxy9iz.9Dri6IVbO08OKTR8OE8hvnblU5Ax6o.") + entry("password", "*14F1A8C42F8B6D4662BB3ED290FD37BF135FE45C") )); } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidatorUnitTest.java index 9a17eb27..61cebf95 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidatorUnitTest.java @@ -1,6 +1,6 @@ package net.hostsharing.hsadminng.hs.hosting.asset.validators; -import net.hostsharing.hsadminng.hash.LinuxEtcShadowHashGenerator; +import net.hostsharing.hsadminng.hash.HashGenerator; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType; import org.junit.jupiter.api.Test; @@ -50,7 +50,7 @@ class HsUnixUserHostingAssetValidatorUnitTest { final var validator = HostingAssetEntityValidatorRegistry.forType(unixUserHostingAsset.getType()); // when - LinuxEtcShadowHashGenerator.nextSalt("Ly3LbsArtL5u4EVt"); + HashGenerator.nextSalt("Ly3LbsArtL5u4EVt"); validator.prepareProperties(unixUserHostingAsset); // then @@ -141,7 +141,7 @@ class HsUnixUserHostingAssetValidatorUnitTest { final var validator = HostingAssetEntityValidatorRegistry.forType(unixUserHostingAsset.getType()); // when - LinuxEtcShadowHashGenerator.nextSalt("Ly3LbsArtL5u4EVt"); + HashGenerator.nextSalt("Ly3LbsArtL5u4EVt"); final var result = validator.revampProperties(unixUserHostingAsset, unixUserHostingAsset.getConfig()); // then diff --git a/src/test/java/net/hostsharing/hsadminng/hs/validation/PasswordPropertyUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/validation/PasswordPropertyUnitTest.java index 2350b288..663a7715 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/validation/PasswordPropertyUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/validation/PasswordPropertyUnitTest.java @@ -1,5 +1,6 @@ package net.hostsharing.hsadminng.hs.validation; +import net.hostsharing.hsadminng.hash.LinuxEtcShadowHashGenerator; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -8,8 +9,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import static net.hostsharing.hsadminng.hash.LinuxEtcShadowHashGenerator.Algorithm.SHA512; -import static net.hostsharing.hsadminng.hash.LinuxEtcShadowHashGenerator.hash; +import static net.hostsharing.hsadminng.hash.HashGenerator.Algorithm.LINUX_SHA512; import static net.hostsharing.hsadminng.hs.validation.PasswordProperty.passwordProperty; import static net.hostsharing.hsadminng.mapper.PatchableMapWrapper.entry; import static org.assertj.core.api.Assertions.assertThat; @@ -17,7 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; class PasswordPropertyUnitTest { private final ValidatableProperty passwordProp = - passwordProperty("password").minLength(8).maxLength(40).hashedUsing(SHA512).writeOnly(); + passwordProperty("password").minLength(8).maxLength(40).hashedUsing(LINUX_SHA512).writeOnly(); private final List violations = new ArrayList<>(); @ParameterizedTest @@ -115,6 +115,6 @@ class PasswordPropertyUnitTest { }); // then - hash("some password").using(SHA512).withRandomSalt().generate(); // throws exception if wrong + LinuxEtcShadowHashGenerator.verify(result, "some password"); // throws exception if wrong } }