check-domain-setup-permission #97
@ -1,13 +1,17 @@
|
|||||||
package net.hostsharing.hsadminng.hs.booking.item.validators;
|
package net.hostsharing.hsadminng.hs.booking.item.validators;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItem;
|
||||||
import net.hostsharing.hsadminng.mapper.Array;
|
import net.hostsharing.hsadminng.mapper.Array;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringProperty;
|
import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringProperty;
|
||||||
|
|
||||||
class HsDomainSetupBookingItemValidator extends HsBookingItemEntityValidator {
|
class HsDomainSetupBookingItemValidator extends HsBookingItemEntityValidator {
|
||||||
|
|
||||||
public static final String FQDN_REGEX = "^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,12}";
|
public static final String FQDN_REGEX = "^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,12}";
|
||||||
public static final String[] REGISRTAR_LEVEL_DOMAINS = Array.of(
|
public static final String[] REGISTRAR_LEVEL_DOMAINS = Array.of(
|
||||||
// "[^.]+", // top-level-domains are already rejected by FQDN_REGEX
|
// "[^.]+", // top-level-domains are already rejected by FQDN_REGEX
|
||||||
"(co|org|gov|ac|sch)\\.uk",
|
"(co|org|gov|ac|sch)\\.uk",
|
||||||
"(com|net|org|edu|gov|asn|id)\\.au",
|
"(com|net|org|edu|gov|asn|id)\\.au",
|
||||||
@ -20,14 +24,26 @@ class HsDomainSetupBookingItemValidator extends HsBookingItemEntityValidator {
|
|||||||
"(co|net|org|govt|ac|school|geek|kiwi)\\.nz",
|
"(co|net|org|govt|ac|school|geek|kiwi)\\.nz",
|
||||||
"(co|ne|or|go|re|pe)\\.kr"
|
"(co|ne|or|go|re|pe)\\.kr"
|
||||||
);
|
);
|
||||||
// hostsharing.com|net|org|coop, // just to be on the safe side
|
public static final String DOMAIN_NAME_PROPERTY_NAME = "domainName";
|
||||||
|
|
||||||
HsDomainSetupBookingItemValidator() {
|
HsDomainSetupBookingItemValidator() {
|
||||||
super(
|
super(
|
||||||
stringProperty("domainName").writeOnce()
|
stringProperty(DOMAIN_NAME_PROPERTY_NAME).writeOnce()
|
||||||
.matchesRegEx(FQDN_REGEX).describedAs("is not a (non-top-level) fully qualified domain name")
|
.matchesRegEx(FQDN_REGEX).describedAs("is not a (non-top-level) fully qualified domain name")
|
||||||
.notMatchesRegEx(REGISRTAR_LEVEL_DOMAINS).describedAs("is a forbidden registrar-level domain name")
|
.notMatchesRegEx(REGISTRAR_LEVEL_DOMAINS).describedAs("is a forbidden registrar-level domain name")
|
||||||
.required()
|
.required()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> validateEntity(final HsBookingItem bookingItem) {
|
||||||
|
final var violations = new ArrayList<String>();
|
||||||
|
final var domainName = bookingItem.getDirectValue(DOMAIN_NAME_PROPERTY_NAME, String.class);
|
||||||
|
if ( !bookingItem.isLoaded() &&
|
||||||
|
domainName.matches("hostsharing.(com|net|org|coop)") ) {
|
||||||
|
violations.add("'" + bookingItem.toShortString() + ".resources." + DOMAIN_NAME_PROPERTY_NAME + "' = '" + domainName + "' is a forbidden Hostsharing domain name");
|
||||||
|
}
|
||||||
|
violations.addAll(super.validateEntity(bookingItem));
|
||||||
|
return violations;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,20 +25,6 @@ class HsDomainSetupHostingAssetValidator extends HostingAssetEntityValidator {
|
|||||||
public List<String> validateEntity(final HsHostingAsset assetEntity) {
|
public List<String> validateEntity(final HsHostingAsset assetEntity) {
|
||||||
// TODO.impl: for newly created entities, check the permission of setting up a domain
|
// TODO.impl: for newly created entities, check the permission of setting up a domain
|
||||||
//
|
//
|
||||||
// reject, if the domain is any of these:
|
|
||||||
// hostsharing.com|net|org|coop, // just to be on the safe side
|
|
||||||
// [^.}+, // top-level-domain
|
|
||||||
// co.uk, org.uk, gov.uk, ac.uk, sch.uk,
|
|
||||||
// com.au, net.au, org.au, edu.au, gov.au, asn.au, id.au,
|
|
||||||
// co.jp, ne.jp, or.jp, ac.jp, go.jp,
|
|
||||||
// com.cn, net.cn, org.cn, gov.cn, edu.cn, ac.cn,
|
|
||||||
// com.br, net.br, org.br, gov.br, edu.br, mil.br, art.br,
|
|
||||||
// co.in, net.in, org.in, gen.in, firm.in, ind.in,
|
|
||||||
// com.mx, net.mx, org.mx, gob.mx, edu.mx,
|
|
||||||
// gov.it, edu.it,
|
|
||||||
// co.nz, net.nz, org.nz, govt.nz, ac.nz, school.nz, geek.nz, kiwi.nz,
|
|
||||||
// co.kr, ne.kr, or.kr, go.kr, re.kr, pe.kr
|
|
||||||
//
|
|
||||||
// allow if
|
// allow if
|
||||||
// - user has Admin/Agent-role for all its sub-domains and the direct parent-Domain which are set up at at Hostsharing
|
// - 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
|
// - domain has DNS zone with TXT record approval
|
||||||
|
@ -11,7 +11,6 @@ import jakarta.persistence.EntityManager;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static java.util.Map.entry;
|
import static java.util.Map.entry;
|
||||||
import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.CLOUD_SERVER;
|
|
||||||
import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.DOMAIN_SETUP;
|
import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.DOMAIN_SETUP;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@ -29,7 +28,7 @@ class HsDomainSetupBookingItemValidatorUnitTest {
|
|||||||
@Test
|
@Test
|
||||||
void acceptsUnregisteredDomain() {
|
void acceptsUnregisteredDomain() {
|
||||||
// given
|
// given
|
||||||
final var cloudServerBookingItemEntity = HsBookingItemRealEntity.builder()
|
final var domainSetupBookingItemEntity = HsBookingItemRealEntity.builder()
|
||||||
.type(DOMAIN_SETUP)
|
.type(DOMAIN_SETUP)
|
||||||
.project(project)
|
.project(project)
|
||||||
.caption("Test-Domain")
|
.caption("Test-Domain")
|
||||||
@ -39,7 +38,7 @@ class HsDomainSetupBookingItemValidatorUnitTest {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = HsBookingItemEntityValidatorRegistry.doValidate(em, cloudServerBookingItemEntity);
|
final var result = HsBookingItemEntityValidatorRegistry.doValidate(em, domainSetupBookingItemEntity);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result).isEmpty();
|
assertThat(result).isEmpty();
|
||||||
@ -48,7 +47,7 @@ class HsDomainSetupBookingItemValidatorUnitTest {
|
|||||||
@Test
|
@Test
|
||||||
void rejectsTopLevelDomain() {
|
void rejectsTopLevelDomain() {
|
||||||
// given
|
// given
|
||||||
final var cloudServerBookingItemEntity = HsBookingItemRealEntity.builder()
|
final var domainSetupBookingItemEntity = HsBookingItemRealEntity.builder()
|
||||||
.type(DOMAIN_SETUP)
|
.type(DOMAIN_SETUP)
|
||||||
.project(project)
|
.project(project)
|
||||||
.caption("Test-Domain")
|
.caption("Test-Domain")
|
||||||
@ -58,7 +57,7 @@ class HsDomainSetupBookingItemValidatorUnitTest {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = HsBookingItemEntityValidatorRegistry.doValidate(em, cloudServerBookingItemEntity);
|
final var result = HsBookingItemEntityValidatorRegistry.doValidate(em, domainSetupBookingItemEntity);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result).containsExactly("'D-12345:Test-Project:Test-Domain.resources.domainName' = 'org' is not a (non-top-level) fully qualified domain name");
|
assertThat(result).containsExactly("'D-12345:Test-Project:Test-Domain.resources.domainName' = 'org' is not a (non-top-level) fully qualified domain name");
|
||||||
@ -79,7 +78,7 @@ class HsDomainSetupBookingItemValidatorUnitTest {
|
|||||||
})
|
})
|
||||||
void reject2ndLevelRegistrarDomain(final String secondLevelRegistrarDomain) {
|
void reject2ndLevelRegistrarDomain(final String secondLevelRegistrarDomain) {
|
||||||
// given
|
// given
|
||||||
final var cloudServerBookingItemEntity = HsBookingItemRealEntity.builder()
|
final var domainSetupBookingItemEntity = HsBookingItemRealEntity.builder()
|
||||||
.type(DOMAIN_SETUP)
|
.type(DOMAIN_SETUP)
|
||||||
.project(project)
|
.project(project)
|
||||||
.caption("Test-Domain")
|
.caption("Test-Domain")
|
||||||
@ -89,7 +88,7 @@ class HsDomainSetupBookingItemValidatorUnitTest {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = HsBookingItemEntityValidatorRegistry.doValidate(em, cloudServerBookingItemEntity);
|
final var result = HsBookingItemEntityValidatorRegistry.doValidate(em, domainSetupBookingItemEntity);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result).containsExactly(
|
assertThat(result).containsExactly(
|
||||||
@ -98,6 +97,31 @@ class HsDomainSetupBookingItemValidatorUnitTest {
|
|||||||
"' is a forbidden registrar-level domain name");
|
"' is a forbidden registrar-level domain name");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(strings = {
|
||||||
|
"hostsharing.net", "hostsharing.org", "hostsharing.com", "hostsharing.coop"
|
||||||
|
})
|
||||||
|
void rejectHostsharingDomain(final String secondLevelRegistrarDomain) {
|
||||||
|
// given
|
||||||
|
final var domainSetupBookingItemEntity = HsBookingItemRealEntity.builder()
|
||||||
|
.type(DOMAIN_SETUP)
|
||||||
|
.project(project)
|
||||||
|
.caption("Test-Domain")
|
||||||
|
.resources(Map.ofEntries(
|
||||||
|
entry("domainName", secondLevelRegistrarDomain)
|
||||||
|
))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// when
|
||||||
|
final var result = HsBookingItemEntityValidatorRegistry.doValidate(em, domainSetupBookingItemEntity);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(result).containsExactly(
|
||||||
|
"'D-12345:Test-Project:Test-Domain.resources.domainName' = '" +
|
||||||
|
secondLevelRegistrarDomain +
|
||||||
|
"' is a forbidden Hostsharing domain name");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void containsAllValidations() {
|
void containsAllValidations() {
|
||||||
// when
|
// when
|
||||||
|
@ -256,6 +256,8 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
.project(givenProject)
|
.project(givenProject)
|
||||||
.type(HsBookingItemType.DOMAIN_SETUP)
|
.type(HsBookingItemType.DOMAIN_SETUP)
|
||||||
.caption("some temp domain setup booking item")
|
.caption("some temp domain setup booking item")
|
||||||
|
.resources(Map.ofEntries(
|
||||||
|
entry("domainName", "example.org")))
|
||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user