diff --git a/core/src/main/java/google/registry/batch/RemoveAllDomainContactsAction.java b/core/src/main/java/google/registry/batch/RemoveAllDomainContactsAction.java
deleted file mode 100644
index cfe4ab85a05..00000000000
--- a/core/src/main/java/google/registry/batch/RemoveAllDomainContactsAction.java
+++ /dev/null
@@ -1,238 +0,0 @@
-// Copyright 2025 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.batch;
-
-import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
-import static google.registry.flows.FlowUtils.marshalWithLenientRetry;
-import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
-import static google.registry.util.DateTimeUtils.END_OF_TIME;
-import static google.registry.util.ResourceUtils.readResourceUtf8;
-import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
-import static jakarta.servlet.http.HttpServletResponse.SC_NO_CONTENT;
-import static jakarta.servlet.http.HttpServletResponse.SC_OK;
-import static java.nio.charset.StandardCharsets.US_ASCII;
-
-import com.google.common.base.Ascii;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.flogger.FluentLogger;
-import com.google.common.util.concurrent.RateLimiter;
-import google.registry.config.RegistryConfig.Config;
-import google.registry.flows.EppController;
-import google.registry.flows.EppRequestSource;
-import google.registry.flows.PasswordOnlyTransportCredentials;
-import google.registry.flows.StatelessRequestSessionMetadata;
-import google.registry.model.contact.Contact;
-import google.registry.model.domain.DesignatedContact;
-import google.registry.model.domain.Domain;
-import google.registry.model.eppcommon.ProtocolDefinition;
-import google.registry.model.eppoutput.EppOutput;
-import google.registry.persistence.VKey;
-import google.registry.request.Action;
-import google.registry.request.Response;
-import google.registry.request.auth.Auth;
-import google.registry.request.lock.LockHandler;
-import jakarta.inject.Inject;
-import jakarta.inject.Named;
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.logging.Level;
-import javax.annotation.Nullable;
-import org.joda.time.Duration;
-
-/**
- * An action that removes all contacts from all active (non-deleted) domains.
- *
- *
This implements part 1 of phase 3 of the Minimum Dataset migration, wherein we remove all uses
- * of contact objects in preparation for later removing all contact data from the system.
- *
- *
This runs as a singly threaded, resumable action that loads batches of domains still
- * containing contacts, and runs a superuser domain update on each one to remove the contacts,
- * leaving behind a record recording that update.
- */
-@Action(
- service = Action.Service.BACKEND,
- path = RemoveAllDomainContactsAction.PATH,
- method = Action.Method.POST,
- auth = Auth.AUTH_ADMIN)
-public class RemoveAllDomainContactsAction implements Runnable {
-
- public static final String PATH = "/_dr/task/removeAllDomainContacts";
- private static final String LOCK_NAME = "Remove all domain contacts";
- private static final String CONTACT_FMT = "%s";
-
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final EppController eppController;
- private final String registryAdminClientId;
- private final LockHandler lockHandler;
- private final RateLimiter rateLimiter;
- private final Response response;
- private final String updateDomainXml;
- private int successes = 0;
- private int failures = 0;
-
- private static final int BATCH_SIZE = 10000;
-
- @Inject
- RemoveAllDomainContactsAction(
- EppController eppController,
- @Config("registryAdminClientId") String registryAdminClientId,
- LockHandler lockHandler,
- @Named("standardRateLimiter") RateLimiter rateLimiter,
- Response response) {
- this.eppController = eppController;
- this.registryAdminClientId = registryAdminClientId;
- this.lockHandler = lockHandler;
- this.rateLimiter = rateLimiter;
- this.response = response;
- this.updateDomainXml =
- readResourceUtf8(RemoveAllDomainContactsAction.class, "domain_remove_contacts.xml");
- }
-
- @Override
- public void run() {
- response.setContentType(PLAIN_TEXT_UTF_8);
- Callable runner =
- () -> {
- try {
- runLocked();
- response.setStatus(SC_OK);
- } catch (Exception e) {
- logger.atSevere().withCause(e).log("Errored out during execution.");
- response.setStatus(SC_INTERNAL_SERVER_ERROR);
- response.setPayload(String.format("Errored out with cause: %s", e));
- }
- return null;
- };
-
- if (!lockHandler.executeWithLocks(runner, null, Duration.standardHours(1), LOCK_NAME)) {
- // Send a 200-series status code to prevent this conflicting action from retrying.
- response.setStatus(SC_NO_CONTENT);
- response.setPayload("Could not acquire lock; already running?");
- }
- }
-
- private void runLocked() {
- logger.atInfo().log("Removing contacts on all active domains.");
-
- List domainRepoIdsBatch;
- do {
- domainRepoIdsBatch =
- tm().>transact(
- () ->
- tm().getEntityManager()
- .createQuery(
- """
- SELECT repoId FROM Domain WHERE deletionTime = :end_of_time AND NOT (
- adminContact IS NULL AND billingContact IS NULL
- AND registrantContact IS NULL AND techContact IS NULL)
- """)
- .setParameter("end_of_time", END_OF_TIME)
- .setMaxResults(BATCH_SIZE)
- .getResultList());
-
- for (String domainRepoId : domainRepoIdsBatch) {
- rateLimiter.acquire();
- runDomainUpdateFlow(domainRepoId);
- }
- } while (!domainRepoIdsBatch.isEmpty());
- String msg =
- String.format(
- "Finished; %d domains were successfully updated and %d errored out.",
- successes, failures);
- logger.at(failures == 0 ? Level.INFO : Level.WARNING).log(msg);
- response.setPayload(msg);
- }
-
- private void runDomainUpdateFlow(String repoId) {
- // Create a new transaction that the flow's execution will be enlisted in that loads the domain
- // transactionally. This way we can ensure that nothing else has modified the domain in question
- // in the intervening period since the query above found it. If a single domain update fails
- // permanently, log it and move on to not block processing all the other domains.
- try {
- boolean success = tm().transact(() -> runDomainUpdateFlowInner(repoId));
- if (success) {
- successes++;
- } else {
- failures++;
- }
- } catch (Throwable t) {
- logger.atWarning().withCause(t).log(
- "Failed updating domain with repoId %s; skipping.", repoId);
- }
- }
-
- /**
- * Runs the actual domain update flow and returns whether the contact removals were successful.
- */
- private boolean runDomainUpdateFlowInner(String repoId) {
- Domain domain = tm().loadByKey(VKey.create(Domain.class, repoId));
- if (!domain.getDeletionTime().equals(END_OF_TIME)) {
- // Domain has been deleted since the action began running; nothing further to be
- // done here.
- logger.atInfo().log("Nothing to process for deleted domain '%s'.", domain.getDomainName());
- return false;
- }
- logger.atInfo().log("Attempting to remove contacts on domain '%s'.", domain.getDomainName());
-
- StringBuilder sb = new StringBuilder();
- ImmutableMap, Contact> contacts =
- tm().loadByKeys(
- domain.getContacts().stream()
- .map(DesignatedContact::getContactKey)
- .collect(ImmutableSet.toImmutableSet()));
-
- // Collect all the (non-registrant) contacts referenced by the domain and compile an EPP XML
- // string that removes each one.
- for (DesignatedContact designatedContact : domain.getContacts()) {
- @Nullable Contact contact = contacts.get(designatedContact.getContactKey());
- if (contact == null) {
- logger.atWarning().log(
- "Domain '%s' referenced contact with repo ID '%s' that couldn't be" + " loaded.",
- domain.getDomainName(), designatedContact.getContactKey().getKey());
- continue;
- }
- sb.append(
- String.format(
- CONTACT_FMT,
- Ascii.toLowerCase(designatedContact.getType().name()),
- contact.getContactId()))
- .append("\n");
- }
-
- String compiledXml =
- updateDomainXml
- .replace("%DOMAIN%", domain.getDomainName())
- .replace("%CONTACTS%", sb.toString());
- EppOutput output =
- eppController.handleEppCommand(
- new StatelessRequestSessionMetadata(
- registryAdminClientId, ProtocolDefinition.getVisibleServiceExtensionUris()),
- new PasswordOnlyTransportCredentials(),
- EppRequestSource.BACKEND,
- false,
- true,
- compiledXml.getBytes(US_ASCII));
- if (output.isSuccess()) {
- logger.atInfo().log(
- "Successfully removed contacts from domain '%s'.", domain.getDomainName());
- } else {
- logger.atWarning().log(
- "Failed removing contacts from domain '%s' with error %s.",
- domain.getDomainName(), new String(marshalWithLenientRetry(output), US_ASCII));
- }
- return output.isSuccess();
- }
-}
diff --git a/core/src/main/java/google/registry/flows/FlowModule.java b/core/src/main/java/google/registry/flows/FlowModule.java
index 81749ad9090..99e883d3f47 100644
--- a/core/src/main/java/google/registry/flows/FlowModule.java
+++ b/core/src/main/java/google/registry/flows/FlowModule.java
@@ -22,7 +22,6 @@
import dagger.Module;
import dagger.Provides;
import google.registry.flows.picker.FlowPicker;
-import google.registry.model.contact.ContactHistory;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.eppcommon.AuthInfo;
@@ -267,23 +266,6 @@ B makeHistoryEntryBuilder(
return builder;
}
- /**
- * Provides a partially filled in {@link ContactHistory.Builder}
- *
- * This is not marked with {@link FlowScope} so that each retry gets a fresh one. Otherwise,
- * the fact that the builder is one-use would cause NPEs.
- */
- @Provides
- static ContactHistory.Builder provideContactHistoryBuilder(
- Trid trid,
- @InputXml byte[] inputXmlBytes,
- @Superuser boolean isSuperuser,
- @RegistrarId String registrarId,
- EppInput eppInput) {
- return makeHistoryEntryBuilder(
- new ContactHistory.Builder(), trid, inputXmlBytes, isSuperuser, registrarId, eppInput);
- }
-
/**
* Provides a partially filled in {@link HostHistory.Builder}
*
diff --git a/core/src/main/java/google/registry/flows/ResourceFlowUtils.java b/core/src/main/java/google/registry/flows/ResourceFlowUtils.java
index 9ceb7150cf3..c52458ac82a 100644
--- a/core/src/main/java/google/registry/flows/ResourceFlowUtils.java
+++ b/core/src/main/java/google/registry/flows/ResourceFlowUtils.java
@@ -16,7 +16,6 @@
import static com.google.common.collect.Sets.intersection;
import static google.registry.model.EppResourceUtils.isLinked;
-import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
@@ -37,7 +36,6 @@
import google.registry.model.EppResource.ForeignKeyedEppResource;
import google.registry.model.EppResource.ResourceWithTransferData;
import google.registry.model.ForeignKeyUtils;
-import google.registry.model.contact.Contact;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Period;
@@ -124,14 +122,6 @@ public static void verifyAuthInfoPresentForResourceTransfer(Optional a
}
}
- /** Check that the given AuthInfo is either missing or else is valid for the given resource. */
- public static void verifyOptionalAuthInfo(Optional authInfo, Contact contact)
- throws EppException {
- if (authInfo.isPresent()) {
- verifyAuthInfo(authInfo.get(), contact);
- }
- }
-
/** Check that the given AuthInfo is either missing or else is valid for the given resource. */
public static void verifyOptionalAuthInfo(Optional authInfo, Domain domain)
throws EppException {
@@ -142,37 +132,14 @@ public static void verifyOptionalAuthInfo(Optional authInfo, Domain do
/** Check that the given {@link AuthInfo} is valid for the given domain. */
public static void verifyAuthInfo(AuthInfo authInfo, Domain domain) throws EppException {
- final String authRepoId = authInfo.getPw().getRepoId();
- String authPassword = authInfo.getPw().getValue();
- if (authRepoId == null) {
- // If no roid is specified, check the password against the domain's password.
- String domainPassword = domain.getAuthInfo().getPw().getValue();
- if (!domainPassword.equals(authPassword)) {
- throw new BadAuthInfoForResourceException();
- }
- return;
- }
- // The roid should match one of the contacts.
- Optional> foundContact =
- domain.getReferencedContacts().stream()
- .filter(key -> key.getKey().equals(authRepoId))
- .findFirst();
- if (foundContact.isEmpty()) {
+ String authRepoId = authInfo.getPw().getRepoId();
+ // Previously one could auth against a contact, but we no longer hold any contact info
+ if (authRepoId != null) {
throw new BadAuthInfoForResourceException();
}
- // Check the authInfo against the contact.
- verifyAuthInfo(authInfo, tm().loadByKey(foundContact.get()));
- }
-
- /** Check that the given {@link AuthInfo} is valid for the given contact. */
- public static void verifyAuthInfo(AuthInfo authInfo, Contact contact) throws EppException {
- String authRepoId = authInfo.getPw().getRepoId();
String authPassword = authInfo.getPw().getValue();
- String contactPassword = contact.getAuthInfo().getPw().getValue();
- if (!contactPassword.equals(authPassword)
- // It's unnecessary to specify a repoId on a contact auth info, but if it's there validate
- // it. The usual case of this is validating a domain's auth using this method.
- || (authRepoId != null && !authRepoId.equals(contact.getRepoId()))) {
+ String domainPassword = domain.getAuthInfo().getPw().getValue();
+ if (!domainPassword.equals(authPassword)) {
throw new BadAuthInfoForResourceException();
}
}
diff --git a/core/src/main/java/google/registry/flows/domain/DomainCreateFlow.java b/core/src/main/java/google/registry/flows/domain/DomainCreateFlow.java
index bc47760546f..9aa7723ef26 100644
--- a/core/src/main/java/google/registry/flows/domain/DomainCreateFlow.java
+++ b/core/src/main/java/google/registry/flows/domain/DomainCreateFlow.java
@@ -167,7 +167,6 @@
* @error {@link DomainFlowUtils.DomainLabelBlockedByBsaException}
* @error {@link DomainFlowUtils.DomainLabelTooLongException}
* @error {@link DomainFlowUtils.DomainReservedException}
- * @error {@link DomainFlowUtils.DuplicateContactForRoleException}
* @error {@link DomainFlowUtils.EmptyDomainNamePartException}
* @error {@link DomainFlowUtils.ExceedsMaxRegistrationYearsException}
* @error {@link DomainFlowUtils.ExpiredClaimException}
@@ -188,7 +187,6 @@
* @error {@link DomainFlowUtils.MaxSigLifeNotSupportedException}
* @error {@link DomainFlowUtils.MissingBillingAccountMapException}
* @error {@link DomainFlowUtils.MissingClaimsNoticeException}
- * @error {@link DomainFlowUtils.MissingContactTypeException}
* @error {@link DomainFlowUtils.NameserversNotAllowedForTldException}
* @error {@link DomainFlowUtils.NameserversNotSpecifiedForTldWithNameserverAllowListException}
* @error {@link DomainFlowUtils.PremiumNameBlockedException}
@@ -221,7 +219,8 @@ public final class DomainCreateFlow implements MutatingFlow {
@Inject DomainPricingLogic pricingLogic;
@Inject DomainDeletionTimeCache domainDeletionTimeCache;
- @Inject DomainCreateFlow() {}
+ @Inject
+ DomainCreateFlow() {}
@Override
public EppResponse run() throws EppException {
@@ -378,12 +377,10 @@ public EppResponse run() throws EppException {
.setLaunchNotice(hasClaimsNotice ? launchCreate.get().getNotice() : null)
.setSmdId(signedMarkId)
.setDsData(secDnsCreate.map(SecDnsCreateExtension::getDsData).orElse(null))
- .setRegistrant(command.getRegistrant())
.setAuthInfo(command.getAuthInfo())
.setDomainName(targetId)
.setNameservers(command.getNameservers().stream().collect(toImmutableSet()))
.setStatusValues(statuses)
- .setContacts(command.getContacts())
.addGracePeriod(
GracePeriod.forBillingEvent(GracePeriodStatus.ADD, repoId, createBillingEvent))
.setLordnPhase(
diff --git a/core/src/main/java/google/registry/flows/domain/DomainFlowTmchUtils.java b/core/src/main/java/google/registry/flows/domain/DomainFlowTmchUtils.java
index 3dcf8994dc7..f0ce2021cac 100644
--- a/core/src/main/java/google/registry/flows/domain/DomainFlowTmchUtils.java
+++ b/core/src/main/java/google/registry/flows/domain/DomainFlowTmchUtils.java
@@ -157,7 +157,8 @@ public Base64RequiredForEncodedSignedMarksException() {
}
/** The provided mark does not match the desired domain label. */
- static class NoMarksFoundMatchingDomainException extends RequiredParameterMissingException {
+ public static class NoMarksFoundMatchingDomainException
+ extends RequiredParameterMissingException {
public NoMarksFoundMatchingDomainException() {
super("The provided mark does not match the desired domain label");
}
diff --git a/core/src/main/java/google/registry/flows/domain/DomainFlowUtils.java b/core/src/main/java/google/registry/flows/domain/DomainFlowUtils.java
index 08da55a759a..1db88bfbe13 100644
--- a/core/src/main/java/google/registry/flows/domain/DomainFlowUtils.java
+++ b/core/src/main/java/google/registry/flows/domain/DomainFlowUtils.java
@@ -19,7 +19,6 @@
import static com.google.common.base.Strings.emptyToNull;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
-import static com.google.common.collect.ImmutableSetMultimap.toImmutableSetMultimap;
import static com.google.common.collect.Sets.difference;
import static com.google.common.collect.Sets.intersection;
import static com.google.common.collect.Sets.union;
@@ -45,10 +44,8 @@
import static google.registry.util.DateTimeUtils.isAtOrAfter;
import static google.registry.util.DateTimeUtils.leapSafeAddYears;
import static google.registry.util.DomainNameUtils.ACE_PREFIX;
-import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.joining;
-import com.google.common.base.Ascii;
import com.google.common.base.CharMatcher;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
@@ -57,9 +54,6 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets;
import com.google.common.collect.Streams;
import com.google.common.net.InternetDomainName;
@@ -81,14 +75,12 @@
import google.registry.model.billing.BillingRecurrence;
import google.registry.model.contact.Contact;
import google.registry.model.domain.DesignatedContact;
-import google.registry.model.domain.DesignatedContact.Type;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainCommand.Create;
import google.registry.model.domain.DomainCommand.CreateOrUpdate;
import google.registry.model.domain.DomainCommand.InvalidReferencesException;
import google.registry.model.domain.DomainCommand.Update;
import google.registry.model.domain.DomainHistory;
-import google.registry.model.domain.ForeignKeyedDesignatedContact;
import google.registry.model.domain.Period;
import google.registry.model.domain.Period.Unit;
import google.registry.model.domain.fee.BaseFee;
@@ -133,10 +125,8 @@
import google.registry.tools.DigestType;
import google.registry.util.Idn;
import java.math.BigDecimal;
-import java.util.Collection;
import java.util.Comparator;
import java.util.List;
-import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
@@ -405,22 +395,11 @@ static Period verifyUnitIsYears(Period period) throws EppException {
return period;
}
- /** Verify that no linked resources have disallowed statuses. */
- static void verifyNotInPendingDelete(
- Set contacts,
- Optional> registrant,
- Set> nameservers)
- throws EppException {
- ImmutableList.Builder> keysToLoad = new ImmutableList.Builder<>();
- contacts.stream().map(DesignatedContact::getContactKey).forEach(keysToLoad::add);
- registrant.ifPresent(keysToLoad::add);
- keysToLoad.addAll(nameservers);
- verifyNotInPendingDelete(EppResource.loadByCacheIfEnabled(keysToLoad.build()).values());
- }
-
- private static void verifyNotInPendingDelete(Iterable resources)
- throws EppException {
- for (EppResource resource : resources) {
+ /** Verify that no linked nameservers have disallowed statuses. */
+ static void verifyNotInPendingDelete(ImmutableSet> nameservers)
+ throws StatusProhibitsOperationException {
+ for (EppResource resource :
+ EppResource.loadByCacheIfEnabled(ImmutableSet.copyOf(nameservers)).values()) {
if (resource.getStatusValues().contains(StatusValue.PENDING_DELETE)) {
throw new LinkedResourceInPendingDeleteProhibitsOperationException(
resource.getForeignKey());
@@ -428,15 +407,6 @@ private static void verifyNotInPendingDelete(Iterable resources)
}
}
- static void validateContactsHaveTypes(Set contacts)
- throws ParameterValuePolicyErrorException {
- for (DesignatedContact contact : contacts) {
- if (contact.getType() == null) {
- throw new MissingContactTypeException();
- }
- }
- }
-
static void validateNameserversCountForTld(String tld, InternetDomainName domainName, int count)
throws EppException {
// For TLDs with a nameserver allow list, all domains must have at least 1 nameserver.
@@ -451,36 +421,22 @@ static void validateNameserversCountForTld(String tld, InternetDomainName domain
}
}
- static void validateNoDuplicateContacts(Set contacts)
+ /** Enforces absence of contact data on creation as part of the Minimum Dataset requirements. */
+ static void enforceContactAbsencesOnCreate(Create create)
throws ParameterValuePolicyErrorException {
- ImmutableMultimap> contactsByType =
- contacts.stream()
- .collect(
- toImmutableSetMultimap(
- DesignatedContact::getType, DesignatedContact::getContactKey));
-
- // If any contact type has multiple contacts:
- if (contactsByType.asMap().values().stream().anyMatch(v -> v.size() > 1)) {
- // Find the duplicates.
- Map>> dupeKeysMap =
- Maps.filterEntries(contactsByType.asMap(), e -> e.getValue().size() > 1);
- ImmutableList> dupeKeys =
- dupeKeysMap.values().stream().flatMap(Collection::stream).collect(toImmutableList());
- // Load the duplicates in one batch.
- Map, Contact> dupeContacts = tm().loadByKeys(dupeKeys);
- ImmutableMultimap.Builder> typesMap = new ImmutableMultimap.Builder<>();
- dupeKeysMap.forEach(typesMap::putAll);
- // Create an error message showing the type and contact IDs of the duplicates.
- throw new DuplicateContactForRoleException(
- Multimaps.transformValues(typesMap.build(), key -> dupeContacts.get(key).getContactId()));
- }
+ enforceContactAbsences(create.getRegistrant(), create.getContacts());
}
- /**
- * Enforces the presence/absence of contact data on domain creates depending on the minimum data
- * set migration schedule.
- */
- static void validateCreateContactData(
+ /** Enforces absence of contact data on update as part of the Minimum Dataset requirements. */
+ static void enforceContactAbsencesOnUpdate(Update update)
+ throws ParameterValuePolicyErrorException {
+ Set allDesignatedContacts =
+ Sets.union(update.getInnerAdd().getContacts(), update.getInnerRemove().getContacts());
+ enforceContactAbsences(update.getInnerChange().getRegistrant(), allDesignatedContacts);
+ }
+
+ /** Enforces the absence of contact data as part of the Minimum Dataset requirements. */
+ static void enforceContactAbsences(
Optional> registrant, Set contacts)
throws ParameterValuePolicyErrorException {
if (registrant.isPresent()) {
@@ -491,25 +447,6 @@ static void validateCreateContactData(
}
}
- /**
- * Enforces the presence/absence of contact data on domain updates depending on the minimum data
- * set migration schedule.
- */
- static void validateUpdateContactData(
- Optional> existingRegistrant,
- Optional> newRegistrant,
- Set existingContacts,
- Set newContacts)
- throws ParameterValuePolicyErrorException {
- // Throw if the update specifies a new registrant that is different from the existing one.
- if (newRegistrant.isPresent() && !newRegistrant.equals(existingRegistrant)) {
- throw new RegistrantProhibitedException();
- }
- // Throw if the update specifies any new contacts that weren't already present on the domain.
- if (!Sets.difference(newContacts, existingContacts).isEmpty()) {
- throw new ContactsProhibitedException();
- }
- }
static void validateNameserversAllowedOnTld(String tld, Set fullyQualifiedHostNames)
throws EppException {
@@ -1032,12 +969,9 @@ public static void verifyNotInPredelegation(Tld registry, DateTime now)
/** Validate the contacts and nameservers specified in a domain create command. */
static void validateCreateCommandContactsAndNameservers(
Create command, Tld tld, InternetDomainName domainName) throws EppException {
- verifyNotInPendingDelete(
- command.getContacts(), command.getRegistrant(), command.getNameservers());
- validateContactsHaveTypes(command.getContacts());
+ verifyNotInPendingDelete(command.getNameservers());
String tldStr = tld.getTldStr();
- validateNoDuplicateContacts(command.getContacts());
- validateCreateContactData(command.getRegistrant(), command.getContacts());
+ enforceContactAbsencesOnCreate(command);
ImmutableSet hostNames = command.getNameserverHostNames();
validateNameserversCountForTld(tldStr, domainName, hostNames.size());
validateNameserversAllowedOnTld(tldStr, hostNames);
@@ -1143,17 +1077,6 @@ static FeeTransformResponseExtension createFeeCreateResponse(
.build();
}
- static ImmutableSet loadForeignKeyedDesignatedContacts(
- ImmutableSet contacts) {
- ImmutableSet.Builder builder = new ImmutableSet.Builder<>();
- for (DesignatedContact contact : contacts) {
- builder.add(
- ForeignKeyedDesignatedContact.create(
- contact.getType(), tm().loadByKey(contact.getContactKey()).getContactId()));
- }
- return builder.build();
- }
-
/**
* Returns a set of DomainTransactionRecords which negate the most recent HistoryEntry's records.
*
@@ -1293,32 +1216,6 @@ public BadPeriodUnitException() {
}
}
- /** Missing type attribute for contact. */
- static class MissingContactTypeException extends ParameterValuePolicyErrorException {
- public MissingContactTypeException() {
- super("Missing type attribute for contact");
- }
- }
-
- /** More than one contact for a given role is not allowed. */
- static class DuplicateContactForRoleException extends ParameterValuePolicyErrorException {
-
- public DuplicateContactForRoleException(Multimap dupeContactsByType) {
- super(
- String.format(
- "More than one contact for a given role is not allowed: %s",
- dupeContactsByType.asMap().entrySet().stream()
- .sorted(comparing(e -> e.getKey().name()))
- .map(
- e ->
- String.format(
- "role [%s] has contacts [%s]",
- Ascii.toLowerCase(e.getKey().name()),
- e.getValue().stream().sorted().collect(joining(", "))))
- .collect(joining(", "))));
- }
- }
-
/** Declared launch extension phase does not match the current registry phase. */
static class LaunchPhaseMismatchException extends ParameterValuePolicyErrorException {
public LaunchPhaseMismatchException() {
diff --git a/core/src/main/java/google/registry/flows/domain/DomainInfoFlow.java b/core/src/main/java/google/registry/flows/domain/DomainInfoFlow.java
index 8522fe8d514..15a9b1b48c9 100644
--- a/core/src/main/java/google/registry/flows/domain/DomainInfoFlow.java
+++ b/core/src/main/java/google/registry/flows/domain/DomainInfoFlow.java
@@ -19,7 +19,6 @@
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo;
import static google.registry.flows.domain.DomainFlowUtils.addSecDnsExtensionIfPresent;
import static google.registry.flows.domain.DomainFlowUtils.handleFeeRequest;
-import static google.registry.flows.domain.DomainFlowUtils.loadForeignKeyedDesignatedContacts;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.common.collect.ImmutableList;
@@ -126,15 +125,11 @@ public EppResponse run() throws EppException {
.setLastEppUpdateTime(domain.getLastEppUpdateTime())
.setRegistrationExpirationTime(domain.getRegistrationExpirationTime())
.setLastTransferTime(domain.getLastTransferTime());
- domain
- .getRegistrant()
- .ifPresent(r -> infoBuilder.setRegistrant(tm().loadByKey(r).getContactId()));
// If authInfo is non-null, then the caller is authorized to see the full information since we
// will have already verified the authInfo is valid.
if (registrarId.equals(domain.getCurrentSponsorRegistrarId()) || authInfo.isPresent()) {
infoBuilder
- .setContacts(loadForeignKeyedDesignatedContacts(domain.getContacts()))
.setSubordinateHosts(
hostsRequest.requestSubordinate() ? domain.getSubordinateHosts() : null)
.setCreationRegistrarId(domain.getCreationRegistrarId())
diff --git a/core/src/main/java/google/registry/flows/domain/DomainUpdateFlow.java b/core/src/main/java/google/registry/flows/domain/DomainUpdateFlow.java
index fc1f494d663..1f565aca585 100644
--- a/core/src/main/java/google/registry/flows/domain/DomainUpdateFlow.java
+++ b/core/src/main/java/google/registry/flows/domain/DomainUpdateFlow.java
@@ -29,14 +29,12 @@
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
import static google.registry.flows.domain.DomainFlowUtils.cloneAndLinkReferences;
+import static google.registry.flows.domain.DomainFlowUtils.enforceContactAbsencesOnUpdate;
import static google.registry.flows.domain.DomainFlowUtils.updateDsData;
-import static google.registry.flows.domain.DomainFlowUtils.validateContactsHaveTypes;
import static google.registry.flows.domain.DomainFlowUtils.validateDsData;
import static google.registry.flows.domain.DomainFlowUtils.validateFeesAckedIfPresent;
import static google.registry.flows.domain.DomainFlowUtils.validateNameserversAllowedOnTld;
import static google.registry.flows.domain.DomainFlowUtils.validateNameserversCountForTld;
-import static google.registry.flows.domain.DomainFlowUtils.validateNoDuplicateContacts;
-import static google.registry.flows.domain.DomainFlowUtils.validateUpdateContactData;
import static google.registry.flows.domain.DomainFlowUtils.verifyClientUpdateNotProhibited;
import static google.registry.flows.domain.DomainFlowUtils.verifyNotInPendingDelete;
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_UPDATE;
@@ -64,8 +62,6 @@
import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingBase.Reason;
import google.registry.model.billing.BillingEvent;
-import google.registry.model.contact.Contact;
-import google.registry.model.domain.DesignatedContact;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainCommand.Update;
import google.registry.model.domain.DomainCommand.Update.AddRemove;
@@ -88,7 +84,6 @@
import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.model.tld.Tld;
-import google.registry.persistence.VKey;
import jakarta.inject.Inject;
import java.util.Objects;
import java.util.Optional;
@@ -97,8 +92,8 @@
/**
* An EPP flow that updates a domain.
*
- * Updates can change contacts, nameservers and delegation signer data of a domain. Updates
- * cannot change the domain's name.
+ *
Updates can change nameservers and delegation signer data of a domain. Updates cannot change
+ * the domain's name.
*
*
Some status values (those of the form "serverSomethingProhibited") can only be applied by the
* superuser. As such, adding or removing these statuses incurs a billing event. There will be only
@@ -113,7 +108,6 @@
* @error {@link google.registry.flows.exceptions.OnlyToolCanPassMetadataException}
* @error {@link google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException}
* @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}
- * @error {@link DomainFlowUtils.DuplicateContactForRoleException}
* @error {@link DomainFlowUtils.EmptySecDnsUpdateException}
* @error {@link DomainFlowUtils.FeesMismatchException}
* @error {@link DomainFlowUtils.FeesRequiredForNonFreeOperationException}
@@ -121,7 +115,6 @@
* @error {@link DomainFlowUtils.LinkedResourcesDoNotExistException}
* @error {@link DomainFlowUtils.LinkedResourceInPendingDeleteProhibitsOperationException}
* @error {@link DomainFlowUtils.MaxSigLifeChangeNotSupportedException}
- * @error {@link DomainFlowUtils.MissingContactTypeException}
* @error {@link DomainFlowUtils.NameserversNotAllowedForTldException}
* @error {@link NameserversNotSpecifiedForTldWithNameserverAllowListException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
@@ -158,7 +151,9 @@ public final class DomainUpdateFlow implements MutatingFlow {
@Inject EppResponse.Builder responseBuilder;
@Inject DomainUpdateFlowCustomLogic flowCustomLogic;
@Inject DomainPricingLogic pricingLogic;
- @Inject DomainUpdateFlow() {}
+
+ @Inject
+ DomainUpdateFlow() {}
@Override
public EppResponse run() throws EppException {
@@ -179,7 +174,7 @@ public EppResponse run() throws EppException {
Domain newDomain = performUpdate(command, existingDomain, now);
DomainHistory domainHistory =
historyBuilder.setType(DOMAIN_UPDATE).setDomain(newDomain).build();
- validateNewState(existingDomain, newDomain);
+ validateNewState(newDomain);
if (requiresDnsUpdate(existingDomain, newDomain)) {
requestDomainDnsRefresh(targetId);
}
@@ -235,12 +230,7 @@ private void verifyUpdateAllowed(Update command, Domain existingDomain, DateTime
eppInput.getSingleExtension(FeeUpdateCommandExtension.class);
FeesAndCredits feesAndCredits = pricingLogic.getUpdatePrice(tld, targetId, now);
validateFeesAckedIfPresent(feeUpdate, feesAndCredits, false);
- verifyNotInPendingDelete(
- add.getContacts(),
- command.getInnerChange().getRegistrant(),
- add.getNameservers());
- validateContactsHaveTypes(add.getContacts());
- validateContactsHaveTypes(remove.getContacts());
+ verifyNotInPendingDelete(add.getNameservers());
validateNameserversAllowedOnTld(tldStr, add.getNameserverHostNames());
}
@@ -250,7 +240,6 @@ private Domain performUpdate(Update command, Domain domain, DateTime now) throws
Optional secDnsUpdate =
eppInput.getSingleExtension(SecDnsUpdateExtension.class);
verifyAddsAndRemoves(domain.getNameservers(), add.getNameservers(), remove.getNameservers());
- verifyAddsAndRemoves(domain.getContacts(), add.getContacts(), remove.getContacts());
verifyAddsAndRemoves(domain.getStatusValues(), add.getStatusValues(), remove.getStatusValues());
if (secDnsUpdate.isPresent()) {
SecDnsUpdateExtension ext = secDnsUpdate.get();
@@ -260,12 +249,7 @@ private Domain performUpdate(Update command, Domain domain, DateTime now) throws
ext.getRemove().map(Remove::getDsData).orElse(ImmutableSet.of()));
}
Change change = command.getInnerChange();
-
- // We have to verify no duplicate contacts _before_ constructing the domain because it is
- // illegal to construct a domain with duplicate contacts.
- Sets.SetView newContacts =
- union(Sets.difference(domain.getContacts(), remove.getContacts()), add.getContacts());
- validateNoDuplicateContacts(newContacts);
+ enforceContactAbsencesOnUpdate(command);
Domain.Builder domainBuilder =
domain
@@ -285,9 +269,6 @@ private Domain performUpdate(Update command, Domain domain, DateTime now) throws
.setLastEppUpdateRegistrarId(registrarId)
.addStatusValues(add.getStatusValues())
.removeStatusValues(remove.getStatusValues())
- .removeContacts(remove.getContacts())
- .addContacts(add.getContacts())
- .setRegistrant(determineUpdatedRegistrant(change, domain))
.setAuthInfo(Optional.ofNullable(change.getAuthInfo()).orElse(domain.getAuthInfo()));
if (!add.getNameservers().isEmpty()) {
@@ -309,15 +290,6 @@ private Domain performUpdate(Update command, Domain domain, DateTime now) throws
return domainBuilder.build();
}
- private Optional> determineUpdatedRegistrant(Change change, Domain domain) {
- // During or after the minimum dataset transition, allow registrant to be removed.
- if (change.getRegistrantContactId().isPresent()
- && change.getRegistrantContactId().get().isEmpty()) {
- return Optional.empty();
- }
- return change.getRegistrant().or(domain::getRegistrant);
- }
-
/**
* Checks whether the new state of the domain is valid.
*
@@ -325,13 +297,7 @@ private Optional> determineUpdatedRegistrant(Change change, Domain
* compliant with the additions or amendments, otherwise existing data can become invalid and
* cause Domain update failure.
*/
- private static void validateNewState(Domain existingDomain, Domain newDomain)
- throws EppException {
- validateUpdateContactData(
- existingDomain.getRegistrant(),
- newDomain.getRegistrant(),
- existingDomain.getContacts(),
- newDomain.getContacts());
+ private static void validateNewState(Domain newDomain) throws EppException {
validateDsData(newDomain.getDsData());
validateNameserversCountForTld(
newDomain.getTld(),
@@ -345,8 +311,8 @@ private Optional createBillingEventForStatusUpdates(
Optional metadataExtension =
eppInput.getSingleExtension(MetadataExtension.class);
if (metadataExtension.isPresent() && metadataExtension.get().getRequestedByRegistrar()) {
- for (StatusValue statusValue
- : symmetricDifference(existingDomain.getStatusValues(), newDomain.getStatusValues())) {
+ for (StatusValue statusValue :
+ symmetricDifference(existingDomain.getStatusValues(), newDomain.getStatusValues())) {
if (statusValue.isChargedStatus()) {
// Only charge once.
return Optional.of(
diff --git a/core/src/main/java/google/registry/module/RequestComponent.java b/core/src/main/java/google/registry/module/RequestComponent.java
index 551b05d8a41..f136150956e 100644
--- a/core/src/main/java/google/registry/module/RequestComponent.java
+++ b/core/src/main/java/google/registry/module/RequestComponent.java
@@ -24,7 +24,6 @@
import google.registry.batch.DeleteProberDataAction;
import google.registry.batch.ExpandBillingRecurrencesAction;
import google.registry.batch.RelockDomainAction;
-import google.registry.batch.RemoveAllDomainContactsAction;
import google.registry.batch.ResaveAllEppResourcesPipelineAction;
import google.registry.batch.ResaveEntityAction;
import google.registry.batch.SendExpiringCertificateNotificationEmailAction;
@@ -276,8 +275,6 @@ interface RequestComponent {
ReadinessProbeActionFrontend readinessProbeActionFrontend();
- RemoveAllDomainContactsAction removeAllDomainContactsAction();
-
RdapAutnumAction rdapAutnumAction();
RdapDomainAction rdapDomainAction();
diff --git a/core/src/test/java/google/registry/batch/RemoveAllDomainContactsActionTest.java b/core/src/test/java/google/registry/batch/RemoveAllDomainContactsActionTest.java
deleted file mode 100644
index 2d358c9e779..00000000000
--- a/core/src/test/java/google/registry/batch/RemoveAllDomainContactsActionTest.java
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2025 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.batch;
-
-import static com.google.common.truth.Truth.assertThat;
-import static google.registry.model.common.FeatureFlag.FeatureName.MINIMUM_DATASET_CONTACTS_PROHIBITED;
-import static google.registry.model.common.FeatureFlag.FeatureStatus.ACTIVE;
-import static google.registry.testing.DatabaseHelper.createTld;
-import static google.registry.testing.DatabaseHelper.loadByEntity;
-import static google.registry.testing.DatabaseHelper.newDomain;
-import static google.registry.testing.DatabaseHelper.persistActiveContact;
-import static google.registry.testing.DatabaseHelper.persistResource;
-import static google.registry.util.DateTimeUtils.START_OF_TIME;
-import static org.mockito.Mockito.mock;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedMap;
-import com.google.common.util.concurrent.RateLimiter;
-import google.registry.flows.DaggerEppTestComponent;
-import google.registry.flows.EppController;
-import google.registry.flows.EppTestComponent.FakesAndMocksModule;
-import google.registry.model.common.FeatureFlag;
-import google.registry.model.contact.Contact;
-import google.registry.model.domain.Domain;
-import google.registry.persistence.transaction.JpaTestExtensions;
-import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
-import google.registry.testing.FakeClock;
-import google.registry.testing.FakeLockHandler;
-import google.registry.testing.FakeResponse;
-import java.util.Optional;
-import org.joda.time.DateTime;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-/** Unit tests for {@link RemoveAllDomainContactsAction}. */
-class RemoveAllDomainContactsActionTest {
-
- @RegisterExtension
- final JpaIntegrationTestExtension jpa =
- new JpaTestExtensions.Builder().buildIntegrationTestExtension();
-
- private final FakeResponse response = new FakeResponse();
- private final RateLimiter rateLimiter = mock(RateLimiter.class);
- private RemoveAllDomainContactsAction action;
-
- @BeforeEach
- void beforeEach() {
- createTld("tld");
- persistResource(
- new FeatureFlag.Builder()
- .setFeatureName(MINIMUM_DATASET_CONTACTS_PROHIBITED)
- .setStatusMap(ImmutableSortedMap.of(START_OF_TIME, ACTIVE))
- .build());
- EppController eppController =
- DaggerEppTestComponent.builder()
- .fakesAndMocksModule(FakesAndMocksModule.create(new FakeClock()))
- .build()
- .startRequest()
- .eppController();
- action =
- new RemoveAllDomainContactsAction(
- eppController, "NewRegistrar", new FakeLockHandler(true), rateLimiter, response);
- }
-
- @Test
- void test_removesAllContactsFromMultipleDomains_andDoesntModifyDomainThatHasNoContacts() {
- Contact c1 = persistActiveContact("contact12345");
- Domain d1 = persistResource(newDomain("foo.tld", c1));
- assertThat(d1.getAllContacts()).hasSize(3);
- Contact c2 = persistActiveContact("contact23456");
- Domain d2 = persistResource(newDomain("bar.tld", c2));
- assertThat(d2.getAllContacts()).hasSize(3);
- Domain d3 =
- persistResource(
- newDomain("baz.tld")
- .asBuilder()
- .setRegistrant(Optional.empty())
- .setContacts(ImmutableSet.of())
- .build());
- assertThat(d3.getAllContacts()).isEmpty();
- DateTime lastUpdate = d3.getUpdateTimestamp().getTimestamp();
-
- action.run();
- assertThat(loadByEntity(d1).getAllContacts()).isEmpty();
- assertThat(loadByEntity(d2).getAllContacts()).isEmpty();
- assertThat(loadByEntity(d3).getUpdateTimestamp().getTimestamp()).isEqualTo(lastUpdate);
- }
-
- @Test
- void test_removesContacts_onDomainsThatOnlyPartiallyHaveContacts() {
- Contact c1 = persistActiveContact("contact12345");
- Domain d1 =
- persistResource(
- newDomain("foo.tld", c1).asBuilder().setContacts(ImmutableSet.of()).build());
- assertThat(d1.getAllContacts()).hasSize(1);
- Contact c2 = persistActiveContact("contact23456");
- Domain d2 =
- persistResource(
- newDomain("bar.tld", c2).asBuilder().setRegistrant(Optional.empty()).build());
- assertThat(d2.getAllContacts()).hasSize(2);
-
- action.run();
- assertThat(loadByEntity(d1).getAllContacts()).isEmpty();
- assertThat(loadByEntity(d2).getAllContacts()).isEmpty();
- }
-}
diff --git a/core/src/test/java/google/registry/flows/domain/DomainCreateFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainCreateFlowTest.java
index 77ba1c404e9..71f93f598b1 100644
--- a/core/src/test/java/google/registry/flows/domain/DomainCreateFlowTest.java
+++ b/core/src/test/java/google/registry/flows/domain/DomainCreateFlowTest.java
@@ -119,7 +119,6 @@
import google.registry.flows.domain.DomainFlowUtils.MaxSigLifeNotSupportedException;
import google.registry.flows.domain.DomainFlowUtils.MissingBillingAccountMapException;
import google.registry.flows.domain.DomainFlowUtils.MissingClaimsNoticeException;
-import google.registry.flows.domain.DomainFlowUtils.MissingContactTypeException;
import google.registry.flows.domain.DomainFlowUtils.NameserversNotAllowedForTldException;
import google.registry.flows.domain.DomainFlowUtils.NameserversNotSpecifiedForTldWithNameserverAllowListException;
import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException;
@@ -1874,15 +1873,6 @@ void testSuccess_customLogicIsCalled_andSavesExtraEntity() throws Exception {
.build());
}
- @Test
- void testFailure_missingContactType() {
- // We need to test for missing type, but not for invalid - the schema enforces that for us.
- setEppInput("domain_create_missing_contact_type.xml");
- persistContactsAndHosts();
- EppException thrown = assertThrows(MissingContactTypeException.class, this::runFlow);
- assertAboutEppExceptions().that(thrown).marshalsToXml();
- }
-
@Test
void testFailure_minimumDataset_noRegistrantButSomeOtherContactTypes() throws Exception {
setEppInput("domain_create_other_contact_types.xml");
diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferApproveFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainTransferApproveFlowTest.java
index 21d2a8fb2bd..aafa9387236 100644
--- a/core/src/test/java/google/registry/flows/domain/DomainTransferApproveFlowTest.java
+++ b/core/src/test/java/google/registry/flows/domain/DomainTransferApproveFlowTest.java
@@ -64,7 +64,6 @@
import google.registry.model.billing.BillingCancellation;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingRecurrence;
-import google.registry.model.contact.ContactAuthInfo;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainAuthInfo;
import google.registry.model.domain.DomainHistory;
@@ -153,12 +152,6 @@ private void assertTransferApproved(Domain domain, DomainTransferData oldTransfe
.build());
}
- private void setEppLoader(String commandFilename) {
- setEppInput(commandFilename);
- // Replace the ROID in the xml file with the one generated in our test.
- eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
- }
-
/**
* Runs a successful test, with the expectedCancellationBillingEvents parameter containing a list
* of billing event builders that will be filled out with the correct HistoryEntry parent as it is
@@ -184,7 +177,7 @@ private void runSuccessfulFlowWithAssertions(
String expectedXmlFilename,
DateTime expectedExpirationTime)
throws Exception {
- setEppLoader(commandFilename);
+ setEppInput(commandFilename);
Tld registry = Tld.get(tld);
domain = reloadResourceByForeignKey();
// Make sure the implicit billing event is there; it will be deleted by the flow.
@@ -361,7 +354,7 @@ private void doSuccessfulTest(String tld, String commandFilename, String expecte
}
private void doFailingTest(String commandFilename) throws Exception {
- setEppLoader(commandFilename);
+ setEppInput(commandFilename);
// Setup done; run the test.
assertMutatingFlow(true);
runFlow();
@@ -376,7 +369,7 @@ void testNotLoggedIn() {
@Test
void testDryRun() throws Exception {
- setEppLoader("domain_transfer_approve.xml");
+ setEppInput("domain_transfer_approve.xml");
dryRunFlowAssertResponse(loadFile("domain_transfer_approve_response.xml"));
}
@@ -492,14 +485,6 @@ void testSuccess_domainAuthInfo() throws Exception {
"domain_transfer_approve_response.xml");
}
- @Test
- void testSuccess_contactAuthInfo() throws Exception {
- doSuccessfulTest(
- "tld",
- "domain_transfer_approve_contact_authinfo.xml",
- "domain_transfer_approve_response.xml");
- }
-
@Test
void testSuccess_autorenewBeforeTransfer() throws Exception {
domain = reloadResourceByForeignKey();
@@ -619,14 +604,8 @@ void testSuccess_specifiedPriceRenewalBehavior_carriesOver() throws Exception {
}
@Test
- void testFailure_badContactPassword() {
- // Change the contact's password so it does not match the password in the file.
- contact =
- persistResource(
- contact
- .asBuilder()
- .setAuthInfo(ContactAuthInfo.create(PasswordAuth.create("badpassword")))
- .build());
+ void testFailure_contactPassword() {
+ // Contact passwords cannot be provided because we don't store contacts
EppException thrown =
assertThrows(
BadAuthInfoForResourceException.class,
diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferCancelFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainTransferCancelFlowTest.java
index 81457833821..c7b62116bb8 100644
--- a/core/src/test/java/google/registry/flows/domain/DomainTransferCancelFlowTest.java
+++ b/core/src/test/java/google/registry/flows/domain/DomainTransferCancelFlowTest.java
@@ -43,7 +43,6 @@
import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException;
import google.registry.flows.exceptions.NotPendingTransferException;
import google.registry.flows.exceptions.NotTransferInitiatorException;
-import google.registry.model.contact.ContactAuthInfo;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainAuthInfo;
import google.registry.model.domain.DomainHistory;
@@ -75,8 +74,6 @@ void beforeEach() {
private void doSuccessfulTest(String commandFilename) throws Exception {
setEppInput(commandFilename);
- // Replace the ROID in the xml file with the one generated in our test.
- eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
// Make sure the implicit billing event is there; it will be deleted by the flow.
// We also expect to see autorenew events for the gaining and losing registrars.
assertBillingEvents(
@@ -187,8 +184,6 @@ private void doSuccessfulTest(String commandFilename) throws Exception {
private void doFailingTest(String commandFilename) throws Exception {
setEppInput(commandFilename);
- // Replace the ROID in the xml file with the one generated in our test.
- eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
// Setup done; run the test.
assertMutatingFlow(true);
runFlow();
@@ -204,7 +199,6 @@ void testNotLoggedIn() {
@Test
void testDryRun() throws Exception {
setEppInput("domain_transfer_cancel.xml");
- eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
dryRunFlowAssertResponse(loadFile("domain_transfer_cancel_response.xml"));
}
@@ -219,19 +213,8 @@ void testSuccess_domainAuthInfo() throws Exception {
}
@Test
- void testSuccess_contactAuthInfo() throws Exception {
- doSuccessfulTest("domain_transfer_cancel_contact_authinfo.xml");
- }
-
- @Test
- void testFailure_badContactPassword() {
- // Change the contact's password so it does not match the password in the file.
- contact =
- persistResource(
- contact
- .asBuilder()
- .setAuthInfo(ContactAuthInfo.create(PasswordAuth.create("badpassword")))
- .build());
+ void testFailure_contactPassword() {
+ // Contact passwords cannot be provided because we don't store contacts
EppException thrown =
assertThrows(
BadAuthInfoForResourceException.class,
diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferFlowTestCase.java b/core/src/test/java/google/registry/flows/domain/DomainTransferFlowTestCase.java
index d337fb78d05..49c1dfd8b52 100644
--- a/core/src/test/java/google/registry/flows/domain/DomainTransferFlowTestCase.java
+++ b/core/src/test/java/google/registry/flows/domain/DomainTransferFlowTestCase.java
@@ -20,7 +20,6 @@
import static google.registry.testing.DatabaseHelper.createBillingEventForTransfer;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.getOnlyHistoryEntryOfType;
-import static google.registry.testing.DatabaseHelper.persistActiveContact;
import static google.registry.testing.DatabaseHelper.persistDomainWithDependentResources;
import static google.registry.testing.DatabaseHelper.persistDomainWithPendingTransfer;
import static google.registry.testing.DatabaseHelper.persistResource;
@@ -36,7 +35,6 @@
import google.registry.model.billing.BillingBase.Reason;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingRecurrence;
-import google.registry.model.contact.Contact;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.eppcommon.StatusValue;
@@ -72,7 +70,6 @@ abstract class DomainTransferFlowTestCase
static final DateTime EXTENDED_REGISTRATION_EXPIRATION_TIME =
REGISTRATION_EXPIRATION_TIME.plusYears(EXTENDED_REGISTRATION_YEARS);
- protected Contact contact;
protected Domain domain;
Host subordinateHost;
private DomainHistory historyEntryDomainCreate;
@@ -104,12 +101,11 @@ static Domain persistWithPendingTransfer(Domain domain) {
/** Adds a domain with no pending transfer on it. */
void setupDomain(String label, String tld) {
createTld(tld);
- contact = persistActiveContact("jd1234");
domain =
persistDomainWithDependentResources(
label,
tld,
- contact,
+ null,
clock.nowUtc(),
DateTime.parse("1999-04-03T22:00:00.0Z"),
REGISTRATION_EXPIRATION_TIME);
diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferQueryFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainTransferQueryFlowTest.java
index 7297dcdb347..523120f4ade 100644
--- a/core/src/test/java/google/registry/flows/domain/DomainTransferQueryFlowTest.java
+++ b/core/src/test/java/google/registry/flows/domain/DomainTransferQueryFlowTest.java
@@ -29,7 +29,6 @@
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
import google.registry.flows.exceptions.NoTransferHistoryToQueryException;
import google.registry.flows.exceptions.NotAuthorizedToViewTransferException;
-import google.registry.model.contact.ContactAuthInfo;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainAuthInfo;
import google.registry.model.eppcommon.AuthInfo.PasswordAuth;
@@ -52,8 +51,6 @@ void beforeEach() {
private void doSuccessfulTest(
String commandFilename, String expectedXmlFilename, int numPollMessages) throws Exception {
setEppInput(commandFilename);
- // Replace the ROID in the xml file with the one generated in our test.
- eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
// Setup done; run the test.
assertMutatingFlow(false);
runFlowAssertResponse(loadFile(expectedXmlFilename));
@@ -73,8 +70,6 @@ private void doSuccessfulTest(
private void doFailingTest(String commandFilename) throws Exception {
setEppInput(commandFilename);
- // Replace the ROID in the xml file with the one generated in our test.
- eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
// Setup done; run the test.
assertMutatingFlow(false);
runFlow();
@@ -105,13 +100,6 @@ void testSuccess_domainAuthInfo() throws Exception {
"domain_transfer_query_domain_authinfo.xml", "domain_transfer_query_response.xml", 1);
}
- @Test
- void testSuccess_contactAuthInfo() throws Exception {
- setRegistrarIdForFlow("ClientZ");
- doSuccessfulTest(
- "domain_transfer_query_contact_authinfo.xml", "domain_transfer_query_response.xml", 1);
- }
-
@Test
void testSuccess_clientApproved() throws Exception {
changeTransferStatus(TransferStatus.CLIENT_APPROVED);
@@ -170,14 +158,7 @@ void testFailure_pendingDeleteDomain() throws Exception {
}
@Test
- void testFailure_badContactPassword() {
- // Change the contact's password so it does not match the password in the file.
- contact =
- persistResource(
- contact
- .asBuilder()
- .setAuthInfo(ContactAuthInfo.create(PasswordAuth.create("badpassword")))
- .build());
+ void testFailure_contactPasswordNotAllowed() {
EppException thrown =
assertThrows(
BadAuthInfoForResourceException.class,
diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferRejectFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainTransferRejectFlowTest.java
index 8179c2811a6..e5ab76f612c 100644
--- a/core/src/test/java/google/registry/flows/domain/DomainTransferRejectFlowTest.java
+++ b/core/src/test/java/google/registry/flows/domain/DomainTransferRejectFlowTest.java
@@ -43,7 +43,6 @@
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException;
import google.registry.flows.exceptions.NotPendingTransferException;
-import google.registry.model.contact.ContactAuthInfo;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainAuthInfo;
import google.registry.model.domain.DomainHistory;
@@ -78,7 +77,6 @@ void beforeEach() {
private void doSuccessfulTest(String commandFilename, String expectedXmlFilename)
throws Exception {
setEppInput(commandFilename);
- eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
// Make sure the implicit billing event is there; it will be deleted by the flow.
// We also expect to see autorenew events for the gaining and losing registrars.
assertBillingEvents(
@@ -149,8 +147,6 @@ private void doSuccessfulTest(String commandFilename, String expectedXmlFilename
private void doFailingTest(String commandFilename) throws Exception {
setEppInput(commandFilename);
- // Replace the ROID in the xml file with the one generated in our test.
- eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
// Setup done; run the test.
assertMutatingFlow(true);
runFlow();
@@ -171,7 +167,6 @@ void testSuccess() throws Exception {
@Test
void testDryRun() throws Exception {
setEppInput("domain_transfer_reject.xml");
- eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
dryRunFlowAssertResponse(loadFile("domain_transfer_reject_response.xml"));
}
@@ -181,12 +176,6 @@ void testSuccess_domainAuthInfo() throws Exception {
"domain_transfer_reject_domain_authinfo.xml", "domain_transfer_reject_response.xml");
}
- @Test
- void testSuccess_contactAuthInfo() throws Exception {
- doSuccessfulTest(
- "domain_transfer_reject_contact_authinfo.xml", "domain_transfer_reject_response.xml");
- }
-
@Test
void testFailure_notAuthorizedForTld() {
persistResource(
@@ -209,14 +198,8 @@ void testSuccess_superuserNotAuthorizedForTld() throws Exception {
}
@Test
- void testFailure_badContactPassword() {
- // Change the contact's password so it does not match the password in the file.
- contact =
- persistResource(
- contact
- .asBuilder()
- .setAuthInfo(ContactAuthInfo.create(PasswordAuth.create("badpassword")))
- .build());
+ void testFailure_contactPassword() {
+ // Contact passwords cannot be provided because we don't store contacts
EppException thrown =
assertThrows(
BadAuthInfoForResourceException.class,
diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java
index 9aaf221d65d..70ad4517e37 100644
--- a/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java
+++ b/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java
@@ -40,7 +40,6 @@
import static google.registry.testing.DatabaseHelper.loadByKey;
import static google.registry.testing.DatabaseHelper.loadByKeys;
import static google.registry.testing.DatabaseHelper.loadRegistrar;
-import static google.registry.testing.DatabaseHelper.persistActiveContact;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.DomainSubject.assertAboutDomains;
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
@@ -96,7 +95,6 @@
import google.registry.model.billing.BillingCancellation;
import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingRecurrence;
-import google.registry.model.contact.ContactAuthInfo;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainAuthInfo;
import google.registry.model.domain.DomainHistory;
@@ -470,8 +468,6 @@ private void doSuccessfulTest(
throws Exception {
setEppInput(commandFilename, substitutions);
ImmutableSet originalGracePeriods = domain.getGracePeriods();
- // Replace the ROID in the xml file with the one generated in our test.
- eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
// For all of the other transfer flow tests, 'now' corresponds to day 3 of the transfer, but
// for the request test we want that same 'now' to be the initial request time, so we shift
// the transfer timeline 3 days later by adjusting the implicit transfer time here.
@@ -571,8 +567,6 @@ private void doSuccessfulSuperuserExtensionTest(
eppRequestSource = EppRequestSource.TOOL;
setEppInput(commandFilename, substitutions);
ImmutableSet originalGracePeriods = domain.getGracePeriods();
- // Replace the ROID in the xml file with the one generated in our test.
- eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
// For all of the other transfer flow tests, 'now' corresponds to day 3 of the transfer, but
// for the request test we want that same 'now' to be the initial request time, so we shift
// the transfer timeline 3 days later by adjusting the implicit transfer time here.
@@ -626,8 +620,6 @@ private void runTest(
String commandFilename, UserPrivileges userPrivileges, Map substitutions)
throws Exception {
setEppInput(commandFilename, substitutions);
- // Replace the ROID in the xml file with the one generated in our test.
- eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
// Setup done; run the test.
assertMutatingFlow(true);
runFlow(CommitMode.LIVE, userPrivileges);
@@ -657,7 +649,6 @@ void testNotLoggedIn() {
void testDryRun() throws Exception {
setupDomain("example", "tld");
setEppInput("domain_transfer_request.xml");
- eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
dryRunFlowAssertResponse(loadFile("domain_transfer_request_response.xml"));
}
@@ -1184,7 +1175,6 @@ void testSuccess_nonPremiumRenewalPrice_isReflectedInTransferCostAndCarriesOver(
// This ensures that the transfer has non-premium cost, as otherwise, the fee extension would be
// required to ack the premium price.
setEppInput("domain_transfer_request.xml");
- eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
runFlowAssertResponse(loadFile("domain_transfer_request_response.xml"));
domain = loadByEntity(domain);
@@ -1238,7 +1228,6 @@ void testSuccess_specifiedRenewalPrice_isReflectedInTransferCostAndCarriesOver()
DateTime now = clock.nowUtc();
setEppInput("domain_transfer_request.xml");
- eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
runFlowAssertResponse(loadFile("domain_transfer_request_response.xml"));
domain = loadByEntity(domain);
@@ -1300,7 +1289,6 @@ void testSuccess_specifiedRenewalPrice_notCarriedOverForBulkPricingName() throws
DateTime now = clock.nowUtc();
setEppInput("domain_transfer_request.xml");
- eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
runFlowAssertResponse(loadFile("domain_transfer_request_response.xml"));
domain = loadByEntity(domain);
@@ -1361,7 +1349,6 @@ void testSuccess_defaultRenewalPrice_carriedOverForBulkPricingName() throws Exce
DateTime now = clock.nowUtc();
setEppInput("domain_transfer_request.xml");
- eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
runFlowAssertResponse(loadFile("domain_transfer_request_response.xml"));
domain = loadByEntity(domain);
@@ -1518,36 +1505,6 @@ void testFailure_noAuthInfo() {
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
- @Test
- void testFailure_badContactPassword() {
- setupDomain("example", "tld");
- // Change the contact's password so it does not match the password in the file.
- contact =
- persistResource(
- contact
- .asBuilder()
- .setAuthInfo(ContactAuthInfo.create(PasswordAuth.create("badpassword")))
- .build());
- EppException thrown =
- assertThrows(
- BadAuthInfoForResourceException.class,
- () -> doFailingTest("domain_transfer_request.xml"));
- assertAboutEppExceptions().that(thrown).marshalsToXml();
- }
-
- @Test
- void testFailure_badContactRepoId() {
- setupDomain("example", "tld");
- // Set the contact to a different ROID, but don't persist it; this is just so the substitution
- // code above will write the wrong ROID into the file.
- contact = contact.asBuilder().setRepoId("DEADBEEF_TLD-ROID").build();
- EppException thrown =
- assertThrows(
- BadAuthInfoForResourceException.class,
- () -> doFailingTest("domain_transfer_request.xml"));
- assertAboutEppExceptions().that(thrown).marshalsToXml();
- }
-
@Test
void testSuccess_clientApproved() throws Exception {
setupDomain("example", "tld");
@@ -1651,7 +1608,6 @@ void testFailure_invalidDomain() throws Exception {
setEppInput(
"domain_transfer_request_wildcard.xml",
ImmutableMap.of("YEARS", "1", "DOMAIN", "--invalid", "EXDATE", "2002-09-08T22:00:00.0Z"));
- eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
assertMutatingFlow(true);
ResourceDoesNotExistException thrown =
assertThrows(
@@ -1663,7 +1619,6 @@ void testFailure_invalidDomain() throws Exception {
@Test
void testFailure_nonexistentDomain() {
createTld("tld");
- contact = persistActiveContact("jd1234");
ResourceDoesNotExistException thrown =
assertThrows(
ResourceDoesNotExistException.class,
@@ -1671,6 +1626,22 @@ void testFailure_nonexistentDomain() {
assertThat(thrown).hasMessageThat().contains(String.format("(%s)", "example.tld"));
}
+ @Test
+ void testFailure_cannotUseContactAuthInfo() {
+ // RFC 5731: "An OPTIONAL "roid" attribute MUST be used to identify the registrant or contact
+ // object if and only if the given authInfo is associated with a registrant or contact object,
+ // and not the domain object itself."
+ //
+ // We have no contacts, so it cannot be valid to specify a roid
+ setupDomain("example", "tld");
+ assertAboutEppExceptions()
+ .that(
+ assertThrows(
+ BadAuthInfoForResourceException.class,
+ () -> doFailingTest("domain_transfer_request_contact_auth_info_failure.xml")))
+ .marshalsToXml();
+ }
+
@Test
void testFailure_periodInMonths() {
setupDomain("example", "tld");
diff --git a/core/src/test/resources/google/registry/flows/domain/domain_create_missing_contact_type.xml b/core/src/test/resources/google/registry/flows/domain/domain_create_missing_contact_type.xml
deleted file mode 100644
index d78add11645..00000000000
--- a/core/src/test/resources/google/registry/flows/domain/domain_create_missing_contact_type.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
- example.tld
- 2
-
- ns1.example.net
- ns2.example.net
-
- sh8013
-
- 2fooBAR
-
-
-
- ABC-12345
-
-
diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request.xml
index 45f757e8c12..947ef66fc0e 100644
--- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request.xml
+++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request.xml
@@ -6,7 +6,7 @@
example.tld
1
- 2fooBAR
+ fooBAR
diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_allocation_token.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_allocation_token.xml
index 6064c60e113..d8b179f1f58 100644
--- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_allocation_token.xml
+++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_allocation_token.xml
@@ -6,7 +6,7 @@
example.tld
1
- 2fooBAR
+ fooBAR
diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_contact_auth_info_failure.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_contact_auth_info_failure.xml
new file mode 100644
index 00000000000..895ec5292c6
--- /dev/null
+++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_contact_auth_info_failure.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ example.tld
+ 1
+
+ 2fooBAR
+
+
+
+ ABC-12345
+
+
diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee.xml
index 32ffebcd2e2..5685179f0f0 100644
--- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee.xml
+++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee.xml
@@ -6,7 +6,7 @@
%DOMAIN%
%YEARS%
- 2fooBAR
+ fooBAR
diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_applied.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_applied.xml
index ace1d334e63..4f5cd08745d 100644
--- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_applied.xml
+++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_applied.xml
@@ -6,7 +6,7 @@
example.tld
1
- 2fooBAR
+ fooBAR
diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_bad_scale.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_bad_scale.xml
index cb0f8e0ee73..313eb810d96 100644
--- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_bad_scale.xml
+++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_bad_scale.xml
@@ -6,7 +6,7 @@
example.tld
1
- 2fooBAR
+ fooBAR
diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_defaults.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_defaults.xml
index 3c8dd64890b..a169b5bca7f 100644
--- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_defaults.xml
+++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_defaults.xml
@@ -6,7 +6,7 @@
example.tld
1
- 2fooBAR
+ fooBAR
diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_grace_period.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_grace_period.xml
index 1b25e13029f..5486694d3e5 100644
--- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_grace_period.xml
+++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_grace_period.xml
@@ -6,7 +6,7 @@
example.tld
1
- 2fooBAR
+ fooBAR
diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_refundable.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_refundable.xml
index 097132cc08f..17b5d2950d0 100644
--- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_refundable.xml
+++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_fee_refundable.xml
@@ -6,7 +6,7 @@
example.tld
1
- 2fooBAR
+ fooBAR
diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_missing_period.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_missing_period.xml
index 0981c182f96..eb6b8266b43 100644
--- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_missing_period.xml
+++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_missing_period.xml
@@ -5,7 +5,7 @@
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
example.tld
- 2fooBAR
+ fooBAR
diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_months.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_months.xml
index f509beaee2d..e08f12f57df 100644
--- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_months.xml
+++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_months.xml
@@ -6,7 +6,7 @@
example.tld
1
- 2fooBAR
+ fooBAR
diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_premium.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_premium.xml
index 2380336d297..f8d93bd9495 100644
--- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_premium.xml
+++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_premium.xml
@@ -6,7 +6,7 @@
rich.example
1
- 2fooBAR
+ fooBAR
diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_separate_fees.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_separate_fees.xml
index 44e733a2a43..9c6d679b4b2 100644
--- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_separate_fees.xml
+++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_separate_fees.xml
@@ -6,7 +6,7 @@
%DOMAIN%
%YEARS%
- 2fooBAR
+ fooBAR
diff --git a/core/src/test/resources/google/registry/module/routing.txt b/core/src/test/resources/google/registry/module/routing.txt
index afb28e832a1..b429eceea7b 100644
--- a/core/src/test/resources/google/registry/module/routing.txt
+++ b/core/src/test/resources/google/registry/module/routing.txt
@@ -46,7 +46,6 @@ BACKEND /_dr/task/readDnsRefreshRequests ReadDnsRefreshReques
BACKEND /_dr/task/refreshDnsForAllDomains RefreshDnsForAllDomainsAction GET n APP ADMIN
BACKEND /_dr/task/refreshDnsOnHostRename RefreshDnsOnHostRenameAction POST n APP ADMIN
BACKEND /_dr/task/relockDomain RelockDomainAction POST y APP ADMIN
-BACKEND /_dr/task/removeAllDomainContacts RemoveAllDomainContactsAction POST n APP ADMIN
BACKEND /_dr/task/resaveAllEppResourcesPipeline ResaveAllEppResourcesPipelineAction GET n APP ADMIN
BACKEND /_dr/task/resaveEntity ResaveEntityAction POST n APP ADMIN
BACKEND /_dr/task/sendExpiringCertificateNotificationEmail SendExpiringCertificateNotificationEmailAction GET n APP ADMIN