mirror of
https://github.com/google/nomulus.git
synced 2025-05-13 07:57:13 +02:00
Add domain_lock nomulus command
This command is used by registry operators to apply registry locks to domain names. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=176549874
This commit is contained in:
parent
8cd3979385
commit
f041b1bac0
18 changed files with 453 additions and 35 deletions
|
@ -135,7 +135,11 @@ import org.joda.time.DateTime;
|
|||
public final class DomainUpdateFlow implements TransactionalFlow {
|
||||
|
||||
/**
|
||||
* Note that CLIENT_UPDATE_PROHIBITED is intentionally not in this list. This is because it
|
||||
* A list of {@link StatusValue}s that prohibit updates.
|
||||
*
|
||||
* <p>Superusers can override these statuses and perform updates anyway.
|
||||
*
|
||||
* <p>Note that CLIENT_UPDATE_PROHIBITED is intentionally not in this list. This is because it
|
||||
* requires special checking, since you must be able to clear the status off the object with an
|
||||
* update.
|
||||
*/
|
||||
|
@ -208,12 +212,12 @@ public final class DomainUpdateFlow implements TransactionalFlow {
|
|||
/** Fail if the object doesn't exist or was deleted. */
|
||||
private void verifyUpdateAllowed(Update command, DomainResource existingDomain, DateTime now)
|
||||
throws EppException {
|
||||
verifyNoDisallowedStatuses(existingDomain, UPDATE_DISALLOWED_STATUSES);
|
||||
verifyOptionalAuthInfo(authInfo, existingDomain);
|
||||
AddRemove add = command.getInnerAdd();
|
||||
AddRemove remove = command.getInnerRemove();
|
||||
String tld = existingDomain.getTld();
|
||||
if (!isSuperuser) {
|
||||
verifyNoDisallowedStatuses(existingDomain, UPDATE_DISALLOWED_STATUSES);
|
||||
verifyResourceOwnership(clientId, existingDomain);
|
||||
verifyClientUpdateNotProhibited(command, existingDomain);
|
||||
verifyAllStatusesAreClientSettable(union(add.getStatusValues(), remove.getStatusValues()));
|
||||
|
|
|
@ -43,11 +43,9 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
|||
* @see <a href="https://tools.ietf.org/html/rfc5731#section-2.3">RFC 5731 (Domain) Section 2.3</a>
|
||||
* @see <a href="https://tools.ietf.org/html/rfc5732#section-2.3">RFC 5732 (Host) Section 2.3</a>
|
||||
* @see <a href="https://tools.ietf.org/html/rfc5733#section-2.2">RFC 5733 (Contact) Section 2.2</a>
|
||||
|
||||
*/
|
||||
@XmlJavaTypeAdapter(StatusValueAdapter.class)
|
||||
public enum StatusValue implements EppEnum {
|
||||
|
||||
CLIENT_DELETE_PROHIBITED(AllowedOn.ALL),
|
||||
CLIENT_HOLD(AllowedOn.ALL),
|
||||
CLIENT_RENEW_PROHIBITED(AllowedOn.ALL),
|
||||
|
@ -114,10 +112,17 @@ public enum StatusValue implements EppEnum {
|
|||
*/
|
||||
PENDING_UPDATE(AllowedOn.NONE),
|
||||
|
||||
|
||||
/** A non-client-settable status that prevents deletes of EPP resources. */
|
||||
SERVER_DELETE_PROHIBITED(AllowedOn.ALL),
|
||||
|
||||
SERVER_HOLD(AllowedOn.ALL),
|
||||
SERVER_RENEW_PROHIBITED(AllowedOn.ALL),
|
||||
|
||||
/** A non-client-settable status that prevents transfers of EPP resources. */
|
||||
SERVER_TRANSFER_PROHIBITED(AllowedOn.ALL),
|
||||
|
||||
/** A non-client-settable status that prevents updates of EPP resources, except by superusers. */
|
||||
SERVER_UPDATE_PROHIBITED(AllowedOn.ALL);
|
||||
|
||||
private final String xmlName = UPPER_UNDERSCORE.to(LOWER_CAMEL, name());
|
||||
|
|
76
java/google/registry/tools/LockDomainCommand.java
Normal file
76
java/google/registry/tools/LockDomainCommand.java
Normal file
|
@ -0,0 +1,76 @@
|
|||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||
import static google.registry.util.FormattingLogger.getLoggerForCallerClass;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.template.soy.data.SoyMapData;
|
||||
import google.registry.model.domain.DomainResource;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.tools.soy.DomainUpdateSoyInfo;
|
||||
import google.registry.util.FormattingLogger;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* A command to registry lock domain names via EPP.
|
||||
*
|
||||
* <p>A registry lock consists of server-side statuses preventing deletes, updates, and transfers.
|
||||
*/
|
||||
@Parameters(separators = " =", commandDescription = "Registry lock a domain via EPP.")
|
||||
public class LockDomainCommand extends LockOrUnlockDomainCommand {
|
||||
|
||||
private static final FormattingLogger logger = getLoggerForCallerClass();
|
||||
|
||||
@Override
|
||||
protected void initMutatingEppToolCommand() throws Exception {
|
||||
// Project all domains as of the same time so that argument order doesn't affect behavior.
|
||||
DateTime now = DateTime.now(UTC);
|
||||
for (String domain : getDomains()) {
|
||||
DomainResource domainResource = loadByForeignKey(DomainResource.class, domain, now);
|
||||
checkArgument(domainResource != null, "Domain '%s' does not exist", domain);
|
||||
ImmutableSet<StatusValue> statusesToAdd =
|
||||
Sets.difference(REGISTRY_LOCK_STATUSES, domainResource.getStatusValues()).immutableCopy();
|
||||
if (statusesToAdd.isEmpty()) {
|
||||
logger.infofmt("Domain '%s' is already locked and needs no updates.", domain);
|
||||
continue;
|
||||
}
|
||||
|
||||
setSoyTemplate(DomainUpdateSoyInfo.getInstance(), DomainUpdateSoyInfo.DOMAINUPDATE);
|
||||
addSoyRecord(
|
||||
clientId,
|
||||
new SoyMapData(
|
||||
"domain", domain,
|
||||
"add", true,
|
||||
"addNameservers", ImmutableList.of(),
|
||||
"addAdmins", ImmutableList.of(),
|
||||
"addTechs", ImmutableList.of(),
|
||||
"addStatuses", statusesToAdd.stream().map(StatusValue::getXmlName).collect(toList()),
|
||||
"remove", false,
|
||||
"removeNameservers", ImmutableList.of(),
|
||||
"removeAdmins", ImmutableList.of(),
|
||||
"removeTechs", ImmutableList.of(),
|
||||
"removeStatuses", ImmutableList.of(),
|
||||
"change", false));
|
||||
}
|
||||
}
|
||||
}
|
60
java/google/registry/tools/LockOrUnlockDomainCommand.java
Normal file
60
java/google/registry/tools/LockOrUnlockDomainCommand.java
Normal file
|
@ -0,0 +1,60 @@
|
|||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.model.eppcommon.StatusValue.SERVER_DELETE_PROHIBITED;
|
||||
import static google.registry.model.eppcommon.StatusValue.SERVER_TRANSFER_PROHIBITED;
|
||||
import static google.registry.model.eppcommon.StatusValue.SERVER_UPDATE_PROHIBITED;
|
||||
import static google.registry.util.CollectionUtils.findDuplicates;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import java.util.List;
|
||||
|
||||
/** Shared base class for commands to registry lock or unlock a domain via EPP. */
|
||||
public abstract class LockOrUnlockDomainCommand extends MutatingEppToolCommand {
|
||||
|
||||
protected static final ImmutableSet<StatusValue> REGISTRY_LOCK_STATUSES =
|
||||
ImmutableSet.of(
|
||||
SERVER_DELETE_PROHIBITED, SERVER_TRANSFER_PROHIBITED, SERVER_UPDATE_PROHIBITED);
|
||||
|
||||
@Parameter(
|
||||
names = {"-c", "--client"},
|
||||
description = "Client identifier of the registrar to execute the command as",
|
||||
required = true
|
||||
)
|
||||
String clientId;
|
||||
|
||||
@Parameter(description = "Names of the domains", required = true)
|
||||
private List<String> mainParameters;
|
||||
|
||||
protected ImmutableSet<String> getDomains() {
|
||||
return ImmutableSet.copyOf(mainParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initEppToolCommand() throws Exception {
|
||||
// Superuser status is required to update registry lock statuses.
|
||||
superuser = true;
|
||||
String duplicates = Joiner.on(", ").join(findDuplicates(mainParameters));
|
||||
checkArgument(duplicates.isEmpty(), "Duplicate domain arguments found: '%s'", duplicates);
|
||||
initMutatingEppToolCommand();
|
||||
System.out.println(
|
||||
"== ENSURE THAT YOU HAVE AUTHENTICATED THE REGISTRAR BEFORE RUNNING THIS COMMAND ==");
|
||||
}
|
||||
}
|
|
@ -95,6 +95,7 @@ public final class RegistryTool {
|
|||
.put("list_tlds", ListTldsCommand.class)
|
||||
.put("load_snapshot", LoadSnapshotCommand.class)
|
||||
.put("load_test", LoadTestCommand.class)
|
||||
.put("lock_domain", LockDomainCommand.class)
|
||||
.put("login", LoginCommand.class)
|
||||
.put("logout", LogoutCommand.class)
|
||||
.put("make_billing_tables", MakeBillingTablesCommand.class)
|
||||
|
|
|
@ -94,9 +94,7 @@ interface RegistryToolComponent {
|
|||
void inject(SendEscrowReportToIcannCommand command);
|
||||
void inject(SetupOteCommand command);
|
||||
void inject(UpdateCursorsCommand command);
|
||||
|
||||
void inject(UpdateDomainCommand command);
|
||||
|
||||
void inject(UpdateKmsKeyringCommand command);
|
||||
void inject(UpdateTldCommand command);
|
||||
void inject(ValidateEscrowDepositCommand command);
|
||||
|
|
|
@ -17,6 +17,7 @@ package google.registry.tools;
|
|||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||
import static google.registry.model.eppcommon.StatusValue.SERVER_UPDATE_PROHIBITED;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
|
@ -127,6 +128,11 @@ final class UpdateDomainCommand extends CreateOrUpdateDomainCommand {
|
|||
DateTime now = DateTime.now(UTC);
|
||||
DomainResource domainResource = loadByForeignKey(DomainResource.class, domain, now);
|
||||
checkArgument(domainResource != null, "Domain '%s' does not exist", domain);
|
||||
checkArgument(
|
||||
!domainResource.getStatusValues().contains(SERVER_UPDATE_PROHIBITED),
|
||||
"The domain '%s' has status SERVER_UPDATE_PROHIBITED. Verify that you are allowed "
|
||||
+ "to make updates, and if so, use the domain_unlock command to enable updates.",
|
||||
domain);
|
||||
if (!nameservers.isEmpty()) {
|
||||
ImmutableSortedSet<String> existingNameservers =
|
||||
domainResource.loadNameserverFullyQualifiedHostNames();
|
||||
|
|
|
@ -18,6 +18,7 @@ import static com.google.common.collect.Sets.union;
|
|||
import static com.google.common.io.BaseEncoding.base16;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||
import static google.registry.model.eppcommon.StatusValue.SERVER_UPDATE_PROHIBITED;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.testing.DatastoreHelper.assertBillingEvents;
|
||||
import static google.registry.testing.DatastoreHelper.assertNoBillingEvents;
|
||||
|
@ -34,6 +35,7 @@ import static google.registry.testing.DatastoreHelper.persistReservedList;
|
|||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.testing.DomainResourceSubject.assertAboutDomains;
|
||||
import static google.registry.testing.HistoryEntrySubject.assertAboutHistoryEntries;
|
||||
import static google.registry.testing.JUnitBackports.expectThrows;
|
||||
import static google.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
|
||||
|
@ -892,9 +894,46 @@ public class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow,
|
|||
persistReferencedEntities();
|
||||
persistDomain();
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE,
|
||||
UserPrivileges.SUPERUSER,
|
||||
readFile("domain_update_response.xml"));
|
||||
CommitMode.LIVE, UserPrivileges.SUPERUSER, readFile("domain_update_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_serverUpdateProhibited_prohibitsNonSuperuserUpdates() throws Exception {
|
||||
persistReferencedEntities();
|
||||
persistResource(
|
||||
newDomainResource(getUniqueIdFromCommand())
|
||||
.asBuilder()
|
||||
.addStatusValue(SERVER_UPDATE_PROHIBITED)
|
||||
.build());
|
||||
Exception e = expectThrows(ResourceStatusProhibitsOperationException.class, this::runFlow);
|
||||
assertThat(e).hasMessageThat().containsMatch("serverUpdateProhibited");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_serverUpdateProhibited_allowsSuperuserUpdates() throws Exception {
|
||||
persistReferencedEntities();
|
||||
persistResource(persistDomain().asBuilder().addStatusValue(SERVER_UPDATE_PROHIBITED).build());
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE, UserPrivileges.SUPERUSER, readFile("domain_update_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_serverUpdateProhibited_notSettableWithoutSuperuser() throws Exception {
|
||||
setEppInput("domain_update_add_registry_lock.xml");
|
||||
persistReferencedEntities();
|
||||
persistDomain();
|
||||
Exception e = expectThrows(StatusNotClientSettableException.class, this::runFlow);
|
||||
assertThat(e).hasMessageThat().containsMatch("serverUpdateProhibited");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_serverUpdateProhibited_isSettableWithSuperuser() throws Exception {
|
||||
setEppInput("domain_update_add_registry_lock.xml");
|
||||
persistReferencedEntities();
|
||||
persistDomain();
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE, UserPrivileges.SUPERUSER, readFile("domain_update_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -915,7 +954,7 @@ public class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow,
|
|||
persistReferencedEntities();
|
||||
persistResource(
|
||||
newDomainResource(getUniqueIdFromCommand()).asBuilder()
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.SERVER_UPDATE_PROHIBITED))
|
||||
.setStatusValues(ImmutableSet.of(SERVER_UPDATE_PROHIBITED))
|
||||
.build());
|
||||
thrown.expect(ResourceStatusProhibitsOperationException.class, "serverUpdateProhibited");
|
||||
runFlow();
|
||||
|
@ -1398,7 +1437,7 @@ public class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow,
|
|||
doSuccessfulTest();
|
||||
assertAboutDomains()
|
||||
.that(reloadResourceByForeignKey())
|
||||
.hasStatusValue(StatusValue.SERVER_UPDATE_PROHIBITED)
|
||||
.hasStatusValue(SERVER_UPDATE_PROHIBITED)
|
||||
.and()
|
||||
.hasStatusValue(StatusValue.SERVER_TRANSFER_PROHIBITED);
|
||||
}
|
||||
|
|
29
javatests/google/registry/flows/domain/testdata/domain_update_add_registry_lock.xml
vendored
Normal file
29
javatests/google/registry/flows/domain/testdata/domain_update_add_registry_lock.xml
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<update>
|
||||
<domain:update
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example.tld</domain:name>
|
||||
<domain:add>
|
||||
<domain:ns>
|
||||
<domain:hostObj>ns2.example.foo</domain:hostObj>
|
||||
</domain:ns>
|
||||
<domain:status s="serverUpdateProhibited"
|
||||
lang="en">Add registry lock for domain.</domain:status>
|
||||
</domain:add>
|
||||
<domain:rem>
|
||||
<domain:ns>
|
||||
<domain:hostObj>ns1.example.foo</domain:hostObj>
|
||||
</domain:ns>
|
||||
</domain:rem>
|
||||
<domain:chg>
|
||||
<domain:registrant>sh8013</domain:registrant>
|
||||
<domain:authInfo>
|
||||
<domain:pw>2BARfoo</domain:pw>
|
||||
</domain:authInfo>
|
||||
</domain:chg>
|
||||
</domain:update>
|
||||
</update>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
|
@ -20,9 +20,7 @@ import static google.registry.util.ResourceUtils.readResourceUtf8;
|
|||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Contains helper methods for dealing with test data.
|
||||
*/
|
||||
/** Contains helper methods for dealing with test data. */
|
||||
public final class TestDataHelper {
|
||||
|
||||
/**
|
||||
|
@ -31,7 +29,11 @@ public final class TestDataHelper {
|
|||
*/
|
||||
public static String loadFileWithSubstitutions(
|
||||
Class<?> context, String filename, Map<String, String> substitutions) {
|
||||
String fileContents = readResourceUtf8(context, "testdata/" + filename);
|
||||
return applySubstitutions(readResourceUtf8(context, "testdata/" + filename), substitutions);
|
||||
}
|
||||
|
||||
/** Applies the given substitutions to the given string and returns the result. */
|
||||
public static String applySubstitutions(String fileContents, Map<String, String> substitutions) {
|
||||
for (Entry<String, String> entry : nullToEmpty(substitutions).entrySet()) {
|
||||
fileContents = fileContents.replaceAll("%" + entry.getKey() + "%", entry.getValue());
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.collect.Iterables.concat;
|
||||
import static com.google.common.collect.Iterables.toArray;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
|
@ -22,6 +23,8 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
|||
import com.beust.jcommander.JCommander;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.ObjectArrays;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
|
@ -95,11 +98,21 @@ public abstract class CommandTestCase<C extends Command> {
|
|||
runCommandInEnvironment(RegistryToolEnvironment.UNITTEST, args);
|
||||
}
|
||||
|
||||
protected void runCommand(Iterable<String> args) throws Exception {
|
||||
runCommandInEnvironment(
|
||||
RegistryToolEnvironment.UNITTEST, Iterables.toArray(args, String.class));
|
||||
}
|
||||
|
||||
/** Adds "--force" as the first parameter, then runs the command. */
|
||||
protected void runCommandForced(String... args) throws Exception {
|
||||
runCommand(ObjectArrays.concat("--force", args));
|
||||
}
|
||||
|
||||
/** Adds "--force" as the first parameter, then runs the command. */
|
||||
protected void runCommandForced(Iterable<String> args) throws Exception {
|
||||
runCommand(concat(ImmutableList.of("--force"), args));
|
||||
}
|
||||
|
||||
/** Writes the data to a named temporary file and then returns a path to the file. */
|
||||
String writeToNamedTmpFile(String filename, byte[] data) throws IOException {
|
||||
File tmpFile = tmpDir.newFile(filename);
|
||||
|
|
|
@ -14,12 +14,14 @@
|
|||
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.xml.XmlTestUtils.assertXmlEquals;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
@ -27,6 +29,7 @@ import com.google.common.net.MediaType;
|
|||
import google.registry.tools.ServerSideCommand.Connection;
|
||||
import google.registry.tools.server.ToolsTestData;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
@ -67,29 +70,34 @@ public class EppToolVerifier {
|
|||
return new EppToolVerifier(connection, clientId, superuser, true);
|
||||
}
|
||||
|
||||
void verifySent(String... xmlToMatch) throws Exception {
|
||||
void verifySent(String... expectedXmlFiles) throws Exception {
|
||||
verifySentContents(
|
||||
Arrays.stream(expectedXmlFiles).map(ToolsTestData::loadUtf8).collect(toImmutableList()));
|
||||
}
|
||||
|
||||
void verifySentContents(List<String> expectedXmlContents) throws Exception {
|
||||
ArgumentCaptor<byte[]> params = ArgumentCaptor.forClass(byte[].class);
|
||||
verify(connection, times(xmlToMatch.length)).send(
|
||||
verify(connection, times(expectedXmlContents.size())).send(
|
||||
eq("/_dr/epptool"),
|
||||
eq(ImmutableMap.<String, Object>of()),
|
||||
eq(MediaType.FORM_DATA),
|
||||
params.capture());
|
||||
List<byte[]> capturedParams = params.getAllValues();
|
||||
assertThat(capturedParams).hasSize(xmlToMatch.length);
|
||||
for (int i = 0; i < xmlToMatch.length; i++) {
|
||||
String xml = xmlToMatch[i];
|
||||
assertThat(capturedParams).hasSize(expectedXmlContents.size());
|
||||
for (int i = 0; i < expectedXmlContents.size(); i++) {
|
||||
byte[] capturedParam = capturedParams.get(i);
|
||||
Map<String, String> map =
|
||||
Splitter.on('&')
|
||||
.withKeyValueSeparator('=')
|
||||
.split(new String(capturedParam, UTF_8));
|
||||
Splitter.on('&').withKeyValueSeparator('=').split(new String(capturedParam, UTF_8));
|
||||
assertThat(map).hasSize(4);
|
||||
assertXmlEquals(
|
||||
ToolsTestData.loadUtf8(xml),
|
||||
URLDecoder.decode(map.get("xml"), UTF_8.toString()));
|
||||
expectedXmlContents.get(i), URLDecoder.decode(map.get("xml"), UTF_8.toString()));
|
||||
assertThat(map).containsEntry("dryRun", Boolean.toString(dryRun));
|
||||
assertThat(map).containsEntry("clientId", clientId);
|
||||
assertThat(map).containsEntry("superuser", Boolean.toString(superuser));
|
||||
}
|
||||
}
|
||||
|
||||
void verifyNothingSent() {
|
||||
verifyZeroInteractions(connection);
|
||||
}
|
||||
}
|
||||
|
|
112
javatests/google/registry/tools/LockDomainCommandTest.java
Normal file
112
javatests/google/registry/tools/LockDomainCommandTest.java
Normal file
|
@ -0,0 +1,112 @@
|
|||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.eppcommon.StatusValue.SERVER_TRANSFER_PROHIBITED;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainResource;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.testing.JUnitBackports.expectThrows;
|
||||
import static google.registry.testing.TestDataHelper.applySubstitutions;
|
||||
import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STATUSES;
|
||||
import static google.registry.tools.server.ToolsTestData.loadUtf8;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link LockDomainCommand}. */
|
||||
public class LockDomainCommandTest extends EppToolCommandTestCase<LockDomainCommand> {
|
||||
|
||||
/** Gets an overridden eppVerifier that has superuser set to true on it. */
|
||||
@Override
|
||||
EppToolVerifier eppVerifier() {
|
||||
return new EppToolVerifier()
|
||||
.withConnection(connection)
|
||||
.withClientId("NewRegistrar")
|
||||
.asSuperuser();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_sendsCorrectEppXml() throws Exception {
|
||||
persistActiveDomain("example.tld");
|
||||
runCommandForced("--client=NewRegistrar", "example.tld");
|
||||
eppVerifier()
|
||||
.verifySentContents(
|
||||
ImmutableList.of(
|
||||
loadUtf8("domain_lock.xml", ImmutableMap.of("DOMAIN", "example.tld"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_partiallyUpdatesStatuses() throws Exception {
|
||||
persistResource(
|
||||
newDomainResource("example.tld")
|
||||
.asBuilder()
|
||||
.addStatusValue(SERVER_TRANSFER_PROHIBITED)
|
||||
.build());
|
||||
runCommandForced("--client=NewRegistrar", "example.tld");
|
||||
eppVerifier().verifySent("domain_lock_partial_statuses.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_manyDomains() throws Exception {
|
||||
List<String> params = new ArrayList<>();
|
||||
List<String> expectedXmls = new ArrayList<>();
|
||||
params.add("--client=NewRegistrar");
|
||||
String updateDomainXml = loadUtf8("domain_lock.xml");
|
||||
// Create 26 domains -- one more than the number of entity groups allowed in a transaction (in
|
||||
// case that was going to be the failure point).
|
||||
for (int n = 0; n < 26; n++) {
|
||||
String domain = String.format("domain%d.tld", n);
|
||||
persistActiveDomain(domain);
|
||||
params.add(domain);
|
||||
expectedXmls.add(applySubstitutions(updateDomainXml, ImmutableMap.of("DOMAIN", domain)));
|
||||
}
|
||||
runCommandForced(params);
|
||||
eppVerifier().verifySentContents(expectedXmls);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_domainDoesntExist() throws Exception {
|
||||
IllegalArgumentException e =
|
||||
expectThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> runCommandForced("--client=NewRegistrar", "missing.tld"));
|
||||
assertThat(e).hasMessageThat().isEqualTo("Domain 'missing.tld' does not exist");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_alreadyLockedDomain_performsNoAction() throws Exception {
|
||||
persistResource(
|
||||
newDomainResource("example.tld")
|
||||
.asBuilder()
|
||||
.addStatusValues(REGISTRY_LOCK_STATUSES)
|
||||
.build());
|
||||
runCommandForced("--client=NewRegistrar", "example.tld");
|
||||
eppVerifier().verifyNothingSent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_duplicateDomainsAreSpecified() throws Exception {
|
||||
IllegalArgumentException e =
|
||||
expectThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> runCommandForced("--client=NewRegistrar", "dupe.tld", "dupe.tld"));
|
||||
assertThat(e).hasMessageThat().isEqualTo("Duplicate domain arguments found: 'dupe.tld'");
|
||||
}
|
||||
}
|
|
@ -14,10 +14,13 @@
|
|||
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.eppcommon.StatusValue.SERVER_UPDATE_PROHIBITED;
|
||||
import static google.registry.testing.DatastoreHelper.newContactResource;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainResource;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveHost;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.testing.JUnitBackports.expectThrows;
|
||||
|
||||
import com.beust.jcommander.ParameterException;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
@ -151,7 +154,7 @@ public class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomain
|
|||
.asBuilder()
|
||||
.setStatusValues(
|
||||
ImmutableSet.of(
|
||||
StatusValue.CLIENT_RENEW_PROHIBITED, StatusValue.SERVER_UPDATE_PROHIBITED))
|
||||
StatusValue.CLIENT_RENEW_PROHIBITED, StatusValue.SERVER_TRANSFER_PROHIBITED))
|
||||
.setNameservers(nameservers)
|
||||
.build());
|
||||
|
||||
|
@ -160,6 +163,32 @@ public class UpdateDomainCommandTest extends EppToolCommandTestCase<UpdateDomain
|
|||
eppVerifier().verifySent("domain_update_set_statuses.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_cantUpdateRegistryLockedDomainEvenAsSuperuser() throws Exception {
|
||||
HostResource host = persistActiveHost("ns1.zdns.google");
|
||||
ImmutableSet<Key<HostResource>> nameservers = ImmutableSet.of(Key.create(host));
|
||||
persistResource(
|
||||
newDomainResource("example.tld")
|
||||
.asBuilder()
|
||||
.setStatusValues(ImmutableSet.of(SERVER_UPDATE_PROHIBITED))
|
||||
.setNameservers(nameservers)
|
||||
.build());
|
||||
|
||||
Exception e =
|
||||
expectThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
runCommandForced(
|
||||
"--client=NewRegistrar",
|
||||
"--statuses=clientRenewProhibited,serverHold",
|
||||
"--superuser",
|
||||
"example.tld"));
|
||||
assertThat(e)
|
||||
.hasMessageThat()
|
||||
.containsMatch("The domain 'example.tld' has status SERVER_UPDATE_PROHIBITED");
|
||||
eppVerifier().verifyNothingSent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_duplicateDomains() throws Exception {
|
||||
thrown.expect(IllegalArgumentException.class, "Duplicate arguments found");
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
|
||||
package google.registry.tools.server;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.io.ByteSource;
|
||||
import com.google.common.io.Resources;
|
||||
import java.io.IOException;
|
||||
import google.registry.testing.TestDataHelper;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
|
||||
/** Utility class providing easy access to contents of the {@code testdata/} directory. */
|
||||
public final class ToolsTestData {
|
||||
|
@ -30,12 +30,17 @@ public final class ToolsTestData {
|
|||
}
|
||||
|
||||
/**
|
||||
* Loads data from file in {@code tools/server/testdata/} as a String (assuming file is UTF-8).
|
||||
*
|
||||
* @throws IOException if the file couldn't be loaded from the jar.
|
||||
* Loads data from file in {@code tools/server/testdata/} as a UTF-8 String.
|
||||
*/
|
||||
public static String loadUtf8(String filename) throws IOException {
|
||||
return Resources.asCharSource(getUrl(filename), UTF_8).read();
|
||||
public static String loadUtf8(String filename) {
|
||||
return loadUtf8(filename, ImmutableMap.of());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads data from file in {@code tools/server/testdata/} as a UTF-8 String, with substitutions.
|
||||
*/
|
||||
public static String loadUtf8(String filename, Map<String, String> substitutions) {
|
||||
return TestDataHelper.loadFileWithSubstitutions(ToolsTestData.class, filename, substitutions);
|
||||
}
|
||||
|
||||
private static URL getUrl(String filename) {
|
||||
|
|
16
javatests/google/registry/tools/server/testdata/domain_lock.xml
vendored
Normal file
16
javatests/google/registry/tools/server/testdata/domain_lock.xml
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<update>
|
||||
<domain:update xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>%DOMAIN%</domain:name>
|
||||
<domain:add>
|
||||
<domain:status s="serverDeleteProhibited"/>
|
||||
<domain:status s="serverTransferProhibited"/>
|
||||
<domain:status s="serverUpdateProhibited"/>
|
||||
</domain:add>
|
||||
</domain:update>
|
||||
</update>
|
||||
<clTRID>RegistryTool</clTRID>
|
||||
</command>
|
||||
</epp>
|
15
javatests/google/registry/tools/server/testdata/domain_lock_partial_statuses.xml
vendored
Normal file
15
javatests/google/registry/tools/server/testdata/domain_lock_partial_statuses.xml
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<update>
|
||||
<domain:update xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example.tld</domain:name>
|
||||
<domain:add>
|
||||
<domain:status s="serverDeleteProhibited"/>
|
||||
<domain:status s="serverUpdateProhibited"/>
|
||||
</domain:add>
|
||||
</domain:update>
|
||||
</update>
|
||||
<clTRID>RegistryTool</clTRID>
|
||||
</command>
|
||||
</epp>
|
|
@ -9,7 +9,7 @@
|
|||
<domain:status s="serverHold"/>
|
||||
</domain:add>
|
||||
<domain:rem>
|
||||
<domain:status s="serverUpdateProhibited"/>
|
||||
<domain:status s="serverTransferProhibited"/>
|
||||
</domain:rem>
|
||||
</domain:update>
|
||||
</update>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue