1
0

add-postgresql-instance-user-and-database-validation (#76)

Co-authored-by: Michael Hoennig <michael@hoennig.de>
Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/76
Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
Michael Hoennig
2024-07-15 12:00:34 +02:00
parent 46fce275ae
commit c32361a83a
27 changed files with 681 additions and 36 deletions

View File

@@ -2,8 +2,12 @@ package net.hostsharing.hsadminng.hash;
import org.junit.jupiter.api.Test;
import java.nio.charset.Charset;
import java.util.Base64;
import static net.hostsharing.hsadminng.hash.HashGenerator.Algorithm.LINUX_SHA512;
import static net.hostsharing.hsadminng.hash.HashGenerator.Algorithm.MYSQL_NATIVE;
import static net.hostsharing.hsadminng.hash.HashGenerator.Algorithm.SCRAM_SHA256;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
@@ -14,17 +18,22 @@ class HashGeneratorUnitTest {
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";
final String GIVEN_LINUX_GENERATED_SHA512_HASH = "$6$ooei1HK6JXVaI7KC$sY5d9fEOr36hjh4CYwIKLMfRKL1539bEmbVCZ.zPiH0sv7jJVnoIXb5YEefEtoSM2WWgDi9hr7vXRe3Nw8zJP/";
final String GIVEN_LINUX_GENERATED_YESCRYPT_HASH = "$y$j9T$wgYACPmBXvlMg2MzeZA0p1$KXUzd28nG.67GhPnBZ3aZsNNA5bWFdL/dyG4wS0iRw7";
// generated in PostgreSQL using:
// CREATE USER test WITH PASSWORD 'given password';
// SELECT rolname, rolpassword FROM pg_authid WHERE rolname = 'test';
final String GIVEN_POSTGRESQL_GENERATED_SCRAM_SHA256_HASH = "SCRAM-SHA-256$4096:m8M12fdSTsKH+ywthTx1Zw==$4vsB1OddRNdsej9NPAFh91MPdtbOPjkQ85LQZS5lV0Q=:NsVpQNx4Ic/8Sqj1dxfBzUAxyF4FCTMpIsI+bOZCTfA=";
@Test
void verifiesLinuxPasswordAgainstSha512HashFromMkpasswd() {
LinuxEtcShadowHashGenerator.verify(GIVEN_LINUX_SHA512_HASH, GIVEN_PASSWORD); // throws exception if wrong
LinuxEtcShadowHashGenerator.verify(GIVEN_LINUX_GENERATED_SHA512_HASH, GIVEN_PASSWORD); // throws exception if wrong
}
@Test
void verifiesLinuxPasswordAgainstYescryptHashFromMkpasswd() {
LinuxEtcShadowHashGenerator.verify(GIVEN_LINUX_YESCRYPT_HASH, GIVEN_PASSWORD); // throws exception if wrong
LinuxEtcShadowHashGenerator.verify(GIVEN_LINUX_GENERATED_YESCRYPT_HASH, GIVEN_PASSWORD); // throws exception if wrong
}
@Test
@@ -49,8 +58,20 @@ class HashGeneratorUnitTest {
}
@Test
void verifiesMySqlNativePassword() {
void generatesMySqlNativePasswordHash() {
final var hash = HashGenerator.using(MYSQL_NATIVE).hash("Test1234");
assertThat(hash).isEqualTo("*14F1A8C42F8B6D4662BB3ED290FD37BF135FE45C");
}
@Test
void generatePostgreSqlScramPasswordHash() {
// given the same salt, extracted from the hash as generated by PostgreSQL
final var postgresBase64Salt = Base64.getDecoder().decode(GIVEN_POSTGRESQL_GENERATED_SCRAM_SHA256_HASH.split("\\$")[1].split(":")[1]);
// when the hash is re-generated via Java
final var hash = HashGenerator.using(SCRAM_SHA256).withSalt(new String(postgresBase64Salt, Charset.forName("latin1"))).hash(GIVEN_PASSWORD);
// then we are getting the same hash
assertThat(hash).isEqualTo(GIVEN_POSTGRESQL_GENERATED_SCRAM_SHA256_HASH);
}
}

View File

@@ -426,6 +426,68 @@ public class HsHostingAssetControllerRestTest {
}
}
]
"""),
PGSQL_INSTANCE(
List.of(
HsHostingAssetEntity.builder()
.type(HsHostingAssetType.PGSQL_INSTANCE)
.parentAsset(TEST_MANAGED_SERVER_HOSTING_ASSET)
.identifier("vm1234|PgSql.default")
.caption("some fake PgSql instance")
.build()),
"""
[
{
"type": "PGSQL_INSTANCE",
"identifier": "vm1234|PgSql.default",
"caption": "some fake PgSql instance",
"alarmContact": null,
"config": {}
}
]
"""),
PGSQL_USER(
List.of(
HsHostingAssetEntity.builder()
.type(HsHostingAssetType.PGSQL_USER)
.identifier("xyz00_temp")
.caption("some fake PgSql user")
.build()),
"""
[
{
"type": "PGSQL_USER",
"identifier": "xyz00_temp",
"caption": "some fake PgSql user",
"alarmContact": null,
"config": {}
}
]
"""),
PGSQL_DATABASE(
List.of(
HsHostingAssetEntity.builder()
.type(HsHostingAssetType.PGSQL_DATABASE)
.identifier("xyz00_temp")
.caption("some fake PgSql database")
.config(Map.ofEntries(
entry("encoding", "latin1"),
entry("collation", "latin2")
))
.build()),
"""
[
{
"type": "PGSQL_DATABASE",
"identifier": "xyz00_temp",
"caption": "some fake PgSql database",
"alarmContact": null,
"config": {
"encoding": "latin1",
"collation": "latin2"
}
}
]
""");
final HsHostingAssetType assetType;

View File

@@ -44,7 +44,10 @@ class HsHostingAssetPropsControllerAcceptanceTest {
"EMAIL_ADDRESS",
"MARIADB_INSTANCE",
"MARIADB_USER",
"MARIADB_DATABASE"
"MARIADB_DATABASE",
"PGSQL_INSTANCE",
"PGSQL_USER",
"PGSQL_DATABASE"
]
"""));
// @formatter:on

View File

@@ -246,7 +246,8 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu
exactlyTheseAssetsAreReturned(
result,
"HsHostingAssetEntity(MANAGED_WEBSPACE, sec01, some Webspace, MANAGED_SERVER:vm1012, D-1000212:D-1000212 default project:separate ManagedWebspace)",
"HsHostingAssetEntity(MARIADB_INSTANCE, vm1012.MariaDB.default, some default MariaDB instance, MANAGED_SERVER:vm1012)");
"HsHostingAssetEntity(MARIADB_INSTANCE, vm1012.MariaDB.default, some default MariaDB instance, MANAGED_SERVER:vm1012)",
"HsHostingAssetEntity(PGSQL_INSTANCE, vm1012.Postgresql.default, some default Postgresql instance, MANAGED_SERVER:vm1012)");
}
}

View File

@@ -132,7 +132,6 @@ class HsHostingAssetTypeUnitTest {
HA_MARIADB_USER *==> HA_MANAGED_WEBSPACE
HA_MARIADB_USER o..> HA_MARIADB_INSTANCE
HA_MARIADB_DATABASE *==> HA_MARIADB_USER
HA_MARIADB_DATABASE o..> HA_MARIADB_INSTANCE
HA_IP_NUMBER o..> HA_CLOUD_SERVER
HA_IP_NUMBER o..> HA_MANAGED_SERVER
HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE
@@ -191,10 +190,9 @@ class HsHostingAssetTypeUnitTest {
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
HA_PGSQL_INSTANCE *==> HA_MANAGED_SERVER
HA_PGSQL_USER *==> HA_PGSQL_INSTANCE
HA_PGSQL_USER o..> HA_MANAGED_WEBSPACE
HA_PGSQL_DATABASE *==> HA_MANAGED_WEBSPACE
HA_PGSQL_DATABASE o..> HA_PGSQL_INSTANCE
HA_PGSQL_USER *==> HA_MANAGED_WEBSPACE
HA_PGSQL_USER o..> HA_PGSQL_INSTANCE
HA_PGSQL_DATABASE *==> HA_PGSQL_USER
HA_IP_NUMBER o..> HA_CLOUD_SERVER
HA_IP_NUMBER o..> HA_MANAGED_SERVER
HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE

View File

@@ -42,7 +42,10 @@ class HostingAssetEntityValidatorRegistryUnitTest {
HsHostingAssetType.EMAIL_ADDRESS,
HsHostingAssetType.MARIADB_INSTANCE,
HsHostingAssetType.MARIADB_USER,
HsHostingAssetType.MARIADB_DATABASE
HsHostingAssetType.MARIADB_DATABASE,
HsHostingAssetType.PGSQL_INSTANCE,
HsHostingAssetType.PGSQL_USER,
HsHostingAssetType.PGSQL_DATABASE
);
}
}

View File

@@ -40,7 +40,6 @@ class HsMariaDbDatabaseHostingAssetValidatorUnitTest {
return HsHostingAssetEntity.builder()
.type(MARIADB_DATABASE)
.parentAsset(GIVEN_MARIADB_USER)
.assignedToAsset(GIVEN_MARIADB_INSTANCE)
.identifier("xyz00_temp")
.caption("some valid test MariaDB-Database")
.config(new HashMap<>(ofEntries(
@@ -112,6 +111,6 @@ class HsMariaDbDatabaseHostingAssetValidatorUnitTest {
// then
assertThat(result).containsExactly(
"'identifier' expected to match '^xyz00$|^xyz00_[a-z0-9]+$', but is 'xyz99-temp'");
"'identifier' expected to match '^xyz00$|^xyz00_[a-z0-9_]+$', but is 'xyz99-temp'");
}
}

View File

@@ -117,6 +117,6 @@ class HsMariaDbUserHostingAssetValidatorUnitTest {
// then
assertThat(result).containsExactly(
"'identifier' expected to match '^xyz00$|^xyz00_[a-z0-9]+$', but is 'xyz99-temp'");
"'identifier' expected to match '^xyz00$|^xyz00_[a-z0-9_]+$', but is 'xyz99-temp'");
}
}

View File

@@ -0,0 +1,138 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity.HsHostingAssetEntityBuilder;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.stream.Stream;
import static java.util.Map.ofEntries;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.PGSQL_DATABASE;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.PGSQL_INSTANCE;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.PGSQL_USER;
import static net.hostsharing.hsadminng.hs.hosting.asset.TestHsHostingAssetEntities.TEST_MANAGED_SERVER_HOSTING_ASSET;
import static net.hostsharing.hsadminng.hs.hosting.asset.TestHsHostingAssetEntities.TEST_MANAGED_WEBSPACE_HOSTING_ASSET;
import static net.hostsharing.hsadminng.mapper.PatchMap.entry;
import static org.assertj.core.api.Assertions.assertThat;
class HsPostgreSqlDatabaseHostingAssetValidatorUnitTest {
private static final HsHostingAssetEntity GIVEN_PGSQL_INSTANCE = HsHostingAssetEntity.builder()
.type(PGSQL_INSTANCE)
.parentAsset(TEST_MANAGED_SERVER_HOSTING_ASSET)
.identifier("vm1234|PgSql.default")
.caption("some valid test PgSql-Instance")
.build();
private static final HsHostingAssetEntity GIVEN_PGSQL_USER = HsHostingAssetEntity.builder()
.type(PGSQL_USER)
.parentAsset(TEST_MANAGED_WEBSPACE_HOSTING_ASSET)
.assignedToAsset(GIVEN_PGSQL_INSTANCE)
.identifier("xyz00_temp")
.caption("some valid test PgSql-User")
.config(new HashMap<>(ofEntries(
entry("password", "Hallo Datenbank, lass mich rein!")
)))
.build();
private static HsHostingAssetEntityBuilder givenValidPgSqlDatabaseBuilder() {
return HsHostingAssetEntity.builder()
.type(PGSQL_DATABASE)
.parentAsset(GIVEN_PGSQL_USER)
.identifier("xyz00_temp")
.caption("some valid test PgSql-Database")
.config(new HashMap<>(ofEntries(
entry("encoding", "LATIN1")
)));
}
@Test
void describesItsProperties() {
// given
final var validator = HostingAssetEntityValidatorRegistry.forType(givenValidPgSqlDatabaseBuilder().build().getType());
// when
final var props = validator.properties();
// then
assertThat(props).extracting(Object::toString).containsExactlyInAnyOrder(
"{type=string, propertyName=encoding, matchesRegEx=[[A-Z0-9_]+], maxLength=24, provided=[LATIN1, UTF8], defaultValue=UTF8}"
);
}
@Test
void validatesValidEntity() {
// given
final var givenPgSqlUserHostingAsset = givenValidPgSqlDatabaseBuilder().build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenPgSqlUserHostingAsset.getType());
// when
final var result = Stream.concat(
validator.validateEntity(givenPgSqlUserHostingAsset).stream(),
validator.validateContext(givenPgSqlUserHostingAsset).stream()
).toList();
// then
assertThat(result).isEmpty();
}
@Test
void rejectsInvalidReferences() {
// given
final var givenPgSqlUserHostingAsset = givenValidPgSqlDatabaseBuilder()
.bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build())
.parentAsset(HsHostingAssetEntity.builder().type(PGSQL_INSTANCE).build())
.assignedToAsset(HsHostingAssetEntity.builder().type(PGSQL_INSTANCE).build())
.build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenPgSqlUserHostingAsset.getType());
// when
final var result = validator.validateEntity(givenPgSqlUserHostingAsset);
// then
assertThat(result).containsExactlyInAnyOrder(
"'PGSQL_DATABASE:xyz00_temp.config.unknown' is not expected but is set to 'wrong'",
"'PGSQL_DATABASE:xyz00_temp.config.encoding' is expected to be of type String, but is of type Integer"
);
}
@Test
void rejectsInvalidProperties() {
// given
final var givenPgSqlUserHostingAsset = givenValidPgSqlDatabaseBuilder()
.config(ofEntries(
entry("unknown", "wrong"),
entry("encoding", 10)
))
.build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenPgSqlUserHostingAsset.getType());
// when
final var result = validator.validateEntity(givenPgSqlUserHostingAsset);
// then
assertThat(result).containsExactlyInAnyOrder(
"'PGSQL_DATABASE:xyz00_temp.config.unknown' is not expected but is set to 'wrong'",
"'PGSQL_DATABASE:xyz00_temp.config.encoding' is expected to be of type String, but is of type Integer"
);
}
@Test
void rejectsInvalidIdentifier() {
// given
final var givenPgSqlUserHostingAsset = givenValidPgSqlDatabaseBuilder()
.identifier("xyz99-temp")
.build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenPgSqlUserHostingAsset.getType());
// when
final var result = validator.validateEntity(givenPgSqlUserHostingAsset);
// then
assertThat(result).containsExactly(
"'identifier' expected to match '^xyz00$|^xyz00_[a-z0-9_]+$', but is 'xyz99-temp'");
}
}

View File

@@ -0,0 +1,116 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity.HsHostingAssetEntityBuilder;
import org.junit.jupiter.api.Test;
import java.util.Map;
import static java.util.Map.entry;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SMTP_SETUP;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MARIADB_INSTANCE;
import static net.hostsharing.hsadminng.hs.hosting.asset.TestHsHostingAssetEntities.TEST_MANAGED_SERVER_HOSTING_ASSET;
import static net.hostsharing.hsadminng.hs.hosting.asset.validators.HsMariaDbInstanceHostingAssetValidator.DEFAULT_INSTANCE_IDENTIFIER_SUFFIX;
import static org.assertj.core.api.Assertions.assertThat;
class HsPostgreSqlInstanceHostingAssetValidatorUnitTest {
static HsHostingAssetEntityBuilder validEntityBuilder() {
return HsHostingAssetEntity.builder()
.type(MARIADB_INSTANCE)
.parentAsset(TEST_MANAGED_SERVER_HOSTING_ASSET)
.identifier(TEST_MANAGED_SERVER_HOSTING_ASSET.getIdentifier() + DEFAULT_INSTANCE_IDENTIFIER_SUFFIX);
}
@Test
void containsExpectedProperties() {
// when
final var validator = HostingAssetEntityValidatorRegistry.forType(DOMAIN_SMTP_SETUP);
// then
assertThat(validator.properties()).map(Map::toString).isEmpty();
}
@Test
void preprocessesTakesIdentifierFromParent() {
// given
final var givenEntity = validEntityBuilder().build();
assertThat(givenEntity.getParentAsset().getIdentifier()).as("precondition failed").isEqualTo("vm1234");
final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
// when
validator.preprocessEntity(givenEntity);
// then
assertThat(givenEntity.getIdentifier()).isEqualTo("vm1234|MariaDB.default");
}
@Test
void acceptsValidEntity() {
// given
final var givenEntity = validEntityBuilder().build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
// when
final var result = validator.validateEntity(givenEntity);
// then
assertThat(result).isEmpty();
}
@Test
void rejectsInvalidIdentifier() {
// given
final var givenEntity = validEntityBuilder().identifier("example.org").build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
// when
final var result = validator.validateEntity(givenEntity);
// then
assertThat(result).containsExactly(
"'identifier' expected to match '^\\Qvm1234|MariaDB.default\\E$', but is 'example.org'"
);
}
@Test
void rejectsInvalidReferencedEntities() {
// given
final var mangedServerHostingAssetEntity = validEntityBuilder()
.bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build())
.parentAsset(HsHostingAssetEntity.builder().type(MANAGED_WEBSPACE).build())
.assignedToAsset(HsHostingAssetEntity.builder().type(MANAGED_WEBSPACE).build())
.build();
final var validator = HostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
// when
final var result = validator.validateEntity(mangedServerHostingAssetEntity);
// then
assertThat(result).containsExactlyInAnyOrder(
"'MARIADB_INSTANCE:vm1234|MariaDB.default.bookingItem' must be null but is of type CLOUD_SERVER",
"'MARIADB_INSTANCE:vm1234|MariaDB.default.parentAsset' must be of type MANAGED_SERVER but is of type MANAGED_WEBSPACE",
"'MARIADB_INSTANCE:vm1234|MariaDB.default.assignedToAsset' must be null but is of type MANAGED_WEBSPACE");
}
@Test
void rejectsInvalidProperties() {
// given
final var mangedServerHostingAssetEntity = validEntityBuilder()
.config(Map.ofEntries(
entry("any", "false")
))
.build();
final var validator = HostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
// when
final var result = validator.validateEntity(mangedServerHostingAssetEntity);
// then
assertThat(result).containsExactlyInAnyOrder(
"'MARIADB_INSTANCE:vm1234|MariaDB.default.config.any' is not expected but is set to 'false'");
}
}

View File

@@ -0,0 +1,125 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hash.HashGenerator;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity.HsHostingAssetEntityBuilder;
import org.junit.jupiter.api.Test;
import java.nio.charset.Charset;
import java.util.Base64;
import java.util.HashMap;
import java.util.stream.Stream;
import static java.util.Map.ofEntries;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.PGSQL_INSTANCE;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.PGSQL_USER;
import static net.hostsharing.hsadminng.hs.hosting.asset.TestHsHostingAssetEntities.TEST_MANAGED_SERVER_HOSTING_ASSET;
import static net.hostsharing.hsadminng.hs.hosting.asset.TestHsHostingAssetEntities.TEST_MANAGED_WEBSPACE_HOSTING_ASSET;
import static net.hostsharing.hsadminng.mapper.PatchMap.entry;
import static org.assertj.core.api.Assertions.assertThat;
class HsPostgreSqlUserHostingAssetValidatorUnitTest {
private static final HsHostingAssetEntity GIVEN_PGSQL_INSTANCE = HsHostingAssetEntity.builder()
.type(PGSQL_INSTANCE)
.parentAsset(TEST_MANAGED_SERVER_HOSTING_ASSET)
.identifier("vm1234|PgSql.default")
.caption("some valid test PgSql-Instance")
.build();
private static HsHostingAssetEntityBuilder givenValidMariaDbUserBuilder() {
return HsHostingAssetEntity.builder()
.type(PGSQL_USER)
.parentAsset(TEST_MANAGED_WEBSPACE_HOSTING_ASSET)
.assignedToAsset(GIVEN_PGSQL_INSTANCE)
.identifier("xyz00_temp")
.caption("some valid test PgSql-User")
.config(new HashMap<>(ofEntries(
entry("password", "Test1234")
)));
}
@Test
void describesItsProperties() {
// given
final var validator = HostingAssetEntityValidatorRegistry.forType(givenValidMariaDbUserBuilder().build().getType());
// when
final var props = validator.properties();
// then
assertThat(props).extracting(Object::toString).containsExactlyInAnyOrder(
"{type=password, propertyName=password, minLength=8, maxLength=40, writeOnly=true, computed=true, hashedUsing=SCRAM_SHA256, undisclosed=true}"
);
}
@Test
void preparesEntity() {
// given
final var givenMariaDbUserHostingAsset = givenValidMariaDbUserBuilder().build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenMariaDbUserHostingAsset.getType());
// when
HashGenerator.nextSalt(new String(Base64.getDecoder().decode("L1QxSVNyTU81b3NZS1djNg=="), Charset.forName("latin1")));
validator.prepareProperties(givenMariaDbUserHostingAsset);
// then
assertThat(givenMariaDbUserHostingAsset.getConfig()).containsExactlyInAnyOrderEntriesOf(ofEntries(
entry("password", "SCRAM-SHA-256$4096:L1QxSVNyTU81b3NZS1djNg==$bB4PEqHpnkoB9FwYfOjh+8yJvLsCnrwxom3TGK0CVJM=:ACRgTfhJwIZLrzhVRbJ3Qif5YhErYWAfkBThvtouW+8=")
));
}
@Test
void validatesValidEntity() {
// given
final var givenMariaDbUserHostingAsset = givenValidMariaDbUserBuilder().build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenMariaDbUserHostingAsset.getType());
// when
final var result = Stream.concat(
validator.validateEntity(givenMariaDbUserHostingAsset).stream(),
validator.validateContext(givenMariaDbUserHostingAsset).stream()
).toList();
// then
assertThat(result).isEmpty();
}
@Test
void rejectsInvalidProperties() {
// given
final var givenMariaDbUserHostingAsset = givenValidMariaDbUserBuilder()
.config(ofEntries(
entry("unknown", 100),
entry("password", "short")
))
.build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenMariaDbUserHostingAsset.getType());
// when
final var result = validator.validateEntity(givenMariaDbUserHostingAsset);
// then
assertThat(result).containsExactlyInAnyOrder(
"'PGSQL_USER:xyz00_temp.config.unknown' is not expected but is set to '100'",
"'PGSQL_USER:xyz00_temp.config.password' length is expected to be at min 8 but length of provided value is 5",
"'PGSQL_USER:xyz00_temp.config.password' must contain at least one character of at least 3 of the following groups: upper case letters, lower case letters, digits, special characters"
);
}
@Test
void rejectsInvalidIdentifier() {
// given
final var givenMariaDbUserHostingAsset = givenValidMariaDbUserBuilder()
.identifier("xyz99-temp")
.build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenMariaDbUserHostingAsset.getType());
// when
final var result = validator.validateEntity(givenMariaDbUserHostingAsset);
// then
assertThat(result).containsExactly(
"'identifier' expected to match '^xyz00$|^xyz00_[a-z0-9_]+$', but is 'xyz99-temp'");
}
}