From d88b0ade4c8c7ff9a2b8a6012faccd774f8af528 Mon Sep 17 00:00:00 2001 From: Gus Brodman Date: Tue, 27 Jan 2026 17:14:02 -0500 Subject: [PATCH] Remove references to contacts in domain flows We've moved on from contacts entirely now so the only thing we really need to do is make sure that people don't include contacts in domain creates or updates. This also makes auth code checking easier too, because now the only auth code that you're allowed to provide is the domain auth code (not a contact auth code) --- .../batch/RemoveAllDomainContactsAction.java | 238 ------------------ .../google/registry/flows/FlowModule.java | 18 -- .../registry/flows/ResourceFlowUtils.java | 43 +--- .../flows/domain/DomainCreateFlow.java | 7 +- .../flows/domain/DomainFlowTmchUtils.java | 3 +- .../flows/domain/DomainFlowUtils.java | 143 ++--------- .../registry/flows/domain/DomainInfoFlow.java | 5 - .../flows/domain/DomainUpdateFlow.java | 58 +---- .../registry/module/RequestComponent.java | 3 - .../RemoveAllDomainContactsActionTest.java | 119 --------- .../flows/domain/DomainCreateFlowTest.java | 10 - .../domain/DomainTransferApproveFlowTest.java | 31 +-- .../domain/DomainTransferCancelFlowTest.java | 21 +- .../domain/DomainTransferFlowTestCase.java | 6 +- .../domain/DomainTransferQueryFlowTest.java | 21 +- .../domain/DomainTransferRejectFlowTest.java | 21 +- .../domain/DomainTransferRequestFlowTest.java | 61 ++--- .../domain_create_missing_contact_type.xml | 20 -- .../flows/domain/domain_transfer_request.xml | 2 +- ...main_transfer_request_allocation_token.xml | 2 +- ...sfer_request_contact_auth_info_failure.xml | 15 ++ .../domain/domain_transfer_request_fee.xml | 2 +- .../domain_transfer_request_fee_applied.xml | 2 +- .../domain_transfer_request_fee_bad_scale.xml | 2 +- .../domain_transfer_request_fee_defaults.xml | 2 +- ...main_transfer_request_fee_grace_period.xml | 2 +- ...domain_transfer_request_fee_refundable.xml | 2 +- ...domain_transfer_request_missing_period.xml | 2 +- .../domain/domain_transfer_request_months.xml | 2 +- .../domain_transfer_request_premium.xml | 2 +- .../domain_transfer_request_separate_fees.xml | 2 +- .../google/registry/module/routing.txt | 1 - 32 files changed, 95 insertions(+), 773 deletions(-) delete mode 100644 core/src/main/java/google/registry/batch/RemoveAllDomainContactsAction.java delete mode 100644 core/src/test/java/google/registry/batch/RemoveAllDomainContactsActionTest.java delete mode 100644 core/src/test/resources/google/registry/flows/domain/domain_create_missing_contact_type.xml create mode 100644 core/src/test/resources/google/registry/flows/domain/domain_transfer_request_contact_auth_info_failure.xml 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