add-mariadb-instance-database-and-user-validations (#75)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/75 Reviewed-by: Timotheus Pokorra <timotheus.pokorra@hostsharing.net>
This commit is contained in:
@@ -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");
|
||||
}
|
||||
}
|
@@ -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");
|
||||
}
|
||||
}
|
@@ -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()
|
||||
|
@@ -30,6 +30,7 @@ import java.util.Map;
|
||||
import static java.util.Map.entry;
|
||||
import static net.hostsharing.hsadminng.hs.booking.item.TestHsBookingItem.TEST_CLOUD_SERVER_BOOKING_ITEM;
|
||||
import static net.hostsharing.hsadminng.hs.booking.item.TestHsBookingItem.TEST_MANAGED_SERVER_BOOKING_ITEM;
|
||||
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.hs.office.contact.TestHsOfficeContact.TEST_CONTACT;
|
||||
import static net.hostsharing.hsadminng.rbac.test.JsonMatcher.lenientlyEquals;
|
||||
@@ -363,6 +364,68 @@ public class HsHostingAssetControllerRestTest {
|
||||
}
|
||||
}
|
||||
]
|
||||
"""),
|
||||
MARIADB_INSTANCE(
|
||||
List.of(
|
||||
HsHostingAssetEntity.builder()
|
||||
.type(HsHostingAssetType.MARIADB_INSTANCE)
|
||||
.parentAsset(TEST_MANAGED_SERVER_HOSTING_ASSET)
|
||||
.identifier("vm1234|MariaDB.default")
|
||||
.caption("some fake MariaDB instance")
|
||||
.build()),
|
||||
"""
|
||||
[
|
||||
{
|
||||
"type": "MARIADB_INSTANCE",
|
||||
"identifier": "vm1234|MariaDB.default",
|
||||
"caption": "some fake MariaDB instance",
|
||||
"alarmContact": null,
|
||||
"config": {}
|
||||
}
|
||||
]
|
||||
"""),
|
||||
MARIADB_USER(
|
||||
List.of(
|
||||
HsHostingAssetEntity.builder()
|
||||
.type(HsHostingAssetType.MARIADB_USER)
|
||||
.identifier("xyz00_temp")
|
||||
.caption("some fake MariaDB user")
|
||||
.build()),
|
||||
"""
|
||||
[
|
||||
{
|
||||
"type": "MARIADB_USER",
|
||||
"identifier": "xyz00_temp",
|
||||
"caption": "some fake MariaDB user",
|
||||
"alarmContact": null,
|
||||
"config": {}
|
||||
}
|
||||
]
|
||||
"""),
|
||||
MARIADB_DATABASE(
|
||||
List.of(
|
||||
HsHostingAssetEntity.builder()
|
||||
.type(HsHostingAssetType.MARIADB_DATABASE)
|
||||
.identifier("xyz00_temp")
|
||||
.caption("some fake MariaDB database")
|
||||
.config(Map.ofEntries(
|
||||
entry("encoding", "latin1"),
|
||||
entry("collation", "latin2")
|
||||
))
|
||||
.build()),
|
||||
"""
|
||||
[
|
||||
{
|
||||
"type": "MARIADB_DATABASE",
|
||||
"identifier": "xyz00_temp",
|
||||
"caption": "some fake MariaDB database",
|
||||
"alarmContact": null,
|
||||
"config": {
|
||||
"encoding": "latin1",
|
||||
"collation": "latin2"
|
||||
}
|
||||
}
|
||||
]
|
||||
""");
|
||||
|
||||
final HsHostingAssetType assetType;
|
||||
|
@@ -41,7 +41,10 @@ class HsHostingAssetPropsControllerAcceptanceTest {
|
||||
"DOMAIN_HTTP_SETUP",
|
||||
"DOMAIN_SMTP_SETUP",
|
||||
"DOMAIN_MBOX_SETUP",
|
||||
"EMAIL_ADDRESS"
|
||||
"EMAIL_ADDRESS",
|
||||
"MARIADB_INSTANCE",
|
||||
"MARIADB_USER",
|
||||
"MARIADB_DATABASE"
|
||||
]
|
||||
"""));
|
||||
// @formatter:on
|
||||
|
@@ -245,7 +245,8 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu
|
||||
// then
|
||||
exactlyTheseAssetsAreReturned(
|
||||
result,
|
||||
"HsHostingAssetEntity(MANAGED_WEBSPACE, sec01, some Webspace, MANAGED_SERVER:vm1012, D-1000212:D-1000212 default project:separate ManagedWebspace)");
|
||||
"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)");
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -36,13 +36,13 @@ class HsHostingAssetTypeUnitTest {
|
||||
entity HA_DOMAIN_MBOX_SETUP
|
||||
entity HA_EMAIL_ADDRESS
|
||||
}
|
||||
|
||||
|
||||
package Server #99bcdb {
|
||||
entity HA_CLOUD_SERVER
|
||||
entity HA_MANAGED_SERVER
|
||||
entity HA_IP_NUMBER
|
||||
}
|
||||
|
||||
|
||||
package Webspace #99bcdb {
|
||||
entity HA_MANAGED_WEBSPACE
|
||||
entity HA_UNIX_USER
|
||||
@@ -129,9 +129,9 @@ class HsHostingAssetTypeUnitTest {
|
||||
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
|
||||
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
|
||||
HA_MARIADB_INSTANCE *==> HA_MANAGED_SERVER
|
||||
HA_MARIADB_USER *==> HA_MARIADB_INSTANCE
|
||||
HA_MARIADB_USER o..> HA_MANAGED_WEBSPACE
|
||||
HA_MARIADB_DATABASE *==> HA_MANAGED_WEBSPACE
|
||||
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
|
||||
@@ -145,7 +145,7 @@ class HsHostingAssetTypeUnitTest {
|
||||
}
|
||||
Booking -down[hidden]->Legend
|
||||
```
|
||||
|
||||
|
||||
### PostgreSQL
|
||||
|
||||
```plantuml
|
||||
|
@@ -39,7 +39,10 @@ class HostingAssetEntityValidatorRegistryUnitTest {
|
||||
HsHostingAssetType.DOMAIN_HTTP_SETUP,
|
||||
HsHostingAssetType.DOMAIN_SMTP_SETUP,
|
||||
HsHostingAssetType.DOMAIN_MBOX_SETUP,
|
||||
HsHostingAssetType.EMAIL_ADDRESS
|
||||
HsHostingAssetType.EMAIL_ADDRESS,
|
||||
HsHostingAssetType.MARIADB_INSTANCE,
|
||||
HsHostingAssetType.MARIADB_USER,
|
||||
HsHostingAssetType.MARIADB_DATABASE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,117 @@
|
||||
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
|
||||
|
||||
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.MARIADB_DATABASE;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MARIADB_INSTANCE;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MARIADB_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 HsMariaDbDatabaseHostingAssetValidatorUnitTest {
|
||||
|
||||
private static final HsHostingAssetEntity GIVEN_MARIADB_INSTANCE = HsHostingAssetEntity.builder()
|
||||
.type(MARIADB_INSTANCE)
|
||||
.parentAsset(TEST_MANAGED_SERVER_HOSTING_ASSET)
|
||||
.identifier("vm1234|MariaDB.default")
|
||||
.caption("some valid test MariaDB-Instance")
|
||||
.build();
|
||||
|
||||
private static final HsHostingAssetEntity GIVEN_MARIADB_USER = HsHostingAssetEntity.builder()
|
||||
.type(MARIADB_USER)
|
||||
.parentAsset(TEST_MANAGED_WEBSPACE_HOSTING_ASSET)
|
||||
.assignedToAsset(GIVEN_MARIADB_INSTANCE)
|
||||
.identifier("xyz00_temp")
|
||||
.caption("some valid test MariaDB-User")
|
||||
.config(new HashMap<>(ofEntries(
|
||||
entry("password", "Hallo Datenbank, lass mich rein!")
|
||||
)))
|
||||
.build();
|
||||
|
||||
private static HsHostingAssetEntityBuilder givenValidMariaDbDatabaseBuilder() {
|
||||
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(
|
||||
entry("encoding", "latin1")
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void describesItsProperties() {
|
||||
// given
|
||||
final var validator = HostingAssetEntityValidatorRegistry.forType(givenValidMariaDbDatabaseBuilder().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 givenMariaDbUserHostingAsset = givenValidMariaDbDatabaseBuilder().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 = givenValidMariaDbDatabaseBuilder()
|
||||
.config(ofEntries(
|
||||
entry("unknown", "wrong"),
|
||||
entry("encoding", 10)
|
||||
))
|
||||
.build();
|
||||
final var validator = HostingAssetEntityValidatorRegistry.forType(givenMariaDbUserHostingAsset.getType());
|
||||
|
||||
// when
|
||||
final var result = validator.validateEntity(givenMariaDbUserHostingAsset);
|
||||
|
||||
// then
|
||||
assertThat(result).containsExactlyInAnyOrder(
|
||||
"'MARIADB_DATABASE:xyz00_temp.config.unknown' is not expected but is set to 'wrong'",
|
||||
"'MARIADB_DATABASE:xyz00_temp.config.encoding' is expected to be of type String, but is of type Integer"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsInvalidIdentifier() {
|
||||
// given
|
||||
final var givenMariaDbUserHostingAsset = givenValidMariaDbDatabaseBuilder()
|
||||
.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'");
|
||||
}
|
||||
}
|
@@ -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 HsMariaDbInstanceHostingAssetValidatorUnitTest {
|
||||
|
||||
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'");
|
||||
}
|
||||
}
|
@@ -0,0 +1,122 @@
|
||||
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
|
||||
|
||||
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.MARIADB_INSTANCE;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MARIADB_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 HsMariaDbUserHostingAssetValidatorUnitTest {
|
||||
|
||||
private static final HsHostingAssetEntity GIVEN_MARIADB_INSTANCE = HsHostingAssetEntity.builder()
|
||||
.type(MARIADB_INSTANCE)
|
||||
.parentAsset(TEST_MANAGED_SERVER_HOSTING_ASSET)
|
||||
.identifier("vm1234|MariaDB.default")
|
||||
.caption("some valid test MariaDB-Instance")
|
||||
.build();
|
||||
|
||||
private static HsHostingAssetEntityBuilder givenValidMariaDbUserBuilder() {
|
||||
return HsHostingAssetEntity.builder()
|
||||
.type(MARIADB_USER)
|
||||
.parentAsset(TEST_MANAGED_WEBSPACE_HOSTING_ASSET)
|
||||
.assignedToAsset(GIVEN_MARIADB_INSTANCE)
|
||||
.identifier("xyz00_temp")
|
||||
.caption("some valid test MariaDB-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=MYSQL_NATIVE, undisclosed=true}"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void preparesEntity() {
|
||||
// given
|
||||
final var givenMariaDbUserHostingAsset = givenValidMariaDbUserBuilder().build();
|
||||
final var validator = HostingAssetEntityValidatorRegistry.forType(givenMariaDbUserHostingAsset.getType());
|
||||
|
||||
// when
|
||||
// HashGenerator.nextSalt("Ly3LbsArtL5u4EVt"); // not needed for mysql_native_password
|
||||
validator.prepareProperties(givenMariaDbUserHostingAsset);
|
||||
|
||||
// then
|
||||
assertThat(givenMariaDbUserHostingAsset.getConfig()).containsExactlyInAnyOrderEntriesOf(ofEntries(
|
||||
entry("password", "*14F1A8C42F8B6D4662BB3ED290FD37BF135FE45C")
|
||||
));
|
||||
}
|
||||
|
||||
@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(
|
||||
"'MARIADB_USER:xyz00_temp.config.unknown' is not expected but is set to '100'",
|
||||
"'MARIADB_USER:xyz00_temp.config.password' length is expected to be at min 8 but length of provided value is 5",
|
||||
"'MARIADB_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'");
|
||||
}
|
||||
}
|
@@ -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
|
||||
@@ -169,7 +169,7 @@ class HsUnixUserHostingAssetValidatorUnitTest {
|
||||
"{type=enumeration, propertyName=shell, values=[/bin/false, /bin/bash, /bin/csh, /bin/dash, /usr/bin/tcsh, /usr/bin/zsh, /usr/bin/passwd], defaultValue=/bin/false}",
|
||||
"{type=string, propertyName=homedir, readOnly=true, computed=true}",
|
||||
"{type=string, propertyName=totpKey, matchesRegEx=[^0x([0-9A-Fa-f]{2})+$], minLength=20, maxLength=256, writeOnly=true, undisclosed=true}",
|
||||
"{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=LINUX_SHA512, undisclosed=true}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -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<PasswordProperty, String> passwordProp =
|
||||
passwordProperty("password").minLength(8).maxLength(40).hashedUsing(SHA512).writeOnly();
|
||||
passwordProperty("password").minLength(8).maxLength(40).hashedUsing(LINUX_SHA512).writeOnly();
|
||||
private final List<String> 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
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user