From ec2daec4126938febf3604f7c9485552125591e6 Mon Sep 17 00:00:00 2001 From: cgoldfeder Date: Mon, 28 Mar 2016 16:16:42 -0700 Subject: [PATCH] Adds the ability to whitelist registrants and nameservers on a TLD This is needed for ROCC TLDs like .foo ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=118404870 --- .../flows/domain/BaseDomainCreateFlow.java | 4 +- .../flows/domain/BaseDomainUpdateFlow.java | 4 +- .../domain/DomainApplicationCreateFlow.java | 2 + .../domain/DomainApplicationUpdateFlow.java | 2 + .../flows/domain/DomainCreateFlow.java | 2 + .../flows/domain/DomainFlowUtils.java | 40 +++- .../flows/domain/DomainUpdateFlow.java | 2 + .../registry/model/registry/Registry.java | 26 +++ .../tools/CreateOrUpdateTldCommand.java | 145 ++++++++---- .../registry/tools/UpdateTldCommand.java | 47 +++- .../DomainApplicationCreateFlowTest.java | 37 +++ .../DomainApplicationUpdateFlowTest.java | 42 ++++ .../flows/domain/DomainCreateFlowTest.java | 34 +++ .../flows/domain/DomainUpdateFlowTest.java | 41 ++++ .../google/domain/registry/model/schema.txt | 2 + .../registry/tools/CreateTldCommandTest.java | 17 ++ .../registry/tools/UpdateTldCommandTest.java | 214 +++++++++++++++--- 17 files changed, 576 insertions(+), 85 deletions(-) diff --git a/java/com/google/domain/registry/flows/domain/BaseDomainCreateFlow.java b/java/com/google/domain/registry/flows/domain/BaseDomainCreateFlow.java index 661f04139..8d81d99bc 100644 --- a/java/com/google/domain/registry/flows/domain/BaseDomainCreateFlow.java +++ b/java/com/google/domain/registry/flows/domain/BaseDomainCreateFlow.java @@ -22,6 +22,7 @@ import static com.google.domain.registry.flows.domain.DomainFlowUtils.validateDo import static com.google.domain.registry.flows.domain.DomainFlowUtils.validateDsData; import static com.google.domain.registry.flows.domain.DomainFlowUtils.validateNameservers; import static com.google.domain.registry.flows.domain.DomainFlowUtils.validateNoDuplicateContacts; +import static com.google.domain.registry.flows.domain.DomainFlowUtils.validateRegistrantAllowedOnTld; import static com.google.domain.registry.flows.domain.DomainFlowUtils.validateRequiredContactsPresent; import static com.google.domain.registry.flows.domain.DomainFlowUtils.verifyLaunchPhase; import static com.google.domain.registry.flows.domain.DomainFlowUtils.verifyNotInPendingDelete; @@ -207,9 +208,10 @@ public abstract class BaseDomainCreateFlow resourceRef) throws EppException { + EppResource resource = resourceRef.getLinked().get(); if (resource.getStatusValues().contains(StatusValue.PENDING_DELETE)) { throw new LinkedResourceInPendingDeleteProhibitsOperationException(resource.getForeignKey()); @@ -274,12 +275,26 @@ public class DomainFlowUtils { } } - static void validateNameservers(Set> nameservers) + /** Return a foreign key for a {@link ReferenceUnion} from memory or datastore as needed. */ + private static String resolveForeignKey(ReferenceUnion ref) { + return Optional.fromNullable(ref.getForeignKey()).or(ref.getLinked().get().getForeignKey()); + } + + static void validateNameservers(String tld, Set> nameservers) throws EppException { if (nameservers != null && nameservers.size() > MAX_NAMESERVERS_PER_DOMAIN) { throw new TooManyNameserversException(String.format( "Only %d nameservers are allowed per domain", MAX_NAMESERVERS_PER_DOMAIN)); } + ImmutableSet whitelist = Registry.get(tld).getAllowedFullyQualifiedHostNames(); + if (!whitelist.isEmpty()) { // Empty whitelists are ignored. + for (ReferenceUnion nameserver : nameservers) { + String foreignKey = resolveForeignKey(nameserver); + if (!whitelist.contains(foreignKey)) { + throw new NameserverNotAllowedException(foreignKey); + } + } + } } static void validateNoDuplicateContacts(Set contacts) @@ -311,6 +326,15 @@ public class DomainFlowUtils { } } + static void validateRegistrantAllowedOnTld(String tld, ReferenceUnion registrant) + throws RegistrantNotAllowedException { + ImmutableSet whitelist = Registry.get(tld).getAllowedRegistrantContactIds(); + // Empty whitelists are ignored. + if (!whitelist.isEmpty() && !whitelist.contains(resolveForeignKey(registrant))) { + throw new RegistrantNotAllowedException(registrant.toString()); + } + } + static void verifyNotReserved( InternetDomainName domainName, boolean isSunriseApplication) throws EppException { if (isReserved(domainName, isSunriseApplication)) { @@ -963,4 +987,18 @@ public class DomainFlowUtils { super("Registrar is not authorized to access the TLD " + tld); } } + + /** Registrant is not whitelisted for this TLD. */ + public static class RegistrantNotAllowedException extends StatusProhibitsOperationException { + public RegistrantNotAllowedException(String contactId) { + super(String.format("Registrant with id %s is not whitelisted for this TLD", contactId)); + } + } + + /** Nameserver is not whitelisted for this TLD. */ + public static class NameserverNotAllowedException extends StatusProhibitsOperationException { + public NameserverNotAllowedException(String fullyQualifiedHostName) { + super(String.format("Nameserver %s is not whitelisted for this TLD", fullyQualifiedHostName)); + } + } } diff --git a/java/com/google/domain/registry/flows/domain/DomainUpdateFlow.java b/java/com/google/domain/registry/flows/domain/DomainUpdateFlow.java index 8fd63be1e..b59c73c14 100644 --- a/java/com/google/domain/registry/flows/domain/DomainUpdateFlow.java +++ b/java/com/google/domain/registry/flows/domain/DomainUpdateFlow.java @@ -60,6 +60,8 @@ import java.util.Set; * @error {@link DomainFlowUtils.MissingAdminContactException} * @error {@link DomainFlowUtils.MissingContactTypeException} * @error {@link DomainFlowUtils.MissingTechnicalContactException} + * @error {@link DomainFlowUtils.NameserverNotAllowedException} + * @error {@link DomainFlowUtils.RegistrantNotAllowedException} * @error {@link DomainFlowUtils.TooManyDsRecordsException} * @error {@link DomainFlowUtils.TooManyNameserversException} */ diff --git a/java/com/google/domain/registry/model/registry/Registry.java b/java/com/google/domain/registry/model/registry/Registry.java index 5d63be5d9..148b8ee11 100644 --- a/java/com/google/domain/registry/model/registry/Registry.java +++ b/java/com/google/domain/registry/model/registry/Registry.java @@ -343,6 +343,12 @@ public class Registry extends BackupGroupRoot implements Buildable { /** The end of the claims period (at or after this time, claims no longer applies). */ DateTime claimsPeriodEnd = END_OF_TIME; + /** A whitelist of clients allowed to be used on domains on this TLD (ignored if empty). */ + Set allowedRegistrantContactIds; + + /** A whitelist of hosts allowed to be used on domains on this TLD (ignored if empty). */ + Set allowedFullyQualifiedHostNames; + public String getTldStr() { return tldStr; } @@ -521,6 +527,14 @@ public class Registry extends BackupGroupRoot implements Buildable { return claimsPeriodEnd; } + public ImmutableSet getAllowedRegistrantContactIds() { + return nullToEmptyImmutableCopy(allowedRegistrantContactIds); + } + + public ImmutableSet getAllowedFullyQualifiedHostNames() { + return nullToEmptyImmutableCopy(allowedFullyQualifiedHostNames); + } + @Override public Builder asBuilder() { return new Builder(clone(this)); @@ -734,6 +748,18 @@ public class Registry extends BackupGroupRoot implements Buildable { return this; } + public Builder setAllowedRegistrantContactIds( + ImmutableSet allowedRegistrantContactIds) { + getInstance().allowedRegistrantContactIds = allowedRegistrantContactIds; + return this; + } + + public Builder setAllowedFullyQualifiedHostNames( + ImmutableSet allowedFullyQualifiedHostNames) { + getInstance().allowedFullyQualifiedHostNames = allowedFullyQualifiedHostNames; + return this; + } + @Override public Registry build() { final Registry instance = getInstance(); diff --git a/java/com/google/domain/registry/tools/CreateOrUpdateTldCommand.java b/java/com/google/domain/registry/tools/CreateOrUpdateTldCommand.java index 8fe142856..2d07db903 100644 --- a/java/com/google/domain/registry/tools/CreateOrUpdateTldCommand.java +++ b/java/com/google/domain/registry/tools/CreateOrUpdateTldCommand.java @@ -15,18 +15,22 @@ package com.google.domain.registry.tools; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.collect.Sets.difference; +import static com.google.common.collect.Sets.intersection; +import static com.google.common.collect.Sets.union; import static com.google.domain.registry.model.RoidSuffixes.isRoidSuffixUsed; import static com.google.domain.registry.util.CollectionUtils.findDuplicates; import static com.google.domain.registry.util.CollectionUtils.nullToEmpty; import static com.google.domain.registry.util.DomainNameUtils.canonicalizeDomainName; import com.google.common.base.CharMatcher; +import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Optional; +import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedMap; -import com.google.common.collect.Sets; import com.google.domain.registry.model.registry.Registries; import com.google.domain.registry.model.registry.Registry; import com.google.domain.registry.model.registry.Registry.TldState; @@ -44,7 +48,6 @@ import org.joda.money.Money; import org.joda.time.DateTime; import org.joda.time.Duration; -import java.util.HashSet; import java.util.List; import java.util.Set; @@ -180,6 +183,18 @@ abstract class CreateOrUpdateTldCommand extends MutatingCommand { description = "A comma-separated list of reserved list names to be applied to the TLD") List reservedListNames; + @Nullable + @Parameter( + names = "--allowed_registrants", + description = "A comma-separated list of allowed registrants for the TLD") + List allowedRegistrants; + + @Nullable + @Parameter( + names = "--allowed_nameservers", + description = "A comma-separated list of allowed nameservers for the TLD") + List allowedNameservers; + @Parameter( names = {"-o", "--override_reserved_list_rules"}, description = "Override restrictions on reserved list naming") @@ -197,6 +212,18 @@ abstract class CreateOrUpdateTldCommand extends MutatingCommand { @Nullable Set reservedListNamesToRemove; + @Nullable + Set allowedRegistrantsToAdd; + + @Nullable + Set allowedRegistrantsToRemove; + + @Nullable + Set allowedNameserversToAdd; + + @Nullable + Set allowedNameserversToRemove; + /** Returns the existing registry (for update) or null (for creates). */ @Nullable abstract Registry getOldRegistry(String tld); @@ -309,54 +336,6 @@ abstract class CreateOrUpdateTldCommand extends MutatingCommand { builder.setClaimsPeriodEnd(claimsPeriodEnd); } - if (reservedListNames != null - || reservedListNamesToAdd != null - || reservedListNamesToRemove != null) { - Set listsToApply = new HashSet<>(); - if (reservedListNames != null) { - listsToApply = ImmutableSet.copyOf(reservedListNames); - checkReservedListValidityForTld(tld, listsToApply); - } else { - checkArgument( - Sets - .intersection( - nullToEmpty(reservedListNamesToAdd), - nullToEmpty(reservedListNamesToRemove)) - .isEmpty(), - "Adding and removing the same reserved list simultaneously doesn't make sense"); - - for (Key key : oldRegistry.getReservedLists()) { - listsToApply.add(key.getName()); - } - - Set duplicateNames = - Sets.intersection(listsToApply, nullToEmpty(reservedListNamesToAdd)); - checkArgument( - duplicateNames.isEmpty(), - "Cannot add reserved list(s) %s to TLD %s because they're already on it", - Joiner.on(", ").join(duplicateNames), - tld); - - if (reservedListNamesToAdd != null) { - checkReservedListValidityForTld(tld, reservedListNamesToAdd); - listsToApply.addAll(reservedListNamesToAdd); - } - - if (reservedListNamesToRemove != null) { - for (String name : reservedListNamesToRemove) { - checkArgument( - listsToApply.contains(name), - "Cannot remove reserved list %s from TLD %s because it isn't on it", - name, - tld); - listsToApply.remove(name); - } - } - } - - builder.setReservedListsByName(listsToApply); - } - if (premiumListName != null) { if (premiumListName.isPresent()) { Optional premiumList = PremiumList.get(premiumListName.get()); @@ -368,12 +347,78 @@ abstract class CreateOrUpdateTldCommand extends MutatingCommand { } } + ImmutableSet newReservedListNames = + formUpdatedList( + "reserved lists", + oldRegistry == null ? ImmutableSet.of() : FluentIterable + .from(oldRegistry.getReservedLists()) + .transform( + new Function, String>() { + @Override + public String apply(Key key) { + return key.getName(); + }}) + .toSet(), + reservedListNames, + reservedListNamesToAdd, + reservedListNamesToRemove); + checkReservedListValidityForTld(tld, newReservedListNames); + builder.setReservedListsByName(newReservedListNames); + + builder.setAllowedRegistrantContactIds( + formUpdatedList( + "allowed registrants", + oldRegistry == null + ? ImmutableSet.of() + : oldRegistry.getAllowedRegistrantContactIds(), + allowedRegistrants, + allowedRegistrantsToAdd, + allowedRegistrantsToRemove)); + + builder.setAllowedFullyQualifiedHostNames( + formUpdatedList( + "allowed nameservers", + oldRegistry == null + ? ImmutableSet.of() + : oldRegistry.getAllowedFullyQualifiedHostNames(), + allowedNameservers, + allowedNameserversToAdd, + allowedNameserversToRemove)); + // Update the Registry object. setCommandSpecificProperties(builder); stageEntityChange(oldRegistry, builder.build()); } } + private ImmutableSet formUpdatedList( + String description, + ImmutableSet originals, + List toReplace, + Set toAdd, + Set toRemove) { + if (toReplace != null) { + return ImmutableSet.copyOf(toReplace); + } + toAdd = nullToEmpty(toAdd); + toRemove = nullToEmpty(toRemove); + checkIsEmpty( + intersection(toAdd, toRemove), + String.format( + "Adding and removing the same %s simultaneously doesn't make sense", description)); + checkIsEmpty( + intersection(originals, toAdd), + String.format("Cannot add %s that were previously present", description)); + checkIsEmpty( + difference(toRemove, originals), + String.format("Cannot remove %s that were not previously present", description)); + return ImmutableSet.copyOf(difference(union(originals, toAdd), toRemove)); + } + + private void checkIsEmpty(Set set, String errorString) { + checkArgument(set.isEmpty(), String.format("%s: %s", errorString, set)); + } + @Override public String execute() throws Exception { try { diff --git a/java/com/google/domain/registry/tools/UpdateTldCommand.java b/java/com/google/domain/registry/tools/UpdateTldCommand.java index 2a5e682bd..9826d97ab 100644 --- a/java/com/google/domain/registry/tools/UpdateTldCommand.java +++ b/java/com/google/domain/registry/tools/UpdateTldCommand.java @@ -43,6 +43,30 @@ class UpdateTldCommand extends CreateOrUpdateTldCommand { description = "A comma-separated list of reserved list names to be removed from the TLD") List reservedListsRemove; + @Nullable + @Parameter( + names = "--add_allowed_registrants", + description = "A comma-separated list of allowed registrants to be added to the TLD") + List allowedRegistrantsAdd; + + @Nullable + @Parameter( + names = "--remove_allowed_registrants", + description = "A comma-separated list of allowed registrants to be removed from the TLD") + List allowedRegistrantsRemove; + + @Nullable + @Parameter( + names = "--add_allowed_nameservers", + description = "A comma-separated list of allowed nameservers to be added to the TLD") + List allowedNameserversAdd; + + @Nullable + @Parameter( + names = "--remove_allowed_nameservers", + description = "A comma-separated list of allowed nameservers to be removed from the TLD") + List allowedNameserversRemove; + @Override Registry getOldRegistry(String tld) { return Registry.get(assertTldExists(tld)); @@ -50,11 +74,26 @@ class UpdateTldCommand extends CreateOrUpdateTldCommand { @Override protected void initTldCommand() throws Exception { - checkArgument(reservedListsAdd == null || reservedListNames == null, - "Don't pass both --reserved_lists and --add_reserved_lists"); + checkConflicts("reserved_lists", reservedListNames, reservedListsAdd, reservedListsRemove); + checkConflicts( + "allowed_registrants", allowedRegistrants, allowedRegistrantsAdd, allowedRegistrantsRemove); + checkConflicts( + "allowed_nameservers", allowedNameservers, allowedNameserversAdd, allowedNameserversRemove); reservedListNamesToAdd = ImmutableSet.copyOf(nullToEmpty(reservedListsAdd)); - checkArgument(reservedListsRemove == null || reservedListNames == null, - "Don't pass both --reserved_lists and --remove_reserved_lists"); reservedListNamesToRemove = ImmutableSet.copyOf(nullToEmpty(reservedListsRemove)); + allowedRegistrantsToAdd = ImmutableSet.copyOf(nullToEmpty(allowedRegistrantsAdd)); + allowedRegistrantsToRemove = ImmutableSet.copyOf(nullToEmpty(allowedRegistrantsRemove)); + allowedNameserversToAdd = ImmutableSet.copyOf(nullToEmpty(allowedNameserversAdd)); + allowedNameserversToRemove = ImmutableSet.copyOf(nullToEmpty(allowedNameserversRemove)); + } + + private void checkConflicts( + String baseFlagName, Object overwriteValue, Object addValue, Object removeValue) { + checkNotBoth(baseFlagName, overwriteValue, "add_" + baseFlagName, addValue); + checkNotBoth(baseFlagName, overwriteValue, "remove_" + baseFlagName, removeValue); + } + + private void checkNotBoth(String nameA, Object valueA, String nameB, Object valueB) { + checkArgument(valueA == null || valueB == null, "Don't pass both --%s and --%s", nameA, nameB); } } diff --git a/javatests/com/google/domain/registry/flows/domain/DomainApplicationCreateFlowTest.java b/javatests/com/google/domain/registry/flows/domain/DomainApplicationCreateFlowTest.java index 3923acfe1..ef4d8871b 100644 --- a/javatests/com/google/domain/registry/flows/domain/DomainApplicationCreateFlowTest.java +++ b/javatests/com/google/domain/registry/flows/domain/DomainApplicationCreateFlowTest.java @@ -78,9 +78,11 @@ import com.google.domain.registry.flows.domain.DomainFlowUtils.LaunchPhaseMismat import com.google.domain.registry.flows.domain.DomainFlowUtils.LeadingDashException; import com.google.domain.registry.flows.domain.DomainFlowUtils.LinkedResourceDoesNotExistException; import com.google.domain.registry.flows.domain.DomainFlowUtils.MissingContactTypeException; +import com.google.domain.registry.flows.domain.DomainFlowUtils.NameserverNotAllowedException; import com.google.domain.registry.flows.domain.DomainFlowUtils.NoMarksFoundMatchingDomainException; import com.google.domain.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException; import com.google.domain.registry.flows.domain.DomainFlowUtils.PremiumNameBlockedException; +import com.google.domain.registry.flows.domain.DomainFlowUtils.RegistrantNotAllowedException; import com.google.domain.registry.flows.domain.DomainFlowUtils.SignedMarkCertificateExpiredException; import com.google.domain.registry.flows.domain.DomainFlowUtils.SignedMarkCertificateInvalidException; import com.google.domain.registry.flows.domain.DomainFlowUtils.SignedMarkCertificateNotYetValidException; @@ -1170,6 +1172,41 @@ public class DomainApplicationCreateFlowTest } } + @Test + public void testFailure_registrantNotWhitelisted() throws Exception { + persistActiveContact("someone"); + persistContactsAndHosts(); + persistResource(Registry.get("tld").asBuilder() + .setAllowedRegistrantContactIds(ImmutableSet.of("someone")) + .build()); + thrown.expect(RegistrantNotAllowedException.class); + runFlow(); + } + + @Test + public void testFailure_nameserverNotWhitelisted() throws Exception { + persistActiveHost("ns1.example.com"); + persistContactsAndHosts(); + persistResource(Registry.get("tld").asBuilder() + .setAllowedFullyQualifiedHostNames(ImmutableSet.of("ns1.someone.tld")) + .build()); + thrown.expect(NameserverNotAllowedException.class); + runFlow(); + } + + @Test + public void testSuccess_nameserverAndRegistrantWhitelisted() throws Exception { + persistResource(Registry.get("tld").asBuilder() + .setAllowedRegistrantContactIds(ImmutableSet.of("jd1234")) + .setAllowedFullyQualifiedHostNames(ImmutableSet.of("ns1.example.net", "ns2.example.net")) + .build()); + persistContactsAndHosts(); + clock.advanceOneMilli(); + doSuccessfulTest("domain_create_sunrise_encoded_signed_mark_response.xml", true); + assertAboutApplications().that(getOnlyGlobalResource(DomainApplication.class)) + .hasApplicationStatus(ApplicationStatus.VALIDATED); + } + /** * There is special logic that disallows a failfast for domains in add grace period and sunrush * add grace period, so make sure that they fail anyways in the actual flow. diff --git a/javatests/com/google/domain/registry/flows/domain/DomainApplicationUpdateFlowTest.java b/javatests/com/google/domain/registry/flows/domain/DomainApplicationUpdateFlowTest.java index c132e0d8f..dceed787d 100644 --- a/javatests/com/google/domain/registry/flows/domain/DomainApplicationUpdateFlowTest.java +++ b/javatests/com/google/domain/registry/flows/domain/DomainApplicationUpdateFlowTest.java @@ -49,7 +49,9 @@ import com.google.domain.registry.flows.domain.DomainFlowUtils.LinkedResourceDoe import com.google.domain.registry.flows.domain.DomainFlowUtils.MissingAdminContactException; import com.google.domain.registry.flows.domain.DomainFlowUtils.MissingContactTypeException; import com.google.domain.registry.flows.domain.DomainFlowUtils.MissingTechnicalContactException; +import com.google.domain.registry.flows.domain.DomainFlowUtils.NameserverNotAllowedException; import com.google.domain.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException; +import com.google.domain.registry.flows.domain.DomainFlowUtils.RegistrantNotAllowedException; import com.google.domain.registry.flows.domain.DomainFlowUtils.TooManyDsRecordsException; import com.google.domain.registry.flows.domain.DomainFlowUtils.TooManyNameserversException; import com.google.domain.registry.model.contact.ContactResource; @@ -63,6 +65,7 @@ import com.google.domain.registry.model.domain.secdns.DelegationSignerData; import com.google.domain.registry.model.eppcommon.StatusValue; import com.google.domain.registry.model.host.HostResource; import com.google.domain.registry.model.registrar.Registrar; +import com.google.domain.registry.model.registry.Registry; import com.google.domain.registry.model.registry.Registry.TldState; import com.google.domain.registry.model.reporting.HistoryEntry; @@ -622,4 +625,43 @@ public class DomainApplicationUpdateFlowTest .build()); runFlow(); } + + @Test + public void testFailure_newRegistrantNotWhitelisted() throws Exception { + setEppInput("domain_update_sunrise_registrant_to_tech.xml"); + persistReferencedEntities(); + persistApplication(); + persistResource( + Registry.get("tld").asBuilder() + .setAllowedRegistrantContactIds(ImmutableSet.of("sha8013")) + .build()); + clock.advanceOneMilli(); + thrown.expect(RegistrantNotAllowedException.class); + runFlow(); + } + + @Test + public void testFailure_newNameserverNotWhitelisted() throws Exception { + persistReferencedEntities(); + persistApplication(); + persistResource( + Registry.get("tld").asBuilder() + .setAllowedFullyQualifiedHostNames(ImmutableSet.of("ns1.example.foo")) + .build()); + clock.advanceOneMilli(); + thrown.expect(NameserverNotAllowedException.class); + runFlow(); + } + + @Test + public void testSuccess_nameserverAndRegistrantWhitelisted() throws Exception { + persistResource( + Registry.get("tld").asBuilder() + .setAllowedRegistrantContactIds(ImmutableSet.of("sh8013")) + .setAllowedFullyQualifiedHostNames(ImmutableSet.of("ns2.example.tld")) + .build()); + persistReferencedEntities(); + persistApplication(); + doSuccessfulTest(); + } } diff --git a/javatests/com/google/domain/registry/flows/domain/DomainCreateFlowTest.java b/javatests/com/google/domain/registry/flows/domain/DomainCreateFlowTest.java index 039298078..dafd574fb 100644 --- a/javatests/com/google/domain/registry/flows/domain/DomainCreateFlowTest.java +++ b/javatests/com/google/domain/registry/flows/domain/DomainCreateFlowTest.java @@ -87,8 +87,10 @@ import com.google.domain.registry.flows.domain.DomainFlowUtils.MissingAdminConta import com.google.domain.registry.flows.domain.DomainFlowUtils.MissingContactTypeException; import com.google.domain.registry.flows.domain.DomainFlowUtils.MissingRegistrantException; import com.google.domain.registry.flows.domain.DomainFlowUtils.MissingTechnicalContactException; +import com.google.domain.registry.flows.domain.DomainFlowUtils.NameserverNotAllowedException; import com.google.domain.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException; import com.google.domain.registry.flows.domain.DomainFlowUtils.PremiumNameBlockedException; +import com.google.domain.registry.flows.domain.DomainFlowUtils.RegistrantNotAllowedException; import com.google.domain.registry.flows.domain.DomainFlowUtils.TldDoesNotExistException; import com.google.domain.registry.flows.domain.DomainFlowUtils.TooManyDsRecordsException; import com.google.domain.registry.flows.domain.DomainFlowUtils.TooManyNameserversException; @@ -1226,4 +1228,36 @@ public class DomainCreateFlowTest extends ResourceFlowTestCase> reservedLists; + java.util.Set allowedFullyQualifiedHostNames; + java.util.Set allowedRegistrantContactIds; org.joda.money.CurrencyUnit currency; org.joda.money.Money createBillingCost; org.joda.money.Money restoreBillingCost; diff --git a/javatests/com/google/domain/registry/tools/CreateTldCommandTest.java b/javatests/com/google/domain/registry/tools/CreateTldCommandTest.java index 272f961fb..1d347b3ce 100644 --- a/javatests/com/google/domain/registry/tools/CreateTldCommandTest.java +++ b/javatests/com/google/domain/registry/tools/CreateTldCommandTest.java @@ -255,6 +255,23 @@ public class CreateTldCommandTest extends CommandTestCase { runCommandForced("1foo", "--roid_suffix=1FOO"); } + @Test + public void testSuccess_setAllowedRegistrants() throws Exception { + runCommandForced("--allowed_registrants=alice,bob", "--roid_suffix=Q9JYB4C", "xn--q9jyb4c"); + assertThat(Registry.get("xn--q9jyb4c").getAllowedRegistrantContactIds()) + .containsExactly("alice", "bob"); + } + + @Test + public void testSuccess_setAllowedNameservers() throws Exception { + runCommandForced( + "--allowed_nameservers=ns1.example.com,ns2.example.com", + "--roid_suffix=Q9JYB4C", + "xn--q9jyb4c"); + assertThat(Registry.get("xn--q9jyb4c").getAllowedFullyQualifiedHostNames()) + .containsExactly("ns1.example.com", "ns2.example.com"); + } + @Test public void testSuccess_setCommonReservedListOnTld() throws Exception { runSuccessfulReservedListsTest("common_abuse"); diff --git a/javatests/com/google/domain/registry/tools/UpdateTldCommandTest.java b/javatests/com/google/domain/registry/tools/UpdateTldCommandTest.java index d7f53eb96..b532ab6e5 100644 --- a/javatests/com/google/domain/registry/tools/UpdateTldCommandTest.java +++ b/javatests/com/google/domain/registry/tools/UpdateTldCommandTest.java @@ -271,43 +271,144 @@ public class UpdateTldCommandTest extends CommandTestCase { } @Test - public void testSuccess_setReservedListsOverwritesCorrectly() throws Exception { - Registry registry = addTwoReservedListsToRegistry(); + public void testSuccess_setReservedListsOverwrites() throws Exception { + persistResource(Registry.get("xn--q9jyb4c").asBuilder() + .setReservedListsByName(ImmutableSet.of("xn--q9jyb4c_r1", "xn--q9jyb4c_r2")) + .build()); runCommandForced("--reserved_lists=xn--q9jyb4c_r2", "xn--q9jyb4c"); - registry = Registry.get("xn--q9jyb4c"); - assertThat(registry.getReservedLists()).hasSize(1); - assertThat(registry.getReservedLists().asList().get(0).getName()).isEqualTo("xn--q9jyb4c_r2"); + assertThat(transform(Registry.get("xn--q9jyb4c").getReservedLists(), GET_NAME_FUNCTION)) + .containsExactly("xn--q9jyb4c_r2"); } @Test - public void testSuccess_addReservedListsWorksCorrectly() throws Exception { - runCommandForced("--add_reserved_lists=xn--q9jyb4c_r1,xn--q9jyb4c_r2", "xn--q9jyb4c"); + public void testSuccess_addReservedLists() throws Exception { + persistResource(Registry.get("xn--q9jyb4c").asBuilder() + .setReservedListsByName(ImmutableSet.of("xn--q9jyb4c_r1")) + .build()); + runCommandForced("--add_reserved_lists=xn--q9jyb4c_r2", "xn--q9jyb4c"); assertThat(transform(Registry.get("xn--q9jyb4c").getReservedLists(), GET_NAME_FUNCTION)) .containsExactly("xn--q9jyb4c_r1", "xn--q9jyb4c_r2"); } @Test - public void testSuccess_removeAllReservedListsWorksCorrectly() throws Exception { - addTwoReservedListsToRegistry(); + public void testSuccess_removeAllReservedLists() throws Exception { + persistResource(Registry.get("xn--q9jyb4c").asBuilder() + .setReservedListsByName(ImmutableSet.of("xn--q9jyb4c_r1", "xn--q9jyb4c_r2")) + .build()); runCommandForced("--remove_reserved_lists=xn--q9jyb4c_r1,xn--q9jyb4c_r2", "xn--q9jyb4c"); assertThat(Registry.get("xn--q9jyb4c").getReservedLists()).isEmpty(); } @Test - public void testSuccess_removeSomeReservedListsWorksCorrectly() throws Exception { - addTwoReservedListsToRegistry(); + public void testSuccess_removeSomeReservedLists() throws Exception { + persistResource(Registry.get("xn--q9jyb4c").asBuilder() + .setReservedListsByName(ImmutableSet.of("xn--q9jyb4c_r1", "xn--q9jyb4c_r2")) + .build()); runCommandForced("--remove_reserved_lists=xn--q9jyb4c_r1", "xn--q9jyb4c"); assertThat(transform(Registry.get("xn--q9jyb4c").getReservedLists(), GET_NAME_FUNCTION)) .containsExactly("xn--q9jyb4c_r2"); } - private Registry addTwoReservedListsToRegistry() throws Exception { + @Test + public void testSuccess_setAllowedRegistrants() throws Exception { + runCommandForced("--allowed_registrants=alice,bob", "xn--q9jyb4c"); + assertThat(Registry.get("xn--q9jyb4c").getAllowedRegistrantContactIds()) + .containsExactly("alice", "bob"); + } + + @Test + public void testSuccess_setAllowedRegistrantsOverwrites() throws Exception { persistResource( - Registry.get("xn--q9jyb4c") - .asBuilder() - .setReservedListsByName(ImmutableSet.of("xn--q9jyb4c_r1", "xn--q9jyb4c_r2")) + Registry.get("xn--q9jyb4c").asBuilder() + .setAllowedRegistrantContactIds(ImmutableSet.of("jane", "john")) .build()); - return Registry.get("xn--q9jyb4c"); + runCommandForced("--allowed_registrants=alice,bob", "xn--q9jyb4c"); + assertThat(Registry.get("xn--q9jyb4c").getAllowedRegistrantContactIds()) + .containsExactly("alice", "bob"); + } + + @Test + public void testSuccess_addAllowedRegistrants() throws Exception { + persistResource( + Registry.get("xn--q9jyb4c").asBuilder() + .setAllowedRegistrantContactIds(ImmutableSet.of("alice")) + .build()); + runCommandForced("--add_allowed_registrants=bob", "xn--q9jyb4c"); + assertThat(Registry.get("xn--q9jyb4c").getAllowedRegistrantContactIds()) + .containsExactly("alice", "bob"); + } + + @Test + public void testSuccess_removeAllAllowedRegistrants() throws Exception { + persistResource( + Registry.get("xn--q9jyb4c").asBuilder() + .setAllowedRegistrantContactIds(ImmutableSet.of("alice", "bob")) + .build()); + runCommandForced("--remove_allowed_registrants=alice,bob", "xn--q9jyb4c"); + assertThat(Registry.get("xn--q9jyb4c").getAllowedRegistrantContactIds()).isEmpty(); + } + + @Test + public void testSuccess_removeSomeAllowedRegistrants() throws Exception { + persistResource( + Registry.get("xn--q9jyb4c").asBuilder() + .setAllowedRegistrantContactIds(ImmutableSet.of("alice", "bob")) + .build()); + runCommandForced("--remove_allowed_registrants=alice", "xn--q9jyb4c"); + assertThat(Registry.get("xn--q9jyb4c").getAllowedRegistrantContactIds()).containsExactly("bob"); + } + + @Test + public void testSuccess_setAllowedNameservers() throws Exception { + runCommandForced("--allowed_nameservers=ns1.example.com,ns2.example.com", "xn--q9jyb4c"); + assertThat(Registry.get("xn--q9jyb4c").getAllowedFullyQualifiedHostNames()) + .containsExactly("ns1.example.com", "ns2.example.com"); + } + + @Test + public void testSuccess_setAllowedNameserversOverwrites() throws Exception { + persistResource( + Registry.get("xn--q9jyb4c").asBuilder() + .setAllowedFullyQualifiedHostNames( + ImmutableSet.of("ns1.example.tld", "ns2.example.tld")) + .build()); + runCommandForced("--allowed_nameservers=ns1.example.com,ns2.example.com", "xn--q9jyb4c"); + assertThat(Registry.get("xn--q9jyb4c").getAllowedFullyQualifiedHostNames()) + .containsExactly("ns1.example.com", "ns2.example.com"); + } + + @Test + public void testSuccess_addAllowedNameservers() throws Exception { + persistResource( + Registry.get("xn--q9jyb4c").asBuilder() + .setAllowedFullyQualifiedHostNames(ImmutableSet.of("ns1.example.com")) + .build()); + runCommandForced("--add_allowed_nameservers=ns2.example.com", "xn--q9jyb4c"); + assertThat(Registry.get("xn--q9jyb4c").getAllowedFullyQualifiedHostNames()) + .containsExactly("ns1.example.com", "ns2.example.com"); + } + + @Test + public void testSuccess_removeAllAllowedNameservers() throws Exception { + persistResource( + Registry.get("xn--q9jyb4c").asBuilder() + .setAllowedFullyQualifiedHostNames( + ImmutableSet.of("ns1.example.com", "ns2.example.com")) + .build()); + runCommandForced("--remove_allowed_nameservers=ns1.example.com,ns2.example.com", "xn--q9jyb4c"); + assertThat(Registry.get("xn--q9jyb4c").getAllowedFullyQualifiedHostNames()).isEmpty(); + } + + @Test + public void testSuccess_removeSomeAllowedNameservers() throws Exception { + persistResource( + Registry.get("xn--q9jyb4c").asBuilder() + .setAllowedFullyQualifiedHostNames( + ImmutableSet.of("ns1.example.com", "ns2.example.com")) + .build()); + runCommandForced("--remove_allowed_nameservers=ns1.example.com", "xn--q9jyb4c"); + assertThat(Registry.get("xn--q9jyb4c").getAllowedFullyQualifiedHostNames()) + .containsExactly("ns2.example.com"); } @Test @@ -445,34 +546,91 @@ public class UpdateTldCommandTest extends CommandTestCase { @Test public void testFailure_cantAddDuplicateReservedList() throws Exception { - thrown.expect( - IllegalArgumentException.class, - "Cannot add reserved list(s) xn--q9jyb4c_r1 to TLD xn--q9jyb4c " - + "because they're already on it"); - addTwoReservedListsToRegistry(); + persistResource(Registry.get("xn--q9jyb4c").asBuilder() + .setReservedListsByName(ImmutableSet.of("xn--q9jyb4c_r1", "xn--q9jyb4c_r2")) + .build()); + thrown.expect(IllegalArgumentException.class, "xn--q9jyb4c_r1"); runCommandForced("--add_reserved_lists=xn--q9jyb4c_r1", "xn--q9jyb4c"); } @Test public void testFailure_cantRemoveReservedListThatIsntPresent() throws Exception { - thrown.expect( - IllegalArgumentException.class, - "Cannot remove reserved list xn--q9jyb4c_Z from TLD xn--q9jyb4c because it isn't on it"); - addTwoReservedListsToRegistry(); + persistResource(Registry.get("xn--q9jyb4c").asBuilder() + .setReservedListsByName(ImmutableSet.of("xn--q9jyb4c_r1", "xn--q9jyb4c_r2")) + .build()); + thrown.expect(IllegalArgumentException.class, "xn--q9jyb4c_Z"); runCommandForced("--remove_reserved_lists=xn--q9jyb4c_Z", "xn--q9jyb4c"); } @Test public void testFailure_cantAddAndRemoveSameReservedListSimultaneously() throws Exception { - thrown.expect( - IllegalArgumentException.class, - "Adding and removing the same reserved list simultaneously doesn't make sense"); + thrown.expect(IllegalArgumentException.class, "xn--q9jyb4c_r1"); runCommandForced( "--add_reserved_lists=xn--q9jyb4c_r1", "--remove_reserved_lists=xn--q9jyb4c_r1", "xn--q9jyb4c"); } + @Test + public void testFailure_cantAddDuplicateAllowedRegistrants() throws Exception { + persistResource( + Registry.get("xn--q9jyb4c").asBuilder() + .setAllowedRegistrantContactIds(ImmutableSet.of("alice", "bob")) + .build()); + thrown.expect(IllegalArgumentException.class, "alice"); + runCommandForced("--add_allowed_registrants=alice", "xn--q9jyb4c"); + } + + @Test + public void testFailure_cantRemoveAllowedRegistrantThatIsntPresent() throws Exception { + persistResource( + Registry.get("xn--q9jyb4c").asBuilder() + .setAllowedRegistrantContactIds(ImmutableSet.of("alice")) + .build()); + thrown.expect(IllegalArgumentException.class, "bob"); + runCommandForced("--remove_allowed_registrants=bob", "xn--q9jyb4c"); + } + + @Test + public void testFailure_cantAddAndRemoveSameAllowedRegistrantsSimultaneously() throws Exception { + thrown.expect(IllegalArgumentException.class, "alice"); + runCommandForced( + "--add_allowed_registrants=alice", + "--remove_allowed_registrants=alice", + "xn--q9jyb4c"); + } + + @Test + public void testFailure_cantAddDuplicateAllowedNameservers() throws Exception { + persistResource( + Registry.get("xn--q9jyb4c").asBuilder() + .setAllowedFullyQualifiedHostNames( + ImmutableSet.of("ns1.example.com", "ns2.example.com")) + .build()); + thrown.expect(IllegalArgumentException.class, "ns1.example.com"); + runCommandForced("--add_allowed_nameservers=ns1.example.com", "xn--q9jyb4c"); + } + + @Test + public void testFailure_cantRemoveAllowedNameserverThatIsntPresent() throws Exception { + persistResource( + Registry.get("xn--q9jyb4c").asBuilder() + .setAllowedFullyQualifiedHostNames( + ImmutableSet.of("ns1.example.com")) + .build()); + thrown.expect(IllegalArgumentException.class, "ns2.example.com"); + runCommandForced("--remove_allowed_nameservers=ns2.example.com", "xn--q9jyb4c"); + } + + @Test + public void testFailure_cantAddAndRemoveSameAllowedNameserversSimultaneously() throws Exception { + thrown.expect(IllegalArgumentException.class, "ns1.example.com"); + runCommandForced( + "--add_allowed_nameservers=ns1.example.com", + "--remove_allowed_nameservers=ns1.example.com", + "xn--q9jyb4c"); + } + @Test public void testFailure_roidSuffixAlreadyInUse() throws Exception { createTld("foo", "BLAH");