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

Merged
hsh-michaelhoennig merged 4 commits from add-postgresql-instance-user-and-database-validation into master 2024-07-15 12:00:35 +02:00
10 changed files with 51 additions and 32 deletions
Showing only changes of commit 07f0b00510 - Show all commits

View File

@ -91,8 +91,7 @@ public enum HsHostingAssetType implements Node {
PGSQL_DATABASE( // named e.g. xyz00_abc PGSQL_DATABASE( // named e.g. xyz00_abc
inGroup("PostgreSQL"), inGroup("PostgreSQL"),
requiredParent(PGSQL_USER), // thus, the PGSQL_USER_USER:Agent becomes RBAC owner requiredParent(PGSQL_USER)), // thus, the PGSQL_USER_USER:Agent becomes RBAC owner
assignedTo(PGSQL_INSTANCE)), // keep in mind: no RBAC grants implied
hsh-michaelhoennig marked this conversation as resolved Outdated

evtl. rausnehmen, erreichbar über user

evtl. rausnehmen, erreichbar über user
MARIADB_INSTANCE( // TODO.spec: identifier to be specified MARIADB_INSTANCE( // TODO.spec: identifier to be specified
inGroup("MariaDB"), inGroup("MariaDB"),
@ -105,8 +104,7 @@ public enum HsHostingAssetType implements Node {
MARIADB_DATABASE( // named e.g. xyz00_abc MARIADB_DATABASE( // named e.g. xyz00_abc
inGroup("MariaDB"), inGroup("MariaDB"),
requiredParent(MARIADB_USER), // thus, the MARIADB_USER:Agent becomes RBAC owner requiredParent(MARIADB_USER)), // thus, the MARIADB_USER:Agent becomes RBAC owner
assignedTo(MARIADB_INSTANCE)),
IP_NUMBER( IP_NUMBER(
inGroup("Server"), inGroup("Server"),

View File

@ -20,6 +20,6 @@ class HsMariaDbDatabaseHostingAssetValidator extends HostingAssetEntityValidator
@Override @Override
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) { protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
final var webspaceIdentifier = assetEntity.getParentAsset().getParentAsset().getIdentifier(); final var webspaceIdentifier = assetEntity.getParentAsset().getParentAsset().getIdentifier();
return Pattern.compile("^"+webspaceIdentifier+"$|^"+webspaceIdentifier+"_[a-z0-9]+$"); return Pattern.compile("^"+webspaceIdentifier+"$|^"+webspaceIdentifier+"_[a-z0-9_]+$");
} }
} }

View File

@ -28,6 +28,6 @@ class HsMariaDbUserHostingAssetValidator extends HostingAssetEntityValidator {
@Override @Override
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) { protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
final var webspaceIdentifier = assetEntity.getParentAsset().getIdentifier(); final var webspaceIdentifier = assetEntity.getParentAsset().getIdentifier();
return Pattern.compile("^"+webspaceIdentifier+"$|^"+webspaceIdentifier+"_[a-z0-9]+$"); return Pattern.compile("^"+webspaceIdentifier+"$|^"+webspaceIdentifier+"_[a-z0-9_]+$");
} }
} }

View File

@ -23,6 +23,6 @@ class HsPostgreSqlDatabaseHostingAssetValidator extends HostingAssetEntityValida
@Override @Override
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) { protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
final var webspaceIdentifier = assetEntity.getParentAsset().getParentAsset().getIdentifier(); final var webspaceIdentifier = assetEntity.getParentAsset().getParentAsset().getIdentifier();
return Pattern.compile("^"+webspaceIdentifier+"$|^"+webspaceIdentifier+"_[a-z0-9]+$"); return Pattern.compile("^"+webspaceIdentifier+"$|^"+webspaceIdentifier+"_[a-z0-9_]+$");
hsh-michaelhoennig marked this conversation as resolved Outdated

underscore auch möglich

underscore auch möglich
} }
} }

View File

@ -28,6 +28,6 @@ class HsPostgreSqlUserHostingAssetValidator extends HostingAssetEntityValidator
@Override @Override
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) { protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
final var webspaceIdentifier = assetEntity.getParentAsset().getIdentifier(); final var webspaceIdentifier = assetEntity.getParentAsset().getIdentifier();
return Pattern.compile("^"+webspaceIdentifier+"$|^"+webspaceIdentifier+"_[a-z0-9]+$"); return Pattern.compile("^"+webspaceIdentifier+"$|^"+webspaceIdentifier+"_[a-z0-9_]+$");
hsh-michaelhoennig marked this conversation as resolved Outdated

underscore

underscore
} }
} }

View File

@ -132,7 +132,6 @@ class HsHostingAssetTypeUnitTest {
HA_MARIADB_USER *==> HA_MANAGED_WEBSPACE HA_MARIADB_USER *==> HA_MANAGED_WEBSPACE
HA_MARIADB_USER o..> HA_MARIADB_INSTANCE HA_MARIADB_USER o..> HA_MARIADB_INSTANCE
HA_MARIADB_DATABASE *==> HA_MARIADB_USER 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_CLOUD_SERVER
HA_IP_NUMBER o..> HA_MANAGED_SERVER HA_IP_NUMBER o..> HA_MANAGED_SERVER
HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE
@ -194,7 +193,6 @@ class HsHostingAssetTypeUnitTest {
HA_PGSQL_USER *==> HA_MANAGED_WEBSPACE HA_PGSQL_USER *==> HA_MANAGED_WEBSPACE
HA_PGSQL_USER o..> HA_PGSQL_INSTANCE HA_PGSQL_USER o..> HA_PGSQL_INSTANCE
HA_PGSQL_DATABASE *==> HA_PGSQL_USER HA_PGSQL_DATABASE *==> HA_PGSQL_USER
HA_PGSQL_DATABASE o..> HA_PGSQL_INSTANCE
HA_IP_NUMBER o..> HA_CLOUD_SERVER HA_IP_NUMBER o..> HA_CLOUD_SERVER
HA_IP_NUMBER o..> HA_MANAGED_SERVER HA_IP_NUMBER o..> HA_MANAGED_SERVER
HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE

View File

@ -40,7 +40,6 @@ class HsMariaDbDatabaseHostingAssetValidatorUnitTest {
return HsHostingAssetEntity.builder() return HsHostingAssetEntity.builder()
.type(MARIADB_DATABASE) .type(MARIADB_DATABASE)
.parentAsset(GIVEN_MARIADB_USER) .parentAsset(GIVEN_MARIADB_USER)
.assignedToAsset(GIVEN_MARIADB_INSTANCE)
.identifier("xyz00_temp") .identifier("xyz00_temp")
.caption("some valid test MariaDB-Database") .caption("some valid test MariaDB-Database")
.config(new HashMap<>(ofEntries( .config(new HashMap<>(ofEntries(
@ -112,6 +111,6 @@ class HsMariaDbDatabaseHostingAssetValidatorUnitTest {
// then // then
assertThat(result).containsExactly( 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 // then
assertThat(result).containsExactly( 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

@ -1,5 +1,7 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validators; 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;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity.HsHostingAssetEntityBuilder; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity.HsHostingAssetEntityBuilder;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -40,7 +42,6 @@ class HsPostgreSqlDatabaseHostingAssetValidatorUnitTest {
return HsHostingAssetEntity.builder() return HsHostingAssetEntity.builder()
.type(PGSQL_DATABASE) .type(PGSQL_DATABASE)
.parentAsset(GIVEN_PGSQL_USER) .parentAsset(GIVEN_PGSQL_USER)
.assignedToAsset(GIVEN_PGSQL_INSTANCE)
.identifier("xyz00_temp") .identifier("xyz00_temp")
.caption("some valid test PgSql-Database") .caption("some valid test PgSql-Database")
.config(new HashMap<>(ofEntries( .config(new HashMap<>(ofEntries(
@ -78,6 +79,26 @@ class HsPostgreSqlDatabaseHostingAssetValidatorUnitTest {
assertThat(result).isEmpty(); 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 @Test
void rejectsInvalidProperties() { void rejectsInvalidProperties() {
// given // given
@ -112,6 +133,6 @@ class HsPostgreSqlDatabaseHostingAssetValidatorUnitTest {
// then // then
assertThat(result).containsExactly( 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

@ -1,36 +1,39 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validators; 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;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity.HsHostingAssetEntityBuilder; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity.HsHostingAssetEntityBuilder;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.nio.charset.Charset;
import java.util.Base64;
import java.util.HashMap; import java.util.HashMap;
import java.util.stream.Stream; import java.util.stream.Stream;
import static java.util.Map.ofEntries; 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.PGSQL_INSTANCE;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MARIADB_USER; 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_SERVER_HOSTING_ASSET;
import static net.hostsharing.hsadminng.hs.hosting.asset.TestHsHostingAssetEntities.TEST_MANAGED_WEBSPACE_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 net.hostsharing.hsadminng.mapper.PatchMap.entry;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
class HsMariaPostgreSqlHostingAssetValidatorUnitTest { class HsPostgreSqlUserHostingAssetValidatorUnitTest {
private static final HsHostingAssetEntity GIVEN_MARIADB_INSTANCE = HsHostingAssetEntity.builder() private static final HsHostingAssetEntity GIVEN_PGSQL_INSTANCE = HsHostingAssetEntity.builder()
.type(MARIADB_INSTANCE) .type(PGSQL_INSTANCE)
.parentAsset(TEST_MANAGED_SERVER_HOSTING_ASSET) .parentAsset(TEST_MANAGED_SERVER_HOSTING_ASSET)
.identifier("vm1234|MariaDB.default") .identifier("vm1234|PgSql.default")
.caption("some valid test MariaDB-Instance") .caption("some valid test PgSql-Instance")
.build(); .build();
private static HsHostingAssetEntityBuilder givenValidMariaDbUserBuilder() { private static HsHostingAssetEntityBuilder givenValidMariaDbUserBuilder() {
return HsHostingAssetEntity.builder() return HsHostingAssetEntity.builder()
.type(MARIADB_USER) .type(PGSQL_USER)
.parentAsset(TEST_MANAGED_WEBSPACE_HOSTING_ASSET) .parentAsset(TEST_MANAGED_WEBSPACE_HOSTING_ASSET)
.assignedToAsset(GIVEN_MARIADB_INSTANCE) .assignedToAsset(GIVEN_PGSQL_INSTANCE)
.identifier("xyz00_temp") .identifier("xyz00_temp")
.caption("some valid test MariaDB-User") .caption("some valid test PgSql-User")
.config(new HashMap<>(ofEntries( .config(new HashMap<>(ofEntries(
entry("password", "Test1234") entry("password", "Test1234")
))); )));
@ -46,7 +49,7 @@ class HsMariaPostgreSqlHostingAssetValidatorUnitTest {
// then // then
assertThat(props).extracting(Object::toString).containsExactlyInAnyOrder( assertThat(props).extracting(Object::toString).containsExactlyInAnyOrder(
"{type=password, propertyName=password, minLength=8, maxLength=40, writeOnly=true, computed=true, hashedUsing=MYSQL_NATIVE, undisclosed=true}" "{type=password, propertyName=password, minLength=8, maxLength=40, writeOnly=true, computed=true, hashedUsing=SCRAM_SHA256, undisclosed=true}"
); );
} }
@ -57,12 +60,12 @@ class HsMariaPostgreSqlHostingAssetValidatorUnitTest {
final var validator = HostingAssetEntityValidatorRegistry.forType(givenMariaDbUserHostingAsset.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(givenMariaDbUserHostingAsset.getType());
// when // when
// HashGenerator.nextSalt("Ly3LbsArtL5u4EVt"); // not needed for mysql_native_password HashGenerator.nextSalt(new String(Base64.getDecoder().decode("L1QxSVNyTU81b3NZS1djNg=="), Charset.forName("latin1")));
validator.prepareProperties(givenMariaDbUserHostingAsset); validator.prepareProperties(givenMariaDbUserHostingAsset);
// then // then
assertThat(givenMariaDbUserHostingAsset.getConfig()).containsExactlyInAnyOrderEntriesOf(ofEntries( assertThat(givenMariaDbUserHostingAsset.getConfig()).containsExactlyInAnyOrderEntriesOf(ofEntries(
entry("password", "*14F1A8C42F8B6D4662BB3ED290FD37BF135FE45C") entry("password", "SCRAM-SHA-256$4096:L1QxSVNyTU81b3NZS1djNg==$bB4PEqHpnkoB9FwYfOjh+8yJvLsCnrwxom3TGK0CVJM=:ACRgTfhJwIZLrzhVRbJ3Qif5YhErYWAfkBThvtouW+8=")
)); ));
} }
@ -98,9 +101,9 @@ class HsMariaPostgreSqlHostingAssetValidatorUnitTest {
// then // then
assertThat(result).containsExactlyInAnyOrder( assertThat(result).containsExactlyInAnyOrder(
"'MARIADB_USER:xyz00_temp.config.unknown' is not expected but is set to '100'", "'PGSQL_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", "'PGSQL_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" "'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"
); );
} }
@ -117,6 +120,6 @@ class HsMariaPostgreSqlHostingAssetValidatorUnitTest {
// then // then
assertThat(result).containsExactly( 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'");
} }
} }