Compare commits

..

No commits in common. "667b3908fdeca23ddf46d183f81117f23fa5836d" and "8d69f2ed39250e3efb2d48c23465b5ce5895d90e" have entirely different histories.

2 changed files with 33 additions and 66 deletions

View File

@ -2,9 +2,9 @@ package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAsset; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAsset;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.function.Supplier;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SETUP; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SETUP;
@ -33,18 +33,44 @@ class HsDomainSetupHostingAssetValidator extends HostingAssetEntityValidator {
return violations; return violations;
} }
final var dnsResult = new Dns(assetEntity.getIdentifier()).fetchRecordsOfType("TXT"); final var domainName = assetEntity.getIdentifier();
final var dnsResult = new Dns(domainName).fetchRecordsOfType("TXT");
final Supplier<String> getCode = () -> assetEntity.getBookingItem().getDirectValue("verificationCode", String.class);
switch (dnsResult.status()) { switch (dnsResult.status()) {
case Dns.Status.SUCCESS: case Dns.Status.SUCCESS: {
violations.addAll(handleDomainNameFound(assetEntity, dnsResult)); final var expectedTxtRecordValue = "Hostsharing-domain-setup-verification-code=" + getCode.get();
final var verificationFound = findTxtRecord(dnsResult, expectedTxtRecordValue)
.or(() -> superDomain(domainName)
.flatMap(superDomainName -> findTxtRecord(
new Dns(superDomainName).fetchRecordsOfType("TXT"),
expectedTxtRecordValue))
);
if (verificationFound.isEmpty()) {
violations.add(
"[DNS] no TXT record '" + expectedTxtRecordValue +
"' found for domain name '" + domainName + "' (nor in its super-domain)");
}
break; break;
}
case Dns.Status.NAME_NOT_FOUND: case Dns.Status.NAME_NOT_FOUND: {
violations.addAll(handleDomainNameNotFoundError(assetEntity, dnsResult)); if (isDnsVerificationRequiredForUnregisteredDomain(assetEntity)) {
final var superDomain = superDomain(domainName);
final var expectedTxtRecordValue = "Hostsharing-domain-setup-verification-code=" + getCode.get();
final var verificationFoundInSuperDomain = superDomain.flatMap(superDomainName -> findTxtRecord(
new Dns(superDomainName).fetchRecordsOfType("TXT"),
expectedTxtRecordValue));
if (verificationFoundInSuperDomain.isEmpty()) {
violations.add(
"[DNS] no TXT record '" + expectedTxtRecordValue +
"' found for domain name '" + superDomain.orElseThrow() + "'");
}
}
// otherwise no DNS verification to be able to setup DNS for domains to register
break; break;
}
case Dns.Status.INVALID_NAME: case Dns.Status.INVALID_NAME:
// should not happen because we validate the domain name at booking item level
violations.add("[DNS] invalid domain name '" + assetEntity.getIdentifier() + "'"); violations.add("[DNS] invalid domain name '" + assetEntity.getIdentifier() + "'");
break; break;
@ -56,10 +82,6 @@ class HsDomainSetupHostingAssetValidator extends HostingAssetEntityValidator {
return violations; return violations;
} }
private static String verificationCode(final HsHostingAsset assetEntity) {
return assetEntity.getBookingItem().getDirectValue("verificationCode", String.class);
}
@Override @Override
protected Pattern identifierPattern(final HsHostingAsset assetEntity) { protected Pattern identifierPattern(final HsHostingAsset assetEntity) {
if (assetEntity.getBookingItem() != null) { if (assetEntity.getBookingItem() != null) {
@ -71,49 +93,6 @@ class HsDomainSetupHostingAssetValidator extends HostingAssetEntityValidator {
return Pattern.compile(SUBDOMAIN_NAME_REGEX + "\\." + parentDomainName.replace(".", "\\."), Pattern.CASE_INSENSITIVE); return Pattern.compile(SUBDOMAIN_NAME_REGEX + "\\." + parentDomainName.replace(".", "\\."), Pattern.CASE_INSENSITIVE);
} }
private static List<String> handleDomainNameFound(final HsHostingAsset assetEntity, final Dns.Result dnsResult) {
final var violations = new ArrayList<String>();
final var expectedTxtRecordValue = "Hostsharing-domain-setup-verification-code=" + verificationCode(assetEntity);
final var verificationFound = findTxtRecord(dnsResult, expectedTxtRecordValue)
.or(() -> superDomain(assetEntity.getIdentifier())
.flatMap(superDomainName -> findTxtRecord(
new Dns(superDomainName).fetchRecordsOfType("TXT"),
expectedTxtRecordValue))
);
if (verificationFound.isEmpty()) {
violations.add(
"[DNS] no TXT record '" + expectedTxtRecordValue +
"' found for domain name '" + assetEntity.getIdentifier() + "' (nor in its super-domain)");
}
return violations;
}
private static List<String> handleDomainNameNotFoundError(final HsHostingAsset assetEntity, final Dns.Result dnsResult) {
final var violations = new ArrayList<String>();
if (isDnsVerificationRequiredForUnregisteredDomain(assetEntity)) {
final var superDomain = superDomain(assetEntity.getIdentifier());
final var expectedTxtRecordValue = "Hostsharing-domain-setup-verification-code=" + verificationCode(assetEntity);
final var verificationFoundInSuperDomain = superDomain.map(superDomainName ->
{
final Dns.Result superDomainDnsResult = new Dns(superDomainName).fetchRecordsOfType("TXT");
if (superDomainDnsResult.status() != Dns.Status.SUCCESS) {
violations.add("[DNS] lookup failed for domain name '" + superDomainName + "': " + dnsResult.exception());
}
return superDomainDnsResult;
}
)
.flatMap(records -> findTxtRecord(records, expectedTxtRecordValue));
if (verificationFoundInSuperDomain.isEmpty()) {
violations.add(
"[DNS] no TXT record '" + expectedTxtRecordValue +
"' found for domain name '" + superDomain.orElseThrow() + "'");
}
} else {
// otherwise no DNS verification to be able to setup DNS for domains to register
}
return violations;
}
private static boolean isDnsVerificationRequiredForUnregisteredDomain(final HsHostingAsset assetEntity) { private static boolean isDnsVerificationRequiredForUnregisteredDomain(final HsHostingAsset assetEntity) {
return !Dns.isRegistrableDomain(assetEntity.getIdentifier()) return !Dns.isRegistrableDomain(assetEntity.getIdentifier())
&& assetEntity.getParentAsset() == null; && assetEntity.getParentAsset() == null;

View File

@ -358,12 +358,6 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
.isRejectedWithCauseMissingVerificationIn("example.org"); .isRejectedWithCauseMissingVerificationIn("example.org");
} }
@Test
void rejectSetupOfUnregisteredSubdomainOfUnregisteredSuperDomain() {
domainSetupFor("sub.sub.example.org").notRegistered()
.isRejectedWithCauseDomainNameNotFound("sub.example.org");
}
@Test @Test
void acceptSetupOfUnregisteredSubdomainWithParentAssetEvenWithoutDnsVerificationInSuperDomain() { void acceptSetupOfUnregisteredSubdomainWithParentAssetEvenWithoutDnsVerificationInSuperDomain() {
domainSetupWithParentAssetFor("sub.example.org").notRegistered() domainSetupWithParentAssetFor("sub.example.org").notRegistered()
@ -494,12 +488,6 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
); );
} }
void isRejectedWithCauseDomainNameNotFound(final String domainName) {
assertThat(validate()).contains(
"[DNS] lookup failed for domain name '" + domainName + "': javax.naming.NameNotFoundException: domain not registered"
);
}
void isAccepted() { void isAccepted() {
assertThat(validate()).isEmpty(); assertThat(validate()).isEmpty();
} }