diff --git a/java/google/registry/model/registrar/Registrar.java b/java/google/registry/model/registrar/Registrar.java index 46bc37295..0fb34cf63 100644 --- a/java/google/registry/model/registrar/Registrar.java +++ b/java/google/registry/model/registrar/Registrar.java @@ -561,6 +561,16 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable .collect(toImmutableSortedSet(CONTACT_EMAIL_COMPARATOR)); } + /** + * Returns the {@link RegistrarContact} that is the WHOIS abuse contact for this registrar, or + * empty if one does not exist. + */ + public Optional getWhoisAbuseContact() { + return getContacts().stream() + .filter(RegistrarContact::getVisibleInDomainWhoisAsAbuse) + .findFirst(); + } + private Iterable getContactsIterable() { return ofy().load().type(RegistrarContact.class).ancestor(Registrar.this); } diff --git a/java/google/registry/tools/CreateOrUpdateRegistrarCommand.java b/java/google/registry/tools/CreateOrUpdateRegistrarCommand.java index 918f98dae..0c8903fd8 100644 --- a/java/google/registry/tools/CreateOrUpdateRegistrarCommand.java +++ b/java/google/registry/tools/CreateOrUpdateRegistrarCommand.java @@ -258,6 +258,8 @@ abstract class CreateOrUpdateRegistrarCommand extends MutatingCommand { @Nullable abstract Registrar getOldRegistrar(String clientId); + abstract void checkModifyAllowedTlds(@Nullable Registrar oldRegistrar); + protected void initRegistrarCommand() {} @Override @@ -300,9 +302,12 @@ abstract class CreateOrUpdateRegistrarCommand extends MutatingCommand { if (driveFolderId != null) { builder.setDriveFolderId(driveFolderId.orElse(null)); } + if (!allowedTlds.isEmpty() || !addAllowedTlds.isEmpty()) { + checkModifyAllowedTlds(oldRegistrar); + } if (!allowedTlds.isEmpty()) { - checkArgument(addAllowedTlds.isEmpty(), - "Can't specify both --allowedTlds and --addAllowedTlds"); + checkArgument( + addAllowedTlds.isEmpty(), "Can't specify both --allowedTlds and --addAllowedTlds"); ImmutableSet.Builder allowedTldsBuilder = new ImmutableSet.Builder<>(); for (String allowedTld : allowedTlds) { allowedTldsBuilder.add(canonicalizeDomainName(allowedTld)); diff --git a/java/google/registry/tools/CreateRegistrarCommand.java b/java/google/registry/tools/CreateRegistrarCommand.java index 06336b09f..67a7203fa 100644 --- a/java/google/registry/tools/CreateRegistrarCommand.java +++ b/java/google/registry/tools/CreateRegistrarCommand.java @@ -30,6 +30,7 @@ import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Streams; +import google.registry.config.RegistryEnvironment; import google.registry.model.registrar.Registrar; import java.util.ArrayList; import java.util.List; @@ -86,14 +87,28 @@ final class CreateRegistrarCommand extends CreateOrUpdateRegistrarCommand .filter(registrar -> normalizeClientId(registrar.getClientId()).equals(clientId)) .collect(toCollection(ArrayList::new)); if (!collisions.isEmpty()) { - throw new IllegalArgumentException(String.format( - "The registrar client identifier %s normalizes identically to existing registrar %s", - clientId, - collisions.get(0).getClientId())); + throw new IllegalArgumentException( + String.format( + "The registrar client identifier %s normalizes identically to existing registrar %s", + clientId, collisions.get(0).getClientId())); } return null; } + @Override + void checkModifyAllowedTlds(@Nullable Registrar oldRegistrar) { + // When creating a registrar, only allow allowed-TLD modification if we're in a non-PRODUCTION + // environment and/or the registrar is not REAL + checkArgument( + !RegistryEnvironment.PRODUCTION.equals(RegistryEnvironment.get()) + || !Registrar.Type.REAL.equals(registrarType), + "Cannot add allowed TLDs when creating a REAL registrar in a production environment." + + " Please create the registrar without allowed TLDs, then use `nomulus" + + " registrar_contact` to create a registrar contact for it that is visible as the" + + " abuse contact in WHOIS. Then use `nomulus update_registrar` to add the allowed" + + " TLDs."); + } + @Override protected String postExecute() { if (!createGoogleGroups) { diff --git a/java/google/registry/tools/UpdateRegistrarCommand.java b/java/google/registry/tools/UpdateRegistrarCommand.java index 277ad2301..04beffd87 100644 --- a/java/google/registry/tools/UpdateRegistrarCommand.java +++ b/java/google/registry/tools/UpdateRegistrarCommand.java @@ -14,10 +14,13 @@ package google.registry.tools; +import static google.registry.util.PreconditionsUtils.checkArgumentNotNull; import static google.registry.util.PreconditionsUtils.checkArgumentPresent; import com.beust.jcommander.Parameters; +import google.registry.config.RegistryEnvironment; import google.registry.model.registrar.Registrar; +import javax.annotation.Nullable; /** Command to update a Registrar. */ @Parameters(separators = " =", commandDescription = "Update registrar account(s)") @@ -28,4 +31,22 @@ final class UpdateRegistrarCommand extends CreateOrUpdateRegistrarCommand { return checkArgumentPresent( Registrar.loadByClientId(clientId), "Registrar %s not found", clientId); } + + @Override + void checkModifyAllowedTlds(@Nullable Registrar oldRegistrar) { + // Only allow modifying allowed TLDs if we're in a non-PRODUCTION environment, if the registrar + // is not REAL, or the registrar has a WHOIS abuse contact set. + checkArgumentNotNull(oldRegistrar, "Old registrar was not present during modification"); + + boolean isRealRegistrar = + Registrar.Type.REAL.equals(registrarType) + || (Registrar.Type.REAL.equals(oldRegistrar.getType()) && registrarType == null); + if (RegistryEnvironment.PRODUCTION.equals(RegistryEnvironment.get()) && isRealRegistrar) { + checkArgumentPresent( + oldRegistrar.getWhoisAbuseContact(), + "Cannot modify allowed TLDs if there is no WHOIS abuse contact set. Please use the" + + " \"nomulus registrar_contact\" command on this registrar to set a WHOIS abuse" + + " contact."); + } + } } diff --git a/javatests/google/registry/tools/CreateRegistrarCommandTest.java b/javatests/google/registry/tools/CreateRegistrarCommandTest.java index ef060aab9..1f5b3f9ba 100644 --- a/javatests/google/registry/tools/CreateRegistrarCommandTest.java +++ b/javatests/google/registry/tools/CreateRegistrarCommandTest.java @@ -163,10 +163,11 @@ public class CreateRegistrarCommandTest extends CommandTestCase registrar = Registrar.loadByClientId("clientz"); + assertThat(registrar).isPresent(); + assertThat(registrar.get().getAllowedTlds()).containsExactly("xn--q9jyb4c", "foobar"); + } + + @Test + public void testSuccess_allowedTldsInPDT() throws Exception { + createTlds("xn--q9jyb4c", "foobar"); + + runCommandInEnvironment( + RegistryToolEnvironment.PRODUCTION, + "--name=blobio", + "--password=some_password", + "--registrar_type=PDT", + "--iana_id=9995", + "--allowed_tlds=xn--q9jyb4c,foobar", + "--billing_account_map=USD=123abc", + "--passcode=01234", + "--icann_referral_email=foo@bar.test", + "--street=\"123 Fake St\"", + "--city Fakington", + "--state MA", + "--zip 00351", + "--cc US", + "--force", "clientz"); Optional registrar = Registrar.loadByClientId("clientz"); @@ -468,7 +497,8 @@ public class CreateRegistrarCommandTest extends CommandTestCase - runCommandForced( + runCommandInEnvironment( + RegistryToolEnvironment.SANDBOX, "--name=blobio", "--password=some_password", "--registrar_type=REAL", @@ -482,6 +512,7 @@ public class CreateRegistrarCommandTest extends CommandTestCase + runCommandInEnvironment( + RegistryToolEnvironment.PRODUCTION, + "--name=blobio", + "--password=some_password", + "--registrar_type=REAL", + "--iana_id=8", + "--allowed_tlds=foobar", + "--passcode=01234", + "--icann_referral_email=foo@bar.test", + "--street=\"123 Fake St\"", + "--city Fakington", + "--state MA", + "--zip 00351", + "--cc US", + "--force", + "clientz")); + assertThat(thrown).hasMessageThat().startsWith("Cannot add allowed TLDs"); + } + @Test public void testFailure_invalidIpWhitelistFlag() { assertThrows( diff --git a/javatests/google/registry/tools/UpdateRegistrarCommandTest.java b/javatests/google/registry/tools/UpdateRegistrarCommandTest.java index 0d2fe07a3..6f458926a 100644 --- a/javatests/google/registry/tools/UpdateRegistrarCommandTest.java +++ b/javatests/google/registry/tools/UpdateRegistrarCommandTest.java @@ -32,6 +32,7 @@ import com.google.common.collect.ImmutableSet; import google.registry.model.registrar.Registrar; import google.registry.model.registrar.Registrar.State; import google.registry.model.registrar.Registrar.Type; +import google.registry.testing.AppEngineRule; import google.registry.util.CidrAddressBlock; import java.util.Optional; import org.joda.money.CurrencyUnit; @@ -86,43 +87,94 @@ public class UpdateRegistrarCommandTest extends CommandTestCase + runCommandInEnvironment( + RegistryToolEnvironment.PRODUCTION, + "--allowed_tlds=bar", + "--force", + "TheRegistrar")); + assertThat(thrown).hasMessageThat().startsWith("Cannot modify allowed TLDs"); + } + + @Test + public void testFailure_addAllowedTldsWithoutAbuseContact() { + createTlds("bar"); + IllegalArgumentException thrown = + assertThrows( + IllegalArgumentException.class, + () -> + runCommandInEnvironment( + RegistryToolEnvironment.PRODUCTION, + "--add_allowed_tlds=bar", + "--force", + "TheRegistrar")); + assertThat(thrown).hasMessageThat().startsWith("Cannot modify allowed TLDs"); + } + @Test public void testFailure_invalidIpWhitelist() { assertThrows( @@ -732,4 +814,12 @@ public class UpdateRegistrarCommandTest extends CommandTestCase