add-mariadb-instance-database-and-user-validations #75
@ -27,6 +27,7 @@ public class HostingAssetEntityValidatorRegistry {
|
|||||||
register(DOMAIN_MBOX_SETUP, new HsDomainMboxSetupHostingAssetValidator());
|
register(DOMAIN_MBOX_SETUP, new HsDomainMboxSetupHostingAssetValidator());
|
||||||
register(EMAIL_ADDRESS, new HsEMailAddressHostingAssetValidator());
|
register(EMAIL_ADDRESS, new HsEMailAddressHostingAssetValidator());
|
||||||
register(MARIADB_INSTANCE, new HsMariaDbInstanceHostingAssetValidator());
|
register(MARIADB_INSTANCE, new HsMariaDbInstanceHostingAssetValidator());
|
||||||
|
register(MARIADB_USER, new HsMariaDbUserHostingAssetValidator());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void register(final Enum<HsHostingAssetType> type, final HsEntityValidator<HsHostingAssetEntity> validator) {
|
private static void register(final Enum<HsHostingAssetType> type, final HsEntityValidator<HsHostingAssetEntity> validator) {
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.hash.LinuxEtcShadowHashGenerator;
|
||||||
|
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MARIADB_USER;
|
||||||
|
import static net.hostsharing.hsadminng.hs.validation.PasswordProperty.passwordProperty;
|
||||||
|
|
||||||
|
class HsMariaDbUserHostingAssetValidator extends HostingAssetEntityValidator {
|
||||||
|
|
||||||
|
public HsMariaDbUserHostingAssetValidator() {
|
||||||
|
super(
|
||||||
|
MARIADB_USER,
|
||||||
|
AlarmContact.isOptional(),
|
||||||
|
|
||||||
|
// TODO.impl: we need to be able to suppress updating of fields etc., something like this:
|
||||||
|
// withFieldValidation(
|
||||||
|
// referenceProperty(alarmContact).isOptional(),
|
||||||
|
// referenceProperty(parentAsset).isWriteOnce(),
|
||||||
|
// referenceProperty(assignedToAsset).isWriteOnce(),
|
||||||
|
// );
|
||||||
|
|
||||||
|
passwordProperty("password").minLength(8).maxLength(40).hashedUsing(LinuxEtcShadowHashGenerator.Algorithm.SHA512).writeOnly());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
|
||||||
|
final var webspaceIdentifier = assetEntity.getAssignedToAsset().getIdentifier();
|
||||||
|
return Pattern.compile("^"+webspaceIdentifier+"$|^"+webspaceIdentifier+"_[a-z0-9]+$");
|
||||||
|
}
|
||||||
|
}
|
@ -76,8 +76,8 @@ begin
|
|||||||
when 'PGSQL_USER' then 'MANAGED_WEBSPACE'
|
when 'PGSQL_USER' then 'MANAGED_WEBSPACE'
|
||||||
when 'PGSQL_DATABASE' then 'MANAGED_WEBSPACE'
|
when 'PGSQL_DATABASE' then 'MANAGED_WEBSPACE'
|
||||||
when 'MARIADB_INSTANCE' then 'MANAGED_SERVER'
|
when 'MARIADB_INSTANCE' then 'MANAGED_SERVER'
|
||||||
when 'MARIADB_USER' then 'MANAGED_WEBSPACE'
|
when 'MARIADB_USER' then 'MARIADB_INSTANCE'
|
||||||
when 'MARIADB_DATABASE' then 'MANAGED_WEBSPACE'
|
when 'MARIADB_DATABASE' then 'MARIADB_INSTANCE'
|
||||||
else raiseException(format('[400] unknown asset type %s', NEW.type::text))
|
else raiseException(format('[400] unknown asset type %s', NEW.type::text))
|
||||||
end);
|
end);
|
||||||
|
|
||||||
|
@ -80,6 +80,7 @@ begin
|
|||||||
(managedServerUuid, managedServerBI.uuid, 'MANAGED_SERVER', null, null, 'vm10' || debitorNumberSuffix, 'some ManagedServer', '{ "monit_max_cpu_usage": 90, "monit_max_ram_usage": 80, "monit_max_ssd_usage": 70 }'::jsonb),
|
(managedServerUuid, managedServerBI.uuid, 'MANAGED_SERVER', null, null, 'vm10' || debitorNumberSuffix, 'some ManagedServer', '{ "monit_max_cpu_usage": 90, "monit_max_ram_usage": 80, "monit_max_ssd_usage": 70 }'::jsonb),
|
||||||
(uuid_generate_v4(), cloudServerBI.uuid, 'CLOUD_SERVER', null, null, 'vm20' || debitorNumberSuffix, 'another CloudServer', '{}'::jsonb),
|
(uuid_generate_v4(), cloudServerBI.uuid, 'CLOUD_SERVER', null, null, 'vm20' || debitorNumberSuffix, 'another CloudServer', '{}'::jsonb),
|
||||||
(mariaDbInstanceUuid, null, 'MARIADB_INSTANCE', managedServerUuid, null, 'vm10' || debitorNumberSuffix || '.MariaDB.default', 'some default MariaDB instance','{}'::jsonb),
|
(mariaDbInstanceUuid, null, 'MARIADB_INSTANCE', managedServerUuid, null, 'vm10' || debitorNumberSuffix || '.MariaDB.default', 'some default MariaDB instance','{}'::jsonb),
|
||||||
|
(uuid_generate_v4(), null, 'MARIADB_USER', mariaDbInstanceUuid, null, defaultPrefix || '01_web', 'some default MariaDB user', '{ "password": "<TODO:replace-by-encrypted-mariadb-password"}'::jsonb ),
|
||||||
(managedWebspaceUuid, managedWebspaceBI.uuid, 'MANAGED_WEBSPACE', managedServerUuid, null, defaultPrefix || '01', 'some Webspace', '{}'::jsonb),
|
(managedWebspaceUuid, managedWebspaceBI.uuid, 'MANAGED_WEBSPACE', managedServerUuid, null, defaultPrefix || '01', 'some Webspace', '{}'::jsonb),
|
||||||
(uuid_generate_v4(), null, 'EMAIL_ALIAS', managedWebspaceUuid, null, defaultPrefix || '01-web', 'some E-Mail-Alias', '{ "target": [ "office@example.org", "archive@example.com" ] }'::jsonb),
|
(uuid_generate_v4(), null, 'EMAIL_ALIAS', managedWebspaceUuid, null, defaultPrefix || '01-web', 'some E-Mail-Alias', '{ "target": [ "office@example.org", "archive@example.com" ] }'::jsonb),
|
||||||
(webUnixUserUuid, null, 'UNIX_USER', managedWebspaceUuid, null, defaultPrefix || '01-web', 'some UnixUser for Website', '{ "SSD-soft-quota": "128", "SSD-hard-quota": "256", "HDD-soft-quota": "512", "HDD-hard-quota": "1024"}'::jsonb),
|
(webUnixUserUuid, null, 'UNIX_USER', managedWebspaceUuid, null, defaultPrefix || '01-web', 'some UnixUser for Website', '{ "SSD-soft-quota": "128", "SSD-hard-quota": "256", "HDD-soft-quota": "512", "HDD-hard-quota": "1024"}'::jsonb),
|
||||||
|
@ -383,6 +383,24 @@ public class HsHostingAssetControllerRestTest {
|
|||||||
"config": {}
|
"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": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
""");
|
""");
|
||||||
|
|
||||||
final HsHostingAssetType assetType;
|
final HsHostingAssetType assetType;
|
||||||
|
@ -42,7 +42,8 @@ class HsHostingAssetPropsControllerAcceptanceTest {
|
|||||||
"DOMAIN_SMTP_SETUP",
|
"DOMAIN_SMTP_SETUP",
|
||||||
"DOMAIN_MBOX_SETUP",
|
"DOMAIN_MBOX_SETUP",
|
||||||
"EMAIL_ADDRESS",
|
"EMAIL_ADDRESS",
|
||||||
"MARIADB_INSTANCE"
|
"MARIADB_INSTANCE",
|
||||||
|
"MARIADB_USER"
|
||||||
]
|
]
|
||||||
"""));
|
"""));
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
@ -40,7 +40,8 @@ class HostingAssetEntityValidatorRegistryUnitTest {
|
|||||||
HsHostingAssetType.DOMAIN_SMTP_SETUP,
|
HsHostingAssetType.DOMAIN_SMTP_SETUP,
|
||||||
HsHostingAssetType.DOMAIN_MBOX_SETUP,
|
HsHostingAssetType.DOMAIN_MBOX_SETUP,
|
||||||
HsHostingAssetType.EMAIL_ADDRESS,
|
HsHostingAssetType.EMAIL_ADDRESS,
|
||||||
HsHostingAssetType.MARIADB_INSTANCE
|
HsHostingAssetType.MARIADB_INSTANCE,
|
||||||
|
HsHostingAssetType.MARIADB_USER
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,123 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
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(GIVEN_MARIADB_INSTANCE)
|
||||||
|
.assignedToAsset(TEST_MANAGED_WEBSPACE_HOSTING_ASSET)
|
||||||
|
.identifier("xyz00_temp")
|
||||||
|
.caption("some valid test MariaDB-User")
|
||||||
|
.config(new HashMap<>(ofEntries(
|
||||||
|
entry("password", "Hallo Datenbank, lass mich rein!")
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@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=SHA512, undisclosed=true}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void preparesEntity() {
|
||||||
|
// given
|
||||||
|
final var givenMariaDbUserHostingAsset = givenValidMariaDbUserBuilder().build();
|
||||||
|
final var validator = HostingAssetEntityValidatorRegistry.forType(givenMariaDbUserHostingAsset.getType());
|
||||||
|
|
||||||
|
// when
|
||||||
|
LinuxEtcShadowHashGenerator.nextSalt("Ly3LbsArtL5u4EVt"); // FIXME
|
||||||
|
validator.prepareProperties(givenMariaDbUserHostingAsset);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(givenMariaDbUserHostingAsset.getConfig()).containsExactlyInAnyOrderEntriesOf(ofEntries(
|
||||||
|
entry("password", "$6$Ly3LbsArtL5u4EVt$T7VM5uCq7I1cKttipCX4TQdyawdpLcSmjApreI4fZcORPOkEkxy9iz.9Dri6IVbO08OKTR8OE8hvnblU5Ax6o.")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@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'");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user