From 0ed7264fc1d0059e9c490b19497c5807623aa39c Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Thu, 5 Sep 2024 13:22:20 +0200 Subject: [PATCH] check hostingasset domain-setup domain name against booking item and parent asset --- .../HsDomainSetupHostingAssetValidator.java | 48 +++++++++------ ...ainSetupHostingAssetValidatorUnitTest.java | 59 ++++++++++++++++++- 2 files changed, 87 insertions(+), 20 deletions(-) diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidator.java index ea306453..c9623dd2 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidator.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidator.java @@ -2,42 +2,52 @@ package net.hostsharing.hsadminng.hs.hosting.asset.validators; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAsset; -import java.util.List; import java.util.regex.Pattern; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SETUP; +import static net.hostsharing.hsadminng.hs.hosting.asset.validators.HsDomainHttpSetupHostingAssetValidator.SUBDOMAIN_NAME_REGEX; class HsDomainSetupHostingAssetValidator extends HostingAssetEntityValidator { public static final String FQDN_REGEX = "^((?!-)[A-Za-z0-9-]{1,63}(? validateEntity(final HsHostingAsset assetEntity) { - // TODO.impl: for newly created entities, check the permission of setting up a domain - // - // allow if - // - user has Admin/Agent-role for all its sub-domains and the direct parent-Domain which are set up at at Hostsharing - // - domain has DNS zone with TXT record approval - // - parent-domain has DNS zone with TXT record approval - // - // TXT-Record check: - // new InitialDirContext().getAttributes("dns:_netblocks.google.com", new String[] { "TXT"}).get("TXT").getAll(); - - return super.validateEntity(assetEntity); - } +// @Override +// public List validateEntity(final HsHostingAsset assetEntity) { +// // TODO.impl: for newly created entities, check the permission of setting up a domain +// // +// // allow if +// // - user has Admin/Agent-role for all its sub-domains and the direct parent-Domain which are set up at at Hostsharing +// // - domain has DNS zone with TXT record approval +// // - parent-domain has DNS zone with TXT record approval +// // +// // TXT-Record check: +// // new InitialDirContext().getAttributes("dns:_netblocks.google.com", new String[] { "TXT"}).get("TXT").getAll(); +// final var violations = new ArrayList(); +// if ( assetEntity.getBookingItem() != null ) { +// final var bookingItemDomainName = assetEntity .getDirectValue(DOMAIN_NAME_PROPERTY_NAME, String.class); +// if ( bookingItemDomainName ) { +// violations.add("'" + bookingItem.toShortString() + ".resources." + DOMAIN_NAME_PROPERTY_NAME + "' = '" + domainName + "' is a forbidden Hostsharing domain name"); +// } +// } +// violations.addAll(super.validateEntity(assetEntity)); +// return violations; +// } @Override protected Pattern identifierPattern(final HsHostingAsset assetEntity) { - return identifierPattern; + if ( assetEntity.getBookingItem() != null ) { + final var bookingItemDomainName = assetEntity.getBookingItem().getDirectValue(DOMAIN_NAME_PROPERTY_NAME, String.class); + return Pattern.compile(bookingItemDomainName, Pattern.CASE_INSENSITIVE|Pattern.LITERAL); + } + final var parentDomainName = assetEntity.getParentAsset().getIdentifier(); + return Pattern.compile(SUBDOMAIN_NAME_REGEX + "\\." + parentDomainName.replace(".", "\\."), Pattern.CASE_INSENSITIVE); } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java index 6f451556..266bad45 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainSetupHostingAssetValidatorUnitTest.java @@ -7,6 +7,7 @@ import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRealEntity; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.ValueSource; import java.util.Map; @@ -18,9 +19,15 @@ import static org.assertj.core.api.Assertions.assertThat; class HsDomainSetupHostingAssetValidatorUnitTest { static HsHostingAssetRbacEntity.HsHostingAssetRbacEntityBuilder validEntityBuilder() { + final HsBookingItemRealEntity bookingItem = HsBookingItemRealEntity.builder() + .type(HsBookingItemType.DOMAIN_SETUP) + .resources(Map.ofEntries( + Map.entry("domainName", "example.org") + )) + .build(); return HsHostingAssetRbacEntity.builder() .type(DOMAIN_SETUP) - .bookingItem(HsBookingItemRealEntity.builder().type(HsBookingItemType.DOMAIN_SETUP).build()) + .bookingItem(bookingItem) .identifier("example.org"); } @@ -111,6 +118,42 @@ class HsDomainSetupHostingAssetValidatorUnitTest { "'DOMAIN_SETUP:example.org.assignedToAsset' must be null but is of type MANAGED_SERVER"); } + @Test + void rejectsDomainNameNotMatchingBookingItemDomainName() { + // given + final var domainSetupHostingAssetEntity = validEntityBuilder() + .identifier("not-matching-booking-item-domain-name.org") + .build(); + final var validator = HostingAssetEntityValidatorRegistry.forType(domainSetupHostingAssetEntity.getType()); + + // when + final var result = validator.validateEntity(domainSetupHostingAssetEntity); + + // then + assertThat(result).containsExactlyInAnyOrder( + "'identifier' expected to match 'example.org', but is 'not-matching-booking-item-domain-name.org'"); + } + + @ParameterizedTest + @ValueSource(strings = {"not-matching-booking-item-domain-name.org", "indirect.subdomain.example.org"}) + void rejectsDomainNameWhichIsNotADirectSubdomainOfParentAsset(final String newDomainName) { + // given + final var domainSetupHostingAssetEntity = validEntityBuilder() + .bookingItem(null) + .parentAsset(createValidParentDomainSetupAsset("example.org")) + .identifier(newDomainName) + .build(); + final var validator = HostingAssetEntityValidatorRegistry.forType(domainSetupHostingAssetEntity.getType()); + + // when + final var result = validator.validateEntity(domainSetupHostingAssetEntity); + + // then + assertThat(result).containsExactlyInAnyOrder( + "'identifier' expected to match '(\\*|(?!-)[A-Za-z0-9-]{1,63}(?