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:
mcilwain 2017-11-21 13:05:32 -08:00 committed by jianglai
parent 8cd3979385
commit f041b1bac0
18 changed files with 453 additions and 35 deletions

View file

@ -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()));

View file

@ -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());

View 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));
}
}
}

View 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 ==");
}
}

View file

@ -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)

View file

@ -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);

View file

@ -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();