Disallow renaming of external hosts

EPP host spec section 3.2.5 requires that attempts to update hosts that are linked to different registrars must fail with error code 2305. This is complicated to do, as linked status is eventually consistent, and even more painful when checking links to those of different registrars.

This change forbids external-to-anything renames entirely.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=150336754
This commit is contained in:
ctingue 2017-03-16 10:33:07 -07:00 committed by Ben McIlwain
parent e1c9395749
commit 443e260f91
23 changed files with 357 additions and 156 deletions

View file

@ -961,8 +961,6 @@ are enqueued to update DNS accordingly.
### Errors ### Errors
* 2003
* Host rename from external to subordinate must also add an IP addresses.
* 2004 * 2004
* The specified status value cannot be set by clients. * The specified status value cannot be set by clients.
* Host names are limited to 253 characters. * Host names are limited to 253 characters.
@ -987,6 +985,7 @@ are enqueued to update DNS accordingly.
clear that status. clear that status.
* Resource status prohibits this operation. * Resource status prohibits this operation.
* Cannot remove all IP addresses from a subordinate host. * Cannot remove all IP addresses from a subordinate host.
* Cannot rename an external host.
* 2306 * 2306
* Cannot add and remove the same value. * Cannot add and remove the same value.
* Host names must be at least two levels below the public suffix. * Host names must be at least two levels below the public suffix.

View file

@ -36,7 +36,6 @@ import google.registry.dns.DnsQueue;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppException.ObjectAlreadyExistsException; import google.registry.flows.EppException.ObjectAlreadyExistsException;
import google.registry.flows.EppException.ParameterValueRangeErrorException; import google.registry.flows.EppException.ParameterValueRangeErrorException;
import google.registry.flows.EppException.RequiredParameterMissingException;
import google.registry.flows.EppException.StatusProhibitsOperationException; import google.registry.flows.EppException.StatusProhibitsOperationException;
import google.registry.flows.ExtensionManager; import google.registry.flows.ExtensionManager;
import google.registry.flows.FlowModule.ClientId; import google.registry.flows.FlowModule.ClientId;
@ -91,9 +90,9 @@ import org.joda.time.DateTime;
* @error {@link HostFlowUtils.SuperordinateDomainDoesNotExistException} * @error {@link HostFlowUtils.SuperordinateDomainDoesNotExistException}
* @error {@link CannotAddIpToExternalHostException} * @error {@link CannotAddIpToExternalHostException}
* @error {@link CannotRemoveSubordinateHostLastIpException} * @error {@link CannotRemoveSubordinateHostLastIpException}
* @error {@link CannotRenameExternalHostException}
* @error {@link HostAlreadyExistsException} * @error {@link HostAlreadyExistsException}
* @error {@link RenameHostToExternalRemoveIpException} * @error {@link RenameHostToExternalRemoveIpException}
* @error {@link RenameHostToSubordinateRequiresIpException}
*/ */
public final class HostUpdateFlow implements TransactionalFlow { public final class HostUpdateFlow implements TransactionalFlow {
@ -138,7 +137,8 @@ public final class HostUpdateFlow implements TransactionalFlow {
Optional<DomainResource> newSuperordinateDomain = Optional<DomainResource> newSuperordinateDomain =
lookupSuperordinateDomain(validateHostName(newHostName), now); lookupSuperordinateDomain(validateHostName(newHostName), now);
EppResource owningResource = firstNonNull(oldSuperordinateDomain, existingHost); EppResource owningResource = firstNonNull(oldSuperordinateDomain, existingHost);
verifyUpdateAllowed(command, existingHost, newSuperordinateDomain.orNull(), owningResource); verifyUpdateAllowed(
command, existingHost, newSuperordinateDomain.orNull(), owningResource, isHostRename);
if (isHostRename && loadAndGetKey(HostResource.class, newHostName, now) != null) { if (isHostRename && loadAndGetKey(HostResource.class, newHostName, now) != null) {
throw new HostAlreadyExistsException(newHostName); throw new HostAlreadyExistsException(newHostName);
} }
@ -205,12 +205,16 @@ public final class HostUpdateFlow implements TransactionalFlow {
Update command, Update command,
HostResource existingHost, HostResource existingHost,
DomainResource newSuperordinateDomain, DomainResource newSuperordinateDomain,
EppResource owningResource) EppResource owningResource,
boolean isHostRename)
throws EppException { throws EppException {
if (!isSuperuser) { if (!isSuperuser) {
// Verify that the host belongs to this registrar, either directly or because it is currently // Verify that the host belongs to this registrar, either directly or because it is currently
// subordinate to a domain owned by this registrar. // subordinate to a domain owned by this registrar.
verifyResourceOwnership(clientId, owningResource); verifyResourceOwnership(clientId, owningResource);
if (isHostRename && !existingHost.isSubordinate()) {
throw new CannotRenameExternalHostException();
}
// Verify that the new superordinate domain belongs to this registrar. // Verify that the new superordinate domain belongs to this registrar.
verifySuperordinateDomainOwnership(clientId, newSuperordinateDomain); verifySuperordinateDomainOwnership(clientId, newSuperordinateDomain);
ImmutableSet<StatusValue> statusesToAdd = command.getInnerAdd().getStatusValues(); ImmutableSet<StatusValue> statusesToAdd = command.getInnerAdd().getStatusValues();
@ -229,7 +233,6 @@ public final class HostUpdateFlow implements TransactionalFlow {
private void verifyHasIpsIffIsExternal( private void verifyHasIpsIffIsExternal(
Update command, HostResource existingHost, HostResource newHost) throws EppException { Update command, HostResource existingHost, HostResource newHost) throws EppException {
boolean wasSubordinate = existingHost.isSubordinate(); boolean wasSubordinate = existingHost.isSubordinate();
boolean wasExternal = !wasSubordinate;
boolean willBeSubordinate = newHost.isSubordinate(); boolean willBeSubordinate = newHost.isSubordinate();
boolean willBeExternal = !willBeSubordinate; boolean willBeExternal = !willBeSubordinate;
boolean newHostHasIps = !isNullOrEmpty(newHost.getInetAddresses()); boolean newHostHasIps = !isNullOrEmpty(newHost.getInetAddresses());
@ -243,9 +246,6 @@ public final class HostUpdateFlow implements TransactionalFlow {
if (wasSubordinate && willBeExternal && newHostHasIps) { if (wasSubordinate && willBeExternal && newHostHasIps) {
throw new RenameHostToExternalRemoveIpException(); throw new RenameHostToExternalRemoveIpException();
} }
if (wasExternal && willBeSubordinate && !commandAddsIps) {
throw new RenameHostToSubordinateRequiresIpException();
}
if (willBeSubordinate && !newHostHasIps) { if (willBeSubordinate && !newHostHasIps) {
throw new CannotRemoveSubordinateHostLastIpException(); throw new CannotRemoveSubordinateHostLastIpException();
} }
@ -321,11 +321,10 @@ public final class HostUpdateFlow implements TransactionalFlow {
} }
} }
/** Host rename from external to subordinate must also add an IP addresses. */ /** Cannot rename an external host. */
static class RenameHostToSubordinateRequiresIpException static class CannotRenameExternalHostException extends StatusProhibitsOperationException {
extends RequiredParameterMissingException { public CannotRenameExternalHostException() {
public RenameHostToSubordinateRequiresIpException() { super("Cannot rename an external host");
super("Host rename from external to subordinate must also add an IP address");
} }
} }

View file

@ -102,7 +102,7 @@ public class EppLifecycleDomainTest extends EppTestCase {
// Verify that nameserver's data was set correctly. // Verify that nameserver's data was set correctly.
assertCommandAndResponse( assertCommandAndResponse(
"host_info_fakesite.xml", "host_info_fakesite.xml",
"host_info_response_fakesite.xml", "host_info_response_fakesite_linked.xml",
DateTime.parse("2000-06-08T00:02:00Z")); DateTime.parse("2000-06-08T00:02:00Z"));
} }
@ -219,6 +219,19 @@ public class EppLifecycleDomainTest extends EppTestCase {
public void testDeletionOfDomain_afterUpdateThatCreatesSubordinateHost_fails() throws Exception { public void testDeletionOfDomain_afterUpdateThatCreatesSubordinateHost_fails() throws Exception {
assertCommandAndResponse("login_valid.xml", "login_response.xml"); assertCommandAndResponse("login_valid.xml", "login_response.xml");
createFakesite(); createFakesite();
// Create domain example.tld.
assertCommandAndResponse(
"domain_create_no_hosts_or_dsdata.xml",
"domain_create_response_superordinate.xml",
DateTime.parse("2000-06-02T00:00:00Z"));
// Create nameserver ns1.example.tld
assertCommandAndResponse(
"host_create_example.xml",
"host_create_response_example.xml",
DateTime.parse("2000-06-02T00:01:00Z"));
// Update the ns1 host to be on the fakesite.example domain. // Update the ns1 host to be on the fakesite.example domain.
assertCommandAndResponse( assertCommandAndResponse(
"host_update_ns1_to_fakesite.xml", "host_update_ns1_to_fakesite.xml",
@ -243,32 +256,6 @@ public class EppLifecycleDomainTest extends EppTestCase {
assertCommandAndResponse("logout.xml", "logout_response.xml"); assertCommandAndResponse("logout.xml", "logout_response.xml");
} }
@Test
public void testRenamingHostToExistingHost_fails() throws Exception {
assertCommandAndResponse("login_valid.xml", "login_response.xml");
// Create the two hosts.
assertCommandAndResponse(
"host_create.xml", "host_create_response.xml", DateTime.parse("2000-06-01T00:02:00Z"));
assertCommandAndResponse(
"host_create2.xml", "host_create2_response.xml", DateTime.parse("2000-06-01T00:03:00Z"));
// Verify that host1 and host2 were created as we expect them.
assertCommandAndResponse(
"host_info_ns1.xml", "host_info_response_ns1.xml", DateTime.parse("2000-06-01T00:04:00Z"));
assertCommandAndResponse(
"host_info_ns2.xml", "host_info_response_ns2.xml", DateTime.parse("2000-06-01T00:05:00Z"));
// Attempt overwriting of host1 on top of host2 (and verify that it fails).
assertCommandAndResponse(
"host_update_ns1_to_ns2.xml",
"host_update_failed_response.xml",
DateTime.parse("2000-06-01T00:06:00Z"));
// Verify that host1 and host2 still exist in their unmodified states.
assertCommandAndResponse(
"host_info_ns1.xml", "host_info_response_ns1.xml", DateTime.parse("2000-06-01T00:07:00Z"));
assertCommandAndResponse(
"host_info_ns2.xml", "host_info_response_ns2.xml", DateTime.parse("2000-06-01T00:08:00Z"));
assertCommandAndResponse("logout.xml", "logout_response.xml");
}
@Test @Test
public void testDomainCreation_failsBeforeSunrise() throws Exception { public void testDomainCreation_failsBeforeSunrise() throws Exception {
DateTime sunriseDate = DateTime.parse("2000-05-30T00:00:00Z"); DateTime sunriseDate = DateTime.parse("2000-05-30T00:00:00Z");

View file

@ -14,6 +14,9 @@
package google.registry.flows; package google.registry.flows;
import static google.registry.testing.DatastoreHelper.createTld;
import com.google.common.collect.ImmutableMap;
import google.registry.testing.AppEngineRule; import google.registry.testing.AppEngineRule;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.junit.Rule; import org.junit.Rule;
@ -28,43 +31,56 @@ public class EppLifecycleHostTest extends EppTestCase {
@Rule @Rule
public final AppEngineRule appEngine = AppEngineRule.builder() public final AppEngineRule appEngine = AppEngineRule.builder()
.withDatastore() .withDatastore()
.withTaskQueue()
.build(); .build();
@Test @Test
public void testRenamingHostToExistingHost_fails() throws Exception { public void testRenamingHostToExistingHost_fails() throws Exception {
createTld("example");
assertCommandAndResponse("login_valid.xml", "login_response.xml"); assertCommandAndResponse("login_valid.xml", "login_response.xml");
// Create the two hosts. // Create the fakesite domain.
assertCommandAndResponse( assertCommandAndResponse(
"host_create.xml", "contact_create_sh8013.xml",
"host_create_response.xml", ImmutableMap.<String, String>of(),
DateTime.parse("2000-06-01T00:02:00Z")); "contact_create_response_sh8013.xml",
ImmutableMap.of("CRDATE", "2000-06-01T00:00:00Z"),
DateTime.parse("2000-06-01T00:00:00Z"));
assertCommandAndResponse( assertCommandAndResponse(
"host_create2.xml", "contact_create_jd1234.xml",
"host_create2_response.xml", "contact_create_response_jd1234.xml",
DateTime.parse("2000-06-01T00:03:00Z")); DateTime.parse("2000-06-01T00:01:00Z"));
// Verify that host1 and host2 were created as we expect them.
assertCommandAndResponse( assertCommandAndResponse(
"host_info_ns1.xml", "domain_create_fakesite_no_nameservers.xml",
"host_info_response_ns1.xml", "domain_create_response_fakesite.xml",
DateTime.parse("2000-06-01T00:04:00Z")); DateTime.parse("2000-06-01T00:04:00Z"));
assertCommandAndResponse( assertCommandAndResponse(
"host_info_ns2.xml", "domain_info_fakesite.xml",
"host_info_response_ns2.xml", "domain_info_response_fakesite_inactive.xml",
DateTime.parse("2000-06-01T00:05:00Z")); DateTime.parse("2000-06-05T00:02:00Z"));
// Attempt overwriting of host1 on top of host2 (and verify that it fails). // Add the fakesite subordinate host (requires that domain is already created).
assertCommandAndResponse( assertCommandAndResponse(
"host_update_ns1_to_ns2.xml", "host_create_fakesite.xml",
"host_create_response_fakesite.xml",
DateTime.parse("2000-06-06T00:01:00Z"));
// Add the 2nd fakesite subordinate host.
assertCommandAndResponse(
"host_create_fakesite2.xml",
"host_create_response_fakesite2.xml",
DateTime.parse("2000-06-09T00:01:00Z"));
// Attempt overwriting of 2nd fakesite subordinate host with the 1st.
assertCommandAndResponse(
"host_update_fakesite1_to_fakesite2.xml",
"host_update_failed_response.xml", "host_update_failed_response.xml",
DateTime.parse("2000-06-01T00:06:00Z")); DateTime.parse("2000-06-10T00:01:00Z"));
// Verify that host1 and host2 still exist in their unmodified states. // Verify that fakesite hosts still exist in their unmodified states.
assertCommandAndResponse( assertCommandAndResponse(
"host_info_ns1.xml", "host_info_fakesite.xml",
"host_info_response_ns1.xml", "host_info_response_fakesite_ok.xml",
DateTime.parse("2000-06-01T00:07:00Z")); DateTime.parse("2000-06-11T00:07:00Z"));
assertCommandAndResponse( assertCommandAndResponse(
"host_info_ns2.xml", "host_info_fakesite2.xml",
"host_info_response_ns2.xml", "host_info_response_fakesite2.xml",
DateTime.parse("2000-06-01T00:08:00Z")); DateTime.parse("2000-06-11T00:08:00Z"));
assertCommandAndResponse("logout.xml", "logout_response.xml"); assertCommandAndResponse("logout.xml", "logout_response.xml");
} }
} }

View file

@ -61,9 +61,9 @@ import google.registry.flows.host.HostFlowUtils.InvalidHostNameException;
import google.registry.flows.host.HostFlowUtils.SuperordinateDomainDoesNotExistException; import google.registry.flows.host.HostFlowUtils.SuperordinateDomainDoesNotExistException;
import google.registry.flows.host.HostUpdateFlow.CannotAddIpToExternalHostException; import google.registry.flows.host.HostUpdateFlow.CannotAddIpToExternalHostException;
import google.registry.flows.host.HostUpdateFlow.CannotRemoveSubordinateHostLastIpException; import google.registry.flows.host.HostUpdateFlow.CannotRemoveSubordinateHostLastIpException;
import google.registry.flows.host.HostUpdateFlow.CannotRenameExternalHostException;
import google.registry.flows.host.HostUpdateFlow.HostAlreadyExistsException; import google.registry.flows.host.HostUpdateFlow.HostAlreadyExistsException;
import google.registry.flows.host.HostUpdateFlow.RenameHostToExternalRemoveIpException; import google.registry.flows.host.HostUpdateFlow.RenameHostToExternalRemoveIpException;
import google.registry.flows.host.HostUpdateFlow.RenameHostToSubordinateRequiresIpException;
import google.registry.model.domain.DomainResource; import google.registry.model.domain.DomainResource;
import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.HostResource; import google.registry.model.host.HostResource;
@ -75,7 +75,6 @@ import google.registry.model.transfer.TransferStatus;
import google.registry.testing.TaskQueueHelper.TaskMatcher; import google.registry.testing.TaskQueueHelper.TaskMatcher;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
/** Unit tests for {@link HostUpdateFlow}. */ /** Unit tests for {@link HostUpdateFlow}. */
@ -96,11 +95,6 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
setEppHostUpdateInput("ns1.example.tld", "ns2.example.tld", null, null); setEppHostUpdateInput("ns1.example.tld", "ns2.example.tld", null, null);
} }
@Before
public void initHostTest() throws Exception {
createTld("xn--q9jyb4c");
}
/** /**
* Setup a domain with a transfer that should have been server approved a day ago. * Setup a domain with a transfer that should have been server approved a day ago.
* *
@ -131,14 +125,26 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
@Test @Test
public void testDryRun() throws Exception { public void testDryRun() throws Exception {
persistActiveHost("ns1.example.tld"); createTld("tld");
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
dryRunFlowAssertResponse(readFile("host_update_response.xml")); dryRunFlowAssertResponse(readFile("host_update_response.xml"));
} }
private HostResource doSuccessfulTest() throws Exception { private HostResource doSuccessfulTest() throws Exception {
return doSuccessfulTest(false); // default to normal user privileges
}
private HostResource doSuccessfulTestAsSuperuser() throws Exception {
return doSuccessfulTest(true);
}
private HostResource doSuccessfulTest(boolean isSuperuser) throws Exception {
clock.advanceOneMilli(); clock.advanceOneMilli();
assertTransactionalFlow(true); assertTransactionalFlow(true);
runFlowAssertResponse(readFile("host_update_response.xml")); runFlowAssertResponse(
CommitMode.LIVE,
isSuperuser ? UserPrivileges.SUPERUSER : UserPrivileges.NORMAL,
readFile("host_update_response.xml"));
// The example xml does a host rename, so reloading the host (which uses the original host name) // The example xml does a host rename, so reloading the host (which uses the original host name)
// should now return null. // should now return null.
assertThat(reloadResourceByForeignKey()).isNull(); assertThat(reloadResourceByForeignKey()).isNull();
@ -154,10 +160,11 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
@Test @Test
public void testSuccess_rename_noOtherHostEverUsedTheOldName() throws Exception { public void testSuccess_rename_noOtherHostEverUsedTheOldName() throws Exception {
persistActiveHost(oldHostName()); createTld("tld");
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
HostResource renamedHost = doSuccessfulTest(); HostResource renamedHost = doSuccessfulTest();
assertThat(renamedHost.isSubordinate()).isFalse(); assertThat(renamedHost.isSubordinate()).isTrue();
assertNoDnsTasksEnqueued(); // No tasks enqueued since it's a rename of an external host. assertDnsTasksEnqueued("ns1.example.tld", "ns2.example.tld");
// The old ForeignKeyIndex is invalidated at the time we did the rename. // The old ForeignKeyIndex is invalidated at the time we did the rename.
ForeignKeyIndex<HostResource> oldFkiBeforeRename = ForeignKeyIndex<HostResource> oldFkiBeforeRename =
ForeignKeyIndex.load( ForeignKeyIndex.load(
@ -171,14 +178,17 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
@Test @Test
public void testSuccess_withReferencingDomain() throws Exception { public void testSuccess_withReferencingDomain() throws Exception {
HostResource host = persistActiveHost(oldHostName()); createTld("tld");
createTld("xn--q9jyb4c");
HostResource host =
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
persistResource( persistResource(
newDomainResource("test.xn--q9jyb4c").asBuilder() newDomainResource("test.xn--q9jyb4c").asBuilder()
.setDeletionTime(END_OF_TIME) .setDeletionTime(END_OF_TIME)
.setNameservers(ImmutableSet.of(Key.create(host))) .setNameservers(ImmutableSet.of(Key.create(host)))
.build()); .build());
HostResource renamedHost = doSuccessfulTest(); HostResource renamedHost = doSuccessfulTest();
assertThat(renamedHost.isSubordinate()).isFalse(); assertThat(renamedHost.isSubordinate()).isTrue();
// Task enqueued to change the NS record of the referencing domain via mapreduce. // Task enqueued to change the NS record of the referencing domain via mapreduce.
assertTasksEnqueued( assertTasksEnqueued(
QUEUE_ASYNC_HOST_RENAME, QUEUE_ASYNC_HOST_RENAME,
@ -349,7 +359,7 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
} }
@Test @Test
public void testSuccess_externalToInternal() throws Exception { public void testFailure_externalToInternal() throws Exception {
setEppHostUpdateInput( setEppHostUpdateInput(
"ns1.example.foo", "ns1.example.foo",
"ns2.example.tld", "ns2.example.tld",
@ -359,7 +369,23 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
DomainResource domain = persistActiveDomain("example.tld"); DomainResource domain = persistActiveDomain("example.tld");
persistActiveHost(oldHostName()); persistActiveHost(oldHostName());
assertThat(domain.getSubordinateHosts()).isEmpty(); assertThat(domain.getSubordinateHosts()).isEmpty();
HostResource renamedHost = doSuccessfulTest(); thrown.expect(CannotRenameExternalHostException.class);
runFlow();
assertNoDnsTasksEnqueued();
}
@Test
public void testSuccess_superuserExternalToInternal() throws Exception {
setEppHostUpdateInput(
"ns1.example.foo",
"ns2.example.tld",
"<host:addr ip=\"v4\">192.0.2.22</host:addr>",
null);
createTld("tld");
DomainResource domain = persistActiveDomain("example.tld");
persistActiveHost(oldHostName());
assertThat(domain.getSubordinateHosts()).isEmpty();
HostResource renamedHost = doSuccessfulTestAsSuperuser();
DateTime now = clock.nowUtc(); DateTime now = clock.nowUtc();
assertAboutHosts().that(renamedHost) assertAboutHosts().that(renamedHost)
.hasSuperordinateDomain(Key.create(domain)).and() .hasSuperordinateDomain(Key.create(domain)).and()
@ -372,14 +398,26 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
} }
@Test @Test
public void testSuccess_externalToExternal() throws Exception { public void testFailure_externalToExternal() throws Exception {
setEppHostUpdateInput( setEppHostUpdateInput(
"ns1.example.foo", "ns1.example.foo",
"ns2.example.tld", "ns2.example.tld",
null, null,
null); null);
persistActiveHost(oldHostName()); persistActiveHost(oldHostName());
HostResource renamedHost = doSuccessfulTest(); thrown.expect(CannotRenameExternalHostException.class);
runFlow();
}
@Test
public void testSuccess_superuserExternalToExternal() throws Exception {
setEppHostUpdateInput(
"ns1.example.foo",
"ns2.example.tld",
null,
null);
persistActiveHost(oldHostName());
HostResource renamedHost = doSuccessfulTestAsSuperuser();
assertAboutHosts().that(renamedHost) assertAboutHosts().that(renamedHost)
.hasSuperordinateDomain(null).and() .hasSuperordinateDomain(null).and()
.hasLastSuperordinateChange(null).and() .hasLastSuperordinateChange(null).and()
@ -688,7 +726,7 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
newHostResource(oldHostName()).asBuilder() newHostResource(oldHostName()).asBuilder()
.setLastTransferTime(hostTransferTime) .setLastTransferTime(hostTransferTime)
.build()); .build());
HostResource renamedHost = doSuccessfulTest(); HostResource renamedHost = doSuccessfulTestAsSuperuser();
assertAboutHosts().that(renamedHost) assertAboutHosts().that(renamedHost)
.hasPersistedCurrentSponsorClientId("TheRegistrar").and() .hasPersistedCurrentSponsorClientId("TheRegistrar").and()
.hasLastTransferTime(hostTransferTime); .hasLastTransferTime(hostTransferTime);
@ -753,7 +791,8 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
@Test @Test
public void testFailure_renameToCurrentName() throws Exception { public void testFailure_renameToCurrentName() throws Exception {
persistActiveHost(oldHostName()); createTld("tld");
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
clock.advanceOneMilli(); clock.advanceOneMilli();
setEppHostUpdateInput("ns1.example.tld", "ns1.example.tld", null, null); setEppHostUpdateInput("ns1.example.tld", "ns1.example.tld", null, null);
thrown.expect(HostAlreadyExistsException.class, "ns1.example.tld"); thrown.expect(HostAlreadyExistsException.class, "ns1.example.tld");
@ -762,7 +801,8 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
@Test @Test
public void testFailure_renameToNameOfExistingOtherHost() throws Exception { public void testFailure_renameToNameOfExistingOtherHost() throws Exception {
persistActiveHost(oldHostName()); createTld("tld");
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
persistActiveHost("ns2.example.tld"); persistActiveHost("ns2.example.tld");
thrown.expect(HostAlreadyExistsException.class, "ns2.example.tld"); thrown.expect(HostAlreadyExistsException.class, "ns2.example.tld");
runFlow(); runFlow();
@ -822,25 +862,11 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
null, null,
"<host:addr ip=\"v6\">1080:0:0:0:8:800:200C:417A</host:addr>"); "<host:addr ip=\"v6\">1080:0:0:0:8:800:200C:417A</host:addr>");
createTld("tld"); createTld("tld");
persistResource(newHostResource(oldHostName()).asBuilder() persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
.setSuperordinateDomain(Key.create(persistActiveDomain("example.tld")))
.build());
thrown.expect(CannotRemoveSubordinateHostLastIpException.class); thrown.expect(CannotRemoveSubordinateHostLastIpException.class);
runFlow(); runFlow();
} }
@Test
public void testFailure_externalMustNotHaveIps() 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>");
persistActiveHost(oldHostName());
thrown.expect(CannotAddIpToExternalHostException.class);
runFlow();
}
@Test @Test
public void testFailure_subordinateToExternal_mustRemoveAllIps() throws Exception { public void testFailure_subordinateToExternal_mustRemoveAllIps() throws Exception {
setEppHostUpdateInput( setEppHostUpdateInput(
@ -849,12 +875,7 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
null, null,
null); null);
createTld("tld"); createTld("tld");
persistResource( persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
newHostResource(oldHostName())
.asBuilder()
.setSuperordinateDomain(Key.create(persistActiveDomain("example.tld")))
.setInetAddresses(ImmutableSet.of(InetAddresses.forString("127.0.0.1")))
.build());
thrown.expect(RenameHostToExternalRemoveIpException.class); thrown.expect(RenameHostToExternalRemoveIpException.class);
runFlow(); runFlow();
} }
@ -867,28 +888,11 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
"<host:addr ip=\"v4\">192.0.2.22</host:addr>", "<host:addr ip=\"v4\">192.0.2.22</host:addr>",
null); null);
createTld("tld"); createTld("tld");
persistResource(newHostResource(oldHostName()).asBuilder() persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
.setSuperordinateDomain(Key.create(persistActiveDomain("example.tld")))
.build());
thrown.expect(CannotAddIpToExternalHostException.class); thrown.expect(CannotAddIpToExternalHostException.class);
runFlow(); runFlow();
} }
@Test
public void testFailure_externalToSubordinate_mustAddAnIp() throws Exception {
setEppHostUpdateInput(
"ns1.example.com",
"ns2.example.tld",
null,
null);
createTld("tld");
persistActiveDomain("example.tld");
persistActiveHost(oldHostName());
clock.advanceOneMilli();
thrown.expect(RenameHostToSubordinateRequiresIpException.class);
runFlow();
}
@Test @Test
public void testFailure_addRemoveSameStatusValues() throws Exception { public void testFailure_addRemoveSameStatusValues() throws Exception {
createTld("tld"); createTld("tld");
@ -898,7 +902,7 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
"ns2.example.tld", "ns2.example.tld",
"<host:status s=\"clientUpdateProhibited\"/>", "<host:status s=\"clientUpdateProhibited\"/>",
"<host:status s=\"clientUpdateProhibited\"/>"); "<host:status s=\"clientUpdateProhibited\"/>");
persistActiveHost(oldHostName()); persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
thrown.expect(AddRemoveSameValueException.class); thrown.expect(AddRemoveSameValueException.class);
runFlow(); runFlow();
} }
@ -906,13 +910,12 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
@Test @Test
public void testFailure_addRemoveSameInetAddresses() throws Exception { public void testFailure_addRemoveSameInetAddresses() throws Exception {
createTld("tld"); createTld("tld");
persistActiveDomain("example.tld"); persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
setEppHostUpdateInput( setEppHostUpdateInput(
"ns1.example.tld", "ns1.example.tld",
"ns2.example.tld", "ns2.example.tld",
"<host:addr ip=\"v4\">192.0.2.22</host:addr>", "<host:addr ip=\"v4\">192.0.2.22</host:addr>",
"<host:addr ip=\"v4\">192.0.2.22</host:addr>"); "<host:addr ip=\"v4\">192.0.2.22</host:addr>");
persistActiveHost(oldHostName());
thrown.expect(AddRemoveSameValueException.class); thrown.expect(AddRemoveSameValueException.class);
runFlow(); runFlow();
} }
@ -920,7 +923,6 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
@Test @Test
public void testSuccess_clientUpdateProhibited_removed() throws Exception { public void testSuccess_clientUpdateProhibited_removed() throws Exception {
setEppInput("host_update_remove_client_update_prohibited.xml"); setEppInput("host_update_remove_client_update_prohibited.xml");
persistActiveHost(oldHostName());
persistResource( persistResource(
newHostResource(oldHostName()).asBuilder() newHostResource(oldHostName()).asBuilder()
.setStatusValues(ImmutableSet.of(StatusValue.CLIENT_UPDATE_PROHIBITED)) .setStatusValues(ImmutableSet.of(StatusValue.CLIENT_UPDATE_PROHIBITED))
@ -931,11 +933,12 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
.doesNotHaveStatusValue(StatusValue.CLIENT_UPDATE_PROHIBITED); .doesNotHaveStatusValue(StatusValue.CLIENT_UPDATE_PROHIBITED);
} }
@Test
public void testFailure_clientUpdateProhibited() throws Exception { public void testFailure_clientUpdateProhibited() throws Exception {
createTld("tld");
persistResource( persistResource(
newHostResource(oldHostName()).asBuilder() newHostResource(oldHostName()).asBuilder()
.setStatusValues(ImmutableSet.of(StatusValue.CLIENT_UPDATE_PROHIBITED)) .setStatusValues(ImmutableSet.of(StatusValue.CLIENT_UPDATE_PROHIBITED))
.setSuperordinateDomain(Key.create(persistActiveDomain("example.tld")))
.build()); .build());
thrown.expect(ResourceHasClientUpdateProhibitedException.class); thrown.expect(ResourceHasClientUpdateProhibitedException.class);
runFlow(); runFlow();
@ -943,9 +946,11 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
@Test @Test
public void testFailure_serverUpdateProhibited() throws Exception { public void testFailure_serverUpdateProhibited() throws Exception {
createTld("tld");
persistResource( persistResource(
newHostResource(oldHostName()).asBuilder() newHostResource(oldHostName()).asBuilder()
.setStatusValues(ImmutableSet.of(StatusValue.SERVER_UPDATE_PROHIBITED)) .setStatusValues(ImmutableSet.of(StatusValue.SERVER_UPDATE_PROHIBITED))
.setSuperordinateDomain(Key.create(persistActiveDomain("example.tld")))
.build()); .build());
thrown.expect(ResourceStatusProhibitsOperationException.class, "serverUpdateProhibited"); thrown.expect(ResourceStatusProhibitsOperationException.class, "serverUpdateProhibited");
runFlow(); runFlow();
@ -953,9 +958,11 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
@Test @Test
public void testFailure_pendingDelete() throws Exception { public void testFailure_pendingDelete() throws Exception {
createTld("tld");
persistResource( persistResource(
newHostResource(oldHostName()).asBuilder() newHostResource(oldHostName()).asBuilder()
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE)) .setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
.setSuperordinateDomain(Key.create(persistActiveDomain("example.tld")))
.build()); .build());
thrown.expect(ResourceStatusProhibitsOperationException.class, "pendingDelete"); thrown.expect(ResourceStatusProhibitsOperationException.class, "pendingDelete");
runFlow(); runFlow();
@ -964,9 +971,8 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
@Test @Test
public void testFailure_statusValueNotClientSettable() throws Exception { public void testFailure_statusValueNotClientSettable() throws Exception {
createTld("tld"); createTld("tld");
persistActiveDomain("example.tld"); persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
setEppInput("host_update_prohibited_status.xml"); setEppInput("host_update_prohibited_status.xml");
persistActiveHost(oldHostName());
thrown.expect(StatusNotClientSettableException.class); thrown.expect(StatusNotClientSettableException.class);
runFlow(); runFlow();
} }
@ -1083,11 +1089,13 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
"<host:addr ip=\"v4\">192.0.2.22</host:addr>", "<host:addr ip=\"v4\">192.0.2.22</host:addr>",
null); null);
sessionMetadata.setClientId("TheRegistrar"); sessionMetadata.setClientId("TheRegistrar");
createTld("foo");
createTld("tld"); createTld("tld");
persistResource(newDomainResource("example.tld").asBuilder() persistResource(newDomainResource("example.tld").asBuilder()
.setPersistedCurrentSponsorClientId("NewRegistar") .setPersistedCurrentSponsorClientId("NewRegistar")
.build()); .build());
HostResource host = persistActiveHost("ns1.example.foo"); HostResource host =
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.foo"));
assertAboutHosts().that(host).hasPersistedCurrentSponsorClientId("TheRegistrar"); assertAboutHosts().that(host).hasPersistedCurrentSponsorClientId("TheRegistrar");
thrown.expect(HostDomainNotOwnedException.class); thrown.expect(HostDomainNotOwnedException.class);
@ -1102,11 +1110,13 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
"<host:addr ip=\"v4\">192.0.2.22</host:addr>", "<host:addr ip=\"v4\">192.0.2.22</host:addr>",
null); null);
sessionMetadata.setClientId("TheRegistrar"); sessionMetadata.setClientId("TheRegistrar");
createTld("foo");
createTld("tld"); createTld("tld");
HostResource host =
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.foo"));
// The domain will belong to NewRegistrar after cloneProjectedAtTime is called. // The domain will belong to NewRegistrar after cloneProjectedAtTime is called.
DomainResource domain = persistResource(createDomainWithServerApprovedTransfer("example.tld")); DomainResource domain = persistResource(createDomainWithServerApprovedTransfer("example.tld"));
assertAboutDomains().that(domain).hasPersistedCurrentSponsorClientId("TheRegistrar"); assertAboutDomains().that(domain).hasPersistedCurrentSponsorClientId("TheRegistrar");
HostResource host = persistActiveHost("ns1.example.foo");
assertAboutHosts().that(host).hasPersistedCurrentSponsorClientId("TheRegistrar"); assertAboutHosts().that(host).hasPersistedCurrentSponsorClientId("TheRegistrar");
thrown.expect(HostDomainNotOwnedException.class); thrown.expect(HostDomainNotOwnedException.class);
@ -1121,11 +1131,16 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
"<host:addr ip=\"v4\">192.0.2.22</host:addr>", "<host:addr ip=\"v4\">192.0.2.22</host:addr>",
null); null);
sessionMetadata.setClientId("NewRegistrar"); sessionMetadata.setClientId("NewRegistrar");
createTld("foo");
createTld("tld"); createTld("tld");
// The domain will belong to NewRegistrar after cloneProjectedAtTime is called. // The domain will belong to NewRegistrar after cloneProjectedAtTime is called.
DomainResource domain = persistResource(createDomainWithServerApprovedTransfer("example.tld")); DomainResource domain = persistResource(createDomainWithServerApprovedTransfer("example.tld"));
DomainResource superordinate = persistResource(newDomainResource("example.foo").asBuilder()
.setPersistedCurrentSponsorClientId("NewRegistrar")
.build());
assertAboutDomains().that(domain).hasPersistedCurrentSponsorClientId("TheRegistrar"); assertAboutDomains().that(domain).hasPersistedCurrentSponsorClientId("TheRegistrar");
persistResource(newHostResource("ns1.example.foo").asBuilder() persistResource(newHostResource("ns1.example.foo").asBuilder()
.setSuperordinateDomain(Key.create(superordinate))
.setPersistedCurrentSponsorClientId("NewRegistrar") .setPersistedCurrentSponsorClientId("NewRegistrar")
.build()); .build());
@ -1197,7 +1212,8 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
@Test @Test
public void testSuccess_metadata() throws Exception { public void testSuccess_metadata() throws Exception {
persistActiveHost("ns1.example.tld"); createTld("tld");
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
clock.advanceOneMilli(); clock.advanceOneMilli();
setEppInput("host_update_metadata.xml"); setEppInput("host_update_metadata.xml");
eppRequestSource = EppRequestSource.TOOL; eppRequestSource = EppRequestSource.TOOL;

View file

@ -0,0 +1,18 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<domain:create
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>fakesite.example</domain:name>
<domain:period unit="y">2</domain:period>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">sh8013</domain:contact>
<domain:contact type="tech">sh8013</domain:contact>
<domain:authInfo>
<domain:pw>2fooBAR</domain:pw>
</domain:authInfo>
</domain:create>
</create>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -0,0 +1,19 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="1000">
<msg>Command completed successfully</msg>
</result>
<resData>
<domain:creData
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:crDate>2000-06-02T00:00:00.0Z</domain:crDate>
<domain:exDate>2002-06-02T00:00:00.0Z</domain:exDate>
</domain:creData>
</resData>
<trID>
<clTRID>ABC-12345</clTRID>
<svTRID>server-trid</svTRID>
</trID>
</response>
</epp>

View file

@ -0,0 +1,34 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="1000">
<msg>Command completed successfully</msg>
</result>
<resData>
<domain:infData
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>fakesite.example</domain:name>
<domain:roid>%ROID%</domain:roid>
<domain:status s="inactive"/>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">sh8013</domain:contact>
<domain:contact type="tech">sh8013</domain:contact>
<domain:clID>NewRegistrar</domain:clID>
<domain:crID>NewRegistrar</domain:crID>
<domain:crDate>2000-06-01T00:04:00Z</domain:crDate>
<domain:exDate>2002-06-01T00:04:00Z</domain:exDate>
<domain:authInfo>
<domain:pw>2fooBAR</domain:pw>
</domain:authInfo>
</domain:infData>
</resData>
<extension>
<rgp:infData xmlns:rgp="urn:ietf:params:xml:ns:rgp-1.0">
<rgp:rgpStatus s="addPeriod"/>
</rgp:infData>
</extension>
<trID>
<clTRID>ABC-12345</clTRID>
<svTRID>server-trid</svTRID>
</trID>
</response>
</epp>

View file

@ -13,7 +13,7 @@
<domain:contact type="admin">sh8013</domain:contact> <domain:contact type="admin">sh8013</domain:contact>
<domain:contact type="tech">sh8013</domain:contact> <domain:contact type="tech">sh8013</domain:contact>
<domain:ns> <domain:ns>
<domain:hostObj>ns3.fakesite.example</domain:hostObj> <domain:hostObj>ns1.example.external</domain:hostObj>
<domain:hostObj>ns2.example.external</domain:hostObj> <domain:hostObj>ns2.example.external</domain:hostObj>
</domain:ns> </domain:ns>
<domain:host>ns3.fakesite.example</domain:host> <domain:host>ns3.fakesite.example</domain:host>

View file

@ -0,0 +1,13 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<host:create xmlns:host="urn:ietf:params:xml:ns:host-1.0">
<host:name>ns1.example.tld</host:name>
<host:addr ip="v4">192.0.2.2</host:addr>
<host:addr ip="v4">192.0.2.29</host:addr>
<host:addr ip="v6">1080:0:0:0:8:800:200C:417A</host:addr>
</host:create>
</create>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -0,0 +1,13 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<host:create xmlns:host="urn:ietf:params:xml:ns:host-1.0">
<host:name>ns4.fakesite.example</host:name>
<host:addr ip="v4">192.0.2.3</host:addr>
<host:addr ip="v4">192.0.2.30</host:addr>
<host:addr ip="v6">1080:0:0:0:8:800:200C:417B</host:addr>
</host:create>
</create>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -0,0 +1,17 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="1000">
<msg>Command completed successfully</msg>
</result>
<resData>
<host:creData xmlns:host="urn:ietf:params:xml:ns:host-1.0">
<host:name>ns1.example.tld</host:name>
<host:crDate>2000-06-02T00:01:00Z</host:crDate>
</host:creData>
</resData>
<trID>
<clTRID>ABC-12345</clTRID>
<svTRID>server-trid</svTRID>
</trID>
</response>
</epp>

View file

@ -0,0 +1,17 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="1000">
<msg>Command completed successfully</msg>
</result>
<resData>
<host:creData xmlns:host="urn:ietf:params:xml:ns:host-1.0">
<host:name>ns4.fakesite.example</host:name>
<host:crDate>2000-06-09T00:01:00Z</host:crDate>
</host:creData>
</resData>
<trID>
<clTRID>ABC-12345</clTRID>
<svTRID>server-trid</svTRID>
</trID>
</response>
</epp>

View file

@ -2,7 +2,7 @@
<command> <command>
<info> <info>
<host:info xmlns:host="urn:ietf:params:xml:ns:host-1.0"> <host:info xmlns:host="urn:ietf:params:xml:ns:host-1.0">
<host:name>ns1.example.external</host:name> <host:name>ns4.fakesite.example</host:name>
</host:info> </host:info>
</info> </info>
<clTRID>ABC-12345</clTRID> <clTRID>ABC-12345</clTRID>

View file

@ -1,10 +0,0 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<info>
<host:info xmlns:host="urn:ietf:params:xml:ns:host-1.0">
<host:name>ns2.example.external</host:name>
</host:info>
</info>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -0,0 +1,25 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="1000">
<msg>Command completed successfully</msg>
</result>
<resData>
<host:infData
xmlns:host="urn:ietf:params:xml:ns:host-1.0">
<host:name>ns4.fakesite.example</host:name>
<host:roid>NS1_EXAMPLE1-REP</host:roid>
<host:status s="ok"/>
<host:addr ip="v4">192.0.2.30</host:addr>
<host:addr ip="v4">192.0.2.3</host:addr>
<host:addr ip="v6">1080::8:800:200c:417b</host:addr>
<host:clID>NewRegistrar</host:clID>
<host:crID>NewRegistrar</host:crID>
<host:crDate>2000-06-09T00:01:00Z</host:crDate>
</host:infData>
</resData>
<trID>
<clTRID>ABC-12345</clTRID>
<svTRID>server-trid</svTRID>
</trID>
</response>
</epp>

View file

@ -0,0 +1,25 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="1000">
<msg>Command completed successfully</msg>
</result>
<resData>
<host:infData
xmlns:host="urn:ietf:params:xml:ns:host-1.0">
<host:name>ns3.fakesite.example</host:name>
<host:roid>NS1_EXAMPLE1-REP</host:roid>
<host:status s="ok"/>
<host:addr ip="v4">192.0.2.29</host:addr>
<host:addr ip="v4">192.0.2.2</host:addr>
<host:addr ip="v6">1080::8:800:200c:417a</host:addr>
<host:clID>NewRegistrar</host:clID>
<host:crID>NewRegistrar</host:crID>
<host:crDate>2000-06-06T00:01:00Z</host:crDate>
</host:infData>
</resData>
<trID>
<clTRID>ABC-12345</clTRID>
<svTRID>server-trid</svTRID>
</trID>
</response>
</epp>

View file

@ -9,13 +9,12 @@
<host:name>ns3.fakesite.example</host:name> <host:name>ns3.fakesite.example</host:name>
<host:roid>NS1_EXAMPLE1-REP</host:roid> <host:roid>NS1_EXAMPLE1-REP</host:roid>
<host:status s="ok"/> <host:status s="ok"/>
<host:status s="linked"/>
<host:addr ip="v4">192.0.2.29</host:addr> <host:addr ip="v4">192.0.2.29</host:addr>
<host:addr ip="v4">192.0.2.2</host:addr> <host:addr ip="v4">192.0.2.2</host:addr>
<host:addr ip="v6">1080::8:800:200c:417a</host:addr> <host:addr ip="v6">1080::8:800:200c:417a</host:addr>
<host:clID>NewRegistrar</host:clID> <host:clID>NewRegistrar</host:clID>
<host:crID>NewRegistrar</host:crID> <host:crID>NewRegistrar</host:crID>
<host:crDate>2000-06-01T00:02:00.000Z</host:crDate> <host:crDate>2000-06-02T00:01:00Z</host:crDate>
<host:upID>NewRegistrar</host:upID> <host:upID>NewRegistrar</host:upID>
<host:upDate>2002-05-30T01:01:00Z</host:upDate> <host:upDate>2002-05-30T01:01:00Z</host:upDate>
</host:infData> </host:infData>

View file

@ -1,7 +1,7 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0"> <epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response> <response>
<result code="2302"> <result code="2302">
<msg>Object with given ID (ns2.example.external) already exists</msg> <msg>Object with given ID (ns4.fakesite.example) already exists</msg>
</result> </result>
<trID> <trID>
<clTRID>ABC-12345</clTRID> <clTRID>ABC-12345</clTRID>

View file

@ -0,0 +1,16 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<update>
<host:update xmlns:host="urn:ietf:params:xml:ns:host-1.0">
<host:name>ns3.fakesite.example</host:name>
<host:add>
<host:status s="clientUpdateProhibited"/>
</host:add>
<host:chg>
<host:name>ns4.fakesite.example</host:name>
</host:chg>
</host:update>
</update>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -2,12 +2,7 @@
<command> <command>
<update> <update>
<host:update xmlns:host="urn:ietf:params:xml:ns:host-1.0"> <host:update xmlns:host="urn:ietf:params:xml:ns:host-1.0">
<host:name>ns1.example.external</host:name> <host:name>ns1.example.tld</host:name>
<host:add>
<host:addr ip="v4">192.0.2.2</host:addr>
<host:addr ip="v4">192.0.2.29</host:addr>
<host:addr ip="v6">1080:0:0:0:8:800:200C:417A</host:addr>
</host:add>
<host:rem/> <host:rem/>
<host:chg> <host:chg>
<host:name>ns3.fakesite.example</host:name> <host:name>ns3.fakesite.example</host:name>

View file

@ -50,6 +50,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.net.InetAddresses;
import com.googlecode.objectify.Key; import com.googlecode.objectify.Key;
import com.googlecode.objectify.VoidWork; import com.googlecode.objectify.VoidWork;
import com.googlecode.objectify.Work; import com.googlecode.objectify.Work;
@ -274,6 +275,8 @@ public class DatastoreHelper {
newHostResource(hostName) newHostResource(hostName)
.asBuilder() .asBuilder()
.setSuperordinateDomain(Key.create(superordinateDomain)) .setSuperordinateDomain(Key.create(superordinateDomain))
.setInetAddresses(
ImmutableSet.of(InetAddresses.forString("1080:0:0:0:8:800:200C:417A")))
.build()); .build());
} }