mirror of
https://github.com/google/nomulus.git
synced 2025-05-14 00:17:20 +02:00
Fix bug which allowed creation of hosts with superordinate domains in pending delete state.
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=154716883
This commit is contained in:
parent
386d2bc6be
commit
11e7374c0f
7 changed files with 82 additions and 0 deletions
|
@ -1009,6 +1009,7 @@ are enqueued to update DNS accordingly.
|
|||
* This resource has clientUpdateProhibited on it, and the update does not
|
||||
clear that status.
|
||||
* Resource status prohibits this operation.
|
||||
* Superordinate domain for this hostname is in pending delete.
|
||||
* Cannot remove all IP addresses from a subordinate host.
|
||||
* Cannot rename an external host.
|
||||
* 2306
|
||||
|
@ -1094,6 +1095,8 @@ allows creating a host name, and if necessary enqueues tasks to update DNS.
|
|||
* Resource with this id already exists.
|
||||
* 2303
|
||||
* Superordinate domain for this hostname does not exist.
|
||||
* 2304
|
||||
* Superordinate domain for this hostname is in pending delete.
|
||||
* 2306
|
||||
* Host names must be at least two levels below the public suffix.
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
|
|||
import static google.registry.flows.ResourceFlowUtils.verifyResourceDoesNotExist;
|
||||
import static google.registry.flows.host.HostFlowUtils.lookupSuperordinateDomain;
|
||||
import static google.registry.flows.host.HostFlowUtils.validateHostName;
|
||||
import static google.registry.flows.host.HostFlowUtils.verifySuperordinateDomainNotInPendingDelete;
|
||||
import static google.registry.flows.host.HostFlowUtils.verifySuperordinateDomainOwnership;
|
||||
import static google.registry.model.EppResourceUtils.createRepoId;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
|
@ -72,6 +73,7 @@ import org.joda.time.DateTime;
|
|||
* @error {@link HostFlowUtils.HostNameNotNormalizedException}
|
||||
* @error {@link HostFlowUtils.HostNameNotPunyCodedException}
|
||||
* @error {@link HostFlowUtils.SuperordinateDomainDoesNotExistException}
|
||||
* @error {@link HostFlowUtils.SuperordinateDomainInPendingDeleteException}
|
||||
* @error {@link SubordinateHostMustHaveIpException}
|
||||
* @error {@link UnexpectedExternalHostIpException}
|
||||
*/
|
||||
|
@ -101,6 +103,7 @@ public final class HostCreateFlow implements TransactionalFlow {
|
|||
// we can detect error conditions earlier.
|
||||
Optional<DomainResource> superordinateDomain =
|
||||
lookupSuperordinateDomain(validateHostName(targetId), now);
|
||||
verifySuperordinateDomainNotInPendingDelete(superordinateDomain.orNull());
|
||||
verifySuperordinateDomainOwnership(clientId, superordinateDomain.orNull());
|
||||
boolean willBeSubordinate = superordinateDomain.isPresent();
|
||||
boolean hasIpAddresses = !isNullOrEmpty(command.getInetAddresses());
|
||||
|
|
|
@ -30,7 +30,9 @@ import google.registry.flows.EppException.ObjectDoesNotExistException;
|
|||
import google.registry.flows.EppException.ParameterValuePolicyErrorException;
|
||||
import google.registry.flows.EppException.ParameterValueRangeErrorException;
|
||||
import google.registry.flows.EppException.ParameterValueSyntaxErrorException;
|
||||
import google.registry.flows.EppException.StatusProhibitsOperationException;
|
||||
import google.registry.model.domain.DomainResource;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.util.Idn;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
|
@ -127,6 +129,24 @@ public class HostFlowUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/** Ensure that the superordinate domain is not in pending delete. */
|
||||
static void verifySuperordinateDomainNotInPendingDelete(
|
||||
DomainResource superordinateDomain) throws EppException {
|
||||
if ((superordinateDomain != null)
|
||||
&& superordinateDomain.getStatusValues().contains(StatusValue.PENDING_DELETE)) {
|
||||
throw new SuperordinateDomainInPendingDeleteException(
|
||||
superordinateDomain.getFullyQualifiedDomainName());
|
||||
}
|
||||
}
|
||||
|
||||
/** Superordinate domain for this hostname is in pending delete. */
|
||||
static class SuperordinateDomainInPendingDeleteException
|
||||
extends StatusProhibitsOperationException {
|
||||
public SuperordinateDomainInPendingDeleteException(String domainName) {
|
||||
super(domainName);
|
||||
}
|
||||
}
|
||||
|
||||
/** Host names are limited to 253 characters. */
|
||||
static class HostNameTooLongException extends ParameterValueRangeErrorException {
|
||||
public HostNameTooLongException() {
|
||||
|
|
|
@ -24,6 +24,7 @@ import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses
|
|||
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
|
||||
import static google.registry.flows.host.HostFlowUtils.lookupSuperordinateDomain;
|
||||
import static google.registry.flows.host.HostFlowUtils.validateHostName;
|
||||
import static google.registry.flows.host.HostFlowUtils.verifySuperordinateDomainNotInPendingDelete;
|
||||
import static google.registry.flows.host.HostFlowUtils.verifySuperordinateDomainOwnership;
|
||||
import static google.registry.model.index.ForeignKeyIndex.loadAndGetKey;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
|
@ -90,6 +91,7 @@ import org.joda.time.DateTime;
|
|||
* @error {@link HostFlowUtils.HostNameTooShallowException}
|
||||
* @error {@link HostFlowUtils.InvalidHostNameException}
|
||||
* @error {@link HostFlowUtils.SuperordinateDomainDoesNotExistException}
|
||||
* @error {@link HostFlowUtils.SuperordinateDomainInPendingDeleteException}
|
||||
* @error {@link CannotAddIpToExternalHostException}
|
||||
* @error {@link CannotRemoveSubordinateHostLastIpException}
|
||||
* @error {@link CannotRenameExternalHostException}
|
||||
|
@ -139,6 +141,7 @@ public final class HostUpdateFlow implements TransactionalFlow {
|
|||
// Note that lookupSuperordinateDomain calls cloneProjectedAtTime on the domain for us.
|
||||
Optional<DomainResource> newSuperordinateDomain =
|
||||
lookupSuperordinateDomain(validateHostName(newHostName), now);
|
||||
verifySuperordinateDomainNotInPendingDelete(newSuperordinateDomain.orNull());
|
||||
EppResource owningResource = firstNonNull(oldSuperordinateDomain, existingHost);
|
||||
verifyUpdateAllowed(
|
||||
command, existingHost, newSuperordinateDomain.orNull(), owningResource, isHostRename);
|
||||
|
|
|
@ -28,6 +28,7 @@ import com.googlecode.objectify.VoidWork;
|
|||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.mapreduce.MapreduceRunner;
|
||||
import google.registry.model.domain.DomainResource;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Parameter;
|
||||
|
@ -107,6 +108,14 @@ public class RdeHostLinkAction implements Runnable {
|
|||
logger.infofmt("Host %s is out of zone", xjcHost.getName());
|
||||
return;
|
||||
}
|
||||
if (superordinateDomain.get().getStatusValues().contains(StatusValue.PENDING_DELETE)) {
|
||||
getContext()
|
||||
.incrementCounter(
|
||||
"post-import hosts with superordinate domains in pending delete");
|
||||
logger.infofmt(
|
||||
"Host %s has a superordinate domain in pending delete", xjcHost.getName());
|
||||
return;
|
||||
}
|
||||
// at this point, the host is definitely in zone and should be linked
|
||||
getContext().incrementCounter("post-import hosts in zone");
|
||||
final Key<DomainResource> superordinateDomainKey = Key.create(superordinateDomain.get());
|
||||
|
|
|
@ -18,15 +18,18 @@ import static com.google.common.truth.Truth.assertThat;
|
|||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||
import static google.registry.testing.DatastoreHelper.assertNoBillingEvents;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainResource;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveHost;
|
||||
import static google.registry.testing.DatastoreHelper.persistDeletedHost;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.testing.HostResourceSubject.assertAboutHosts;
|
||||
import static google.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
|
||||
import static google.registry.testing.TaskQueueHelper.assertNoDnsTasksEnqueued;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.flows.EppXmlTransformer.IpAddressVersionMismatchException;
|
||||
import google.registry.flows.ResourceFlowTestCase;
|
||||
|
@ -40,7 +43,9 @@ import google.registry.flows.host.HostFlowUtils.HostNameTooLongException;
|
|||
import google.registry.flows.host.HostFlowUtils.HostNameTooShallowException;
|
||||
import google.registry.flows.host.HostFlowUtils.InvalidHostNameException;
|
||||
import google.registry.flows.host.HostFlowUtils.SuperordinateDomainDoesNotExistException;
|
||||
import google.registry.flows.host.HostFlowUtils.SuperordinateDomainInPendingDeleteException;
|
||||
import google.registry.model.domain.DomainResource;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import org.joda.time.DateTime;
|
||||
|
@ -167,6 +172,22 @@ public class HostCreateFlowTest extends ResourceFlowTestCase<HostCreateFlow, Hos
|
|||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_superordinateInPendingDelete() throws Exception {
|
||||
setEppHostCreateInputWithIps("ns1.example.tld");
|
||||
createTld("tld");
|
||||
persistResource(newDomainResource("example.tld")
|
||||
.asBuilder()
|
||||
.setDeletionTime(clock.nowUtc().plusDays(35))
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
thrown.expect(
|
||||
SuperordinateDomainInPendingDeleteException.class,
|
||||
"example.tld");
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_alreadyExists() throws Exception {
|
||||
setEppHostCreateInput("ns1.example.tld", null);
|
||||
|
|
|
@ -59,6 +59,7 @@ import google.registry.flows.host.HostFlowUtils.HostNameTooLongException;
|
|||
import google.registry.flows.host.HostFlowUtils.HostNameTooShallowException;
|
||||
import google.registry.flows.host.HostFlowUtils.InvalidHostNameException;
|
||||
import google.registry.flows.host.HostFlowUtils.SuperordinateDomainDoesNotExistException;
|
||||
import google.registry.flows.host.HostFlowUtils.SuperordinateDomainInPendingDeleteException;
|
||||
import google.registry.flows.host.HostUpdateFlow.CannotAddIpToExternalHostException;
|
||||
import google.registry.flows.host.HostUpdateFlow.CannotRemoveSubordinateHostLastIpException;
|
||||
import google.registry.flows.host.HostUpdateFlow.CannotRenameExternalHostException;
|
||||
|
@ -762,6 +763,28 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
|
|||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_superordinateInPendingDelete() throws Exception {
|
||||
setEppHostUpdateInput(
|
||||
"ns1.example.tld",
|
||||
"ns2.example.tld",
|
||||
"<host:addr ip=\"v4\">192.0.2.22</host:addr>",
|
||||
"<host:addr ip=\"v6\">1080:0:0:0:8:800:200C:417A</host:addr>");
|
||||
createTld("tld");
|
||||
DomainResource domain = persistResource(newDomainResource("example.tld")
|
||||
.asBuilder()
|
||||
.setSubordinateHosts(ImmutableSet.of(oldHostName()))
|
||||
.setDeletionTime(clock.nowUtc().plusDays(35))
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
|
||||
.build());
|
||||
persistActiveSubordinateHost(oldHostName(), domain);
|
||||
clock.advanceOneMilli();
|
||||
thrown.expect(
|
||||
SuperordinateDomainInPendingDeleteException.class,
|
||||
"example.tld");
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverExisted() throws Exception {
|
||||
thrown.expect(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue