From cd13f6c5d3e38e1af49885e81ca6b210c6837485 Mon Sep 17 00:00:00 2001 From: Ben McIlwain Date: Fri, 24 Apr 2020 18:06:27 -0400 Subject: [PATCH] Allow the `nomulus renew_domain` command to specify the client ID (#567) * Allow the `nomulus renew_domain` command to specify the client ID This means that a superuser can renew a domain and have the associated history entry, one time billing event, and renewal grace period be recorded against a specified registrar rather than the owning registrar of the domain. This is useful to e.g. renew a domain for free by "charging" the renewal to the registry's fake registrar. Since the grace period is written to the specified cliend id as well, if the actual registrar deletes the domain, they don't get back the money that they didn't pay in the first place. --- .../registry/tools/RenewDomainCommand.java | 10 ++- .../flows/domain/DomainRenewFlowTest.java | 38 ++++++++-- .../tools/RenewDomainCommandTest.java | 74 ++++++++++++++----- 3 files changed, 95 insertions(+), 27 deletions(-) diff --git a/core/src/main/java/google/registry/tools/RenewDomainCommand.java b/core/src/main/java/google/registry/tools/RenewDomainCommand.java index 0ddcc9f61..7f820d210 100644 --- a/core/src/main/java/google/registry/tools/RenewDomainCommand.java +++ b/core/src/main/java/google/registry/tools/RenewDomainCommand.java @@ -15,6 +15,7 @@ package google.registry.tools; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Strings.isNullOrEmpty; import static google.registry.model.EppResourceUtils.loadByForeignKey; import static google.registry.util.CollectionUtils.findDuplicates; import static google.registry.util.PreconditionsUtils.checkArgumentPresent; @@ -37,6 +38,13 @@ import org.joda.time.format.DateTimeFormatter; @Parameters(separators = " =", commandDescription = "Renew domain(s) via EPP.") final class RenewDomainCommand extends MutatingEppToolCommand { + @Parameter( + names = {"-c", "--client"}, + description = + "The registrar to execute as and bill the renewal to; otherwise each domain's sponsoring" + + " registrar. Renewals by non-sponsoring registrars require --superuser as well.") + String clientId; + @Parameter( names = {"-p", "--period"}, description = "Number of years to renew the registration for (defaults to 1).") @@ -63,7 +71,7 @@ final class RenewDomainCommand extends MutatingEppToolCommand { setSoyTemplate(RenewDomainSoyInfo.getInstance(), RenewDomainSoyInfo.RENEWDOMAIN); DomainBase domain = domainOptional.get(); addSoyRecord( - domain.getCurrentSponsorClientId(), + isNullOrEmpty(clientId) ? domain.getCurrentSponsorClientId() : clientId, new SoyMapData( "domainName", domain.getFullyQualifiedDomainName(), "expirationDate", domain.getRegistrationExpirationTime().toString(DATE_FORMATTER), diff --git a/core/src/test/java/google/registry/flows/domain/DomainRenewFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainRenewFlowTest.java index df047deaa..aeba114da 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainRenewFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainRenewFlowTest.java @@ -153,6 +153,8 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase substitutions, Money totalRenewCost) throws Exception { assertTransactionalFlow(true); DateTime currentExpiration = reloadResourceByForeignKey().getRegistrationExpirationTime(); DateTime newExpiration = currentExpiration.plusYears(renewalYears); - runFlowAssertResponse(loadFile(responseFilename, substitutions)); + runFlowAssertResponse( + CommitMode.LIVE, userPrivileges, loadFile(responseFilename, substitutions)); DomainBase domain = reloadResourceByForeignKey(); HistoryEntry historyEntryDomainRenew = getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_RENEW); @@ -183,13 +188,13 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase { @@ -63,23 +69,57 @@ public class RenewDomainCommandTest extends EppToolCommandTestCase persistThreeDomains() { + ImmutableList.Builder domains = new ImmutableList.Builder<>(); + domains.add( + persistActiveDomain( + "domain1.tld", + DateTime.parse("2014-09-05T05:05:05Z"), + DateTime.parse("2015-09-05T05:05:05Z"))); + domains.add( + persistActiveDomain( + "domain2.tld", + DateTime.parse("2014-11-05T05:05:05Z"), + DateTime.parse("2015-11-05T05:05:05Z"))); + // The third domain is owned by a different registrar. + domains.add( + persistResource( + newDomainBase("domain3.tld") + .asBuilder() + .setCreationTimeForTest(DateTime.parse("2015-01-05T05:05:05Z")) + .setRegistrationExpirationTime(DateTime.parse("2016-01-05T05:05:05Z")) + .setPersistedCurrentSponsorClientId("NewRegistrar") + .build())); + return domains.build(); + } + @Test - public void testSuccess_multipleDomains() throws Exception { - persistActiveDomain( - "domain1.tld", - DateTime.parse("2014-09-05T05:05:05Z"), - DateTime.parse("2015-09-05T05:05:05Z")); - persistActiveDomain( - "domain2.tld", - DateTime.parse("2014-11-05T05:05:05Z"), - DateTime.parse("2015-11-05T05:05:05Z")); - persistActiveDomain( - "domain3.tld", - DateTime.parse("2015-01-05T05:05:05Z"), - DateTime.parse("2016-01-05T05:05:05Z")); + public void testSuccess_multipleDomains_renewsAndUsesEachDomainsRegistrar() throws Exception { + persistThreeDomains(); runCommandForced("--period 3", "domain1.tld", "domain2.tld", "domain3.tld"); eppVerifier .expectClientId("TheRegistrar") + .verifySent( + "domain_renew.xml", + ImmutableMap.of("DOMAIN", "domain1.tld", "EXPDATE", "2015-09-05", "YEARS", "3")) + .verifySent( + "domain_renew.xml", + ImmutableMap.of("DOMAIN", "domain2.tld", "EXPDATE", "2015-11-05", "YEARS", "3")) + .expectClientId("NewRegistrar") + .verifySent( + "domain_renew.xml", + ImmutableMap.of("DOMAIN", "domain3.tld", "EXPDATE", "2016-01-05", "YEARS", "3")) + .verifyNoMoreSent(); + } + + @Test + public void testSuccess_multipleDomains_renewsAndUsesSpecifiedRegistrar() throws Exception { + persistThreeDomains(); + persistNewRegistrar("reg3", "Registrar 3", Registrar.Type.REAL, 9783L); + runCommandForced("--period 3", "domain1.tld", "domain2.tld", "domain3.tld", "-u", "-c reg3"); + eppVerifier + .expectClientId("reg3") + .expectSuperuser() .verifySent( "domain_renew.xml", ImmutableMap.of("DOMAIN", "domain1.tld", "EXPDATE", "2015-09-05", "YEARS", "3")) @@ -106,9 +146,7 @@ public class RenewDomainCommandTest extends EppToolCommandTestCase runCommandForced("deleted.tld")); - assertThat(e) - .hasMessageThat() - .isEqualTo("Domain 'deleted.tld' does not exist or is deleted"); + assertThat(e).hasMessageThat().isEqualTo("Domain 'deleted.tld' does not exist or is deleted"); } @Test @@ -128,9 +166,7 @@ public class RenewDomainCommandTest extends EppToolCommandTestCase runCommandForced("domain.tld", "--period 10")); - assertThat(e) - .hasMessageThat() - .isEqualTo("Cannot renew domains for 10 or more years"); + assertThat(e).hasMessageThat().isEqualTo("Cannot renew domains for 10 or more years"); } @Test