allowSetupOfNonExistingSubdomainOfRegistrarLevelDomain

This commit is contained in:
Michael Hoennig 2024-09-06 13:08:02 +02:00
parent bab85c5581
commit 8316a88bce
4 changed files with 50 additions and 23 deletions

View File

@ -9,17 +9,23 @@ import javax.naming.NamingException;
import javax.naming.ServiceUnavailableException;
import javax.naming.directory.Attribute;
import javax.naming.directory.InitialDirContext;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import static java.util.Collections.emptyList;
public class Dns {
private static Result nextFakeResult = null;
private final static Map<String, Result> fakeResults = new HashMap<>();
public static void fakeNextResult(final Result fakeResult) {
nextFakeResult = fakeResult;
public static void fakeResultForDomain(final String domainName, final Result fakeResult) {
fakeResults.put(domainName, fakeResult);
}
static void resetFakeResults() {
fakeResults.clear();
}
public enum Status {
@ -56,12 +62,8 @@ public class Dns {
}
public Result fetchRecordsOfType(final String recordType) {
if (nextFakeResult != null) {
try {
return nextFakeResult;
} finally {
nextFakeResult = null;
}
if (fakeResults.containsKey(domainName)) {
return fakeResults.get(domainName);
}
try {

View File

@ -60,12 +60,12 @@ class HsDomainSetupHostingAssetValidator extends HostingAssetEntityValidator {
break;
case Dns.Status.INVALID_NAME:
violations.add("Invalid domain name " + assetEntity.getIdentifier());
violations.add("[DNS] invalid domain name '" + assetEntity.getIdentifier() + "'");
break;
case Dns.Status.SERVICE_UNAVAILABLE:
case Dns.Status.UNKNOWN_FAILURE:
violations.add("DNS request for " + assetEntity.getIdentifier() + " failed: " + result.exception());
violations.add("[DNS] lookup failed for domain name '" + assetEntity.getIdentifier() + "': " + result.exception());
break;
}

View File

@ -250,7 +250,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
void globalAdmin_canAddTopLevelAsset() {
context.define("superuser-alex@hostsharing.net");
Dns.fakeNextResult(new Dns.Result(Dns.Status.NAME_NOT_FOUND, null, null));
Dns.fakeResultForDomain("example.com", new Dns.Result(Dns.Status.NAME_NOT_FOUND, null, null));
final var givenProject = realProjectRepo.findByCaption("D-1000111 default project").stream()
.findAny().orElseThrow();
final var bookingItem = givenSomeTemporaryBookingItem(() ->

View File

@ -4,6 +4,7 @@ import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealEntity;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRbacEntity;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRealEntity;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
@ -39,6 +40,11 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
return validEntityBuilder("example.org");
}
@AfterEach
void cleanup() {
Dns.resetFakeResults();
}
enum InvalidDomainNameIdentifier {
EMPTY(""),
TOO_LONG("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456890123456789.de"),
@ -57,7 +63,6 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
@EnumSource(InvalidDomainNameIdentifier.class)
void rejectsInvalidIdentifier(final InvalidDomainNameIdentifier testCase) {
// given
Dns.fakeNextResult(new Dns.Result(Dns.Status.NAME_NOT_FOUND, null, null));
final var givenEntity = validEntityBuilder().identifier(testCase.domainName).build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
@ -65,12 +70,11 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
final var result = validator.validateEntity(givenEntity);
// then
assertThat(result).containsExactly(
assertThat(result).contains(
"'identifier' expected to match 'example.org', but is '"+testCase.domainName+"'"
);
}
enum ValidDomainNameIdentifier {
SIMPLE("example.org"),
MAX_LENGTH("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz01234568901.de"),
@ -88,7 +92,7 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
@EnumSource(ValidDomainNameIdentifier.class)
void acceptsValidIdentifier(final ValidDomainNameIdentifier testCase) {
// given
Dns.fakeNextResult(new Dns.Result(Dns.Status.NAME_NOT_FOUND, null, null));
Dns.fakeResultForDomain(testCase.domainName, new Dns.Result(Dns.Status.NAME_NOT_FOUND, null, null));
final var givenEntity = validEntityBuilder(testCase.domainName).identifier(testCase.domainName).build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
@ -111,7 +115,6 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
@Test
void validatesReferencedEntities() {
// given
Dns.fakeNextResult(new Dns.Result(Dns.Status.NAME_NOT_FOUND, null, null));
final var domainSetupHostingAssetEntity = validEntityBuilder()
.parentAsset(HsHostingAssetRealEntity.builder().type(CLOUD_SERVER).build())
.assignedToAsset(HsHostingAssetRealEntity.builder().type(MANAGED_SERVER).build())
@ -169,8 +172,10 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
void expectsEitherParentAssetOrBookingItem() {
// given
Dns.fakeNextResult(new Dns.Result(Dns.Status.NAME_NOT_FOUND, null, null));
final var domainSetupHostingAssetEntity = validEntityBuilder().build();
Dns.fakeResultForDomain(
domainSetupHostingAssetEntity.getIdentifier(),
new Dns.Result(Dns.Status.NAME_NOT_FOUND, null, null));
final var validator = HostingAssetEntityValidatorRegistry.forType(domainSetupHostingAssetEntity.getType());
// when
@ -183,16 +188,16 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
enum DnsLookupFailureTestCase {
SERVICE_UNAVAILABLE(
new ServiceUnavailableException("no Internet connection"),
"DNS request for example.org failed: javax.naming.ServiceUnavailableException: no Internet connection"),
"[DNS] lookup failed for domain name 'example.org': javax.naming.ServiceUnavailableException: no Internet connection"),
NAME_NOT_FOUND(
new NameNotFoundException("domain not registered"),
new NameNotFoundException("domain name not found"),
null), // no
INVALID_NAME(
new InvalidNameException("domain name too long or whatever"),
"Invalid domain name example.org"),
"[DNS] invalid domain name 'example.org'"),
UNKNOWN_FAILURE(
new NamingException("some other problem"),
"DNS request for example.org failed: javax.naming.NamingException: some other problem");
"[DNS] lookup failed for domain name 'example.org': javax.naming.NamingException: some other problem");
public final NamingException givenException;
public final String expectedErrorMessage;
@ -208,8 +213,10 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
void handlesDnsLookupFailures(final DnsLookupFailureTestCase testCase) {
// given
Dns.fakeNextResult(Dns.Result.fromException(testCase.givenException));
final var domainSetupHostingAssetEntity = validEntityBuilder().build();
Dns.fakeResultForDomain(
domainSetupHostingAssetEntity.getIdentifier(),
Dns.Result.fromException(testCase.givenException));
final var validator = HostingAssetEntityValidatorRegistry.forType(domainSetupHostingAssetEntity.getType());
// when
@ -223,6 +230,24 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
}
}
@Test
void allowSetupOfNonExistingSubdomainOfRegistrarLevelDomain() {
// given
final var domainSetupHostingAssetEntity = validEntityBuilder().build();
final var domainName = domainSetupHostingAssetEntity.getIdentifier();
Dns.fakeResultForDomain(
domainName,
Dns.Result.fromException(new NameNotFoundException("domain not registered")));
final var validator = HostingAssetEntityValidatorRegistry.forType(domainSetupHostingAssetEntity.getType());
// when
final var result = validator.validateEntity(domainSetupHostingAssetEntity);
// then
assertThat(result).isEmpty();
}
private static HsHostingAssetRealEntity createValidParentDomainSetupAsset(final String parentDomainName) {
final var bookingItem = HsBookingItemRealEntity.builder()
.type(HsBookingItemType.DOMAIN_SETUP)