mirror of
https://github.com/google/nomulus.git
synced 2025-04-30 03:57:51 +02:00
Add REMOVEPACKAGE token functionality to domain transfer flow (#1792)
This commit is contained in:
parent
527bf82370
commit
5ec4ec3af5
5 changed files with 119 additions and 19 deletions
|
@ -32,6 +32,8 @@ import static google.registry.flows.domain.DomainTransferUtils.createLosingTrans
|
|||
import static google.registry.flows.domain.DomainTransferUtils.createPendingTransferData;
|
||||
import static google.registry.flows.domain.DomainTransferUtils.createTransferResponse;
|
||||
import static google.registry.flows.domain.DomainTransferUtils.createTransferServerApproveEntities;
|
||||
import static google.registry.flows.domain.token.AllocationTokenFlowUtils.maybeApplyPackageRemovalToken;
|
||||
import static google.registry.flows.domain.token.AllocationTokenFlowUtils.verifyTokenAllowedOnDomain;
|
||||
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACTION_PENDING;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
|
@ -63,6 +65,7 @@ import google.registry.model.domain.fee.FeeTransferCommandExtension;
|
|||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
import google.registry.model.domain.superuser.DomainTransferRequestSuperuserExtension;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.domain.token.AllocationTokenExtension;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
|
@ -132,6 +135,8 @@ import org.joda.time.DateTime;
|
|||
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForTldException}
|
||||
* @error {@link
|
||||
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AlreadyRedeemedAllocationTokenException}
|
||||
* @error {@link
|
||||
* google.registry.flows.domain.token.AllocationTokenFlowUtils.MissingRemovePackageTokenOnPackageDomainException}
|
||||
*/
|
||||
@ReportingSpec(ActivityReportField.DOMAIN_TRANSFER_REQUEST)
|
||||
public final class DomainTransferRequestFlow implements TransactionalFlow {
|
||||
|
@ -169,19 +174,24 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
|
|||
extensionManager.validate();
|
||||
DateTime now = tm().getTransactionTime();
|
||||
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
|
||||
allocationTokenFlowUtils.verifyAllocationTokenIfPresent(
|
||||
existingDomain,
|
||||
Registry.get(existingDomain.getTld()),
|
||||
gainingClientId,
|
||||
now,
|
||||
eppInput.getSingleExtension(AllocationTokenExtension.class));
|
||||
Optional<AllocationToken> allocationToken =
|
||||
allocationTokenFlowUtils.verifyAllocationTokenIfPresent(
|
||||
existingDomain,
|
||||
Registry.get(existingDomain.getTld()),
|
||||
gainingClientId,
|
||||
now,
|
||||
eppInput.getSingleExtension(AllocationTokenExtension.class));
|
||||
Optional<DomainTransferRequestSuperuserExtension> superuserExtension =
|
||||
eppInput.getSingleExtension(DomainTransferRequestSuperuserExtension.class);
|
||||
Period period =
|
||||
superuserExtension.isPresent()
|
||||
? superuserExtension.get().getRenewalPeriod()
|
||||
: ((Transfer) resourceCommand).getPeriod();
|
||||
verifyTransferAllowed(existingDomain, period, now, superuserExtension);
|
||||
verifyTransferAllowed(existingDomain, period, now, superuserExtension, allocationToken);
|
||||
|
||||
// If client passed an applicable static token this updates the domain
|
||||
existingDomain = maybeApplyPackageRemovalToken(existingDomain, allocationToken);
|
||||
|
||||
String tld = existingDomain.getTld();
|
||||
Registry registry = Registry.get(tld);
|
||||
// An optional extension from the client specifying what they think the transfer should cost.
|
||||
|
@ -293,9 +303,11 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
|
|||
Domain existingDomain,
|
||||
Period period,
|
||||
DateTime now,
|
||||
Optional<DomainTransferRequestSuperuserExtension> superuserExtension)
|
||||
Optional<DomainTransferRequestSuperuserExtension> superuserExtension,
|
||||
Optional<AllocationToken> allocationToken)
|
||||
throws EppException {
|
||||
verifyNoDisallowedStatuses(existingDomain, DISALLOWED_STATUSES);
|
||||
verifyTokenAllowedOnDomain(existingDomain, allocationToken);
|
||||
if (!isSuperuser) {
|
||||
verifyAuthInfoPresentForResourceTransfer(authInfo);
|
||||
verifyAuthInfo(authInfo.get(), existingDomain);
|
||||
|
|
|
@ -293,11 +293,11 @@ public class AllocationTokenFlowUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/** The __REMOVEPACKAGE__ token is missing on a renew package domain command */
|
||||
/** The __REMOVEPACKAGE__ token is missing on a package domain command */
|
||||
public static class MissingRemovePackageTokenOnPackageDomainException
|
||||
extends AssociationProhibitsOperationException {
|
||||
MissingRemovePackageTokenOnPackageDomainException() {
|
||||
super("Domains that are inside packages cannot be explicitly renewed");
|
||||
super("Domains that are inside packages cannot be explicitly renewed or transferred");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,9 @@ import static com.google.common.truth.Truth8.assertThat;
|
|||
import static google.registry.batch.AsyncTaskEnqueuer.PARAM_REQUESTED_TIME;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.PARAM_RESOURCE_KEY;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_ACTIONS;
|
||||
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.DEFAULT;
|
||||
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.SPECIFIED;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.PACKAGE;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE;
|
||||
import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_SUCCESSFUL;
|
||||
|
@ -61,6 +64,7 @@ import com.google.common.collect.Iterables;
|
|||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.common.truth.Truth8;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.batch.ResaveEntityAction;
|
||||
import google.registry.flows.EppException;
|
||||
|
@ -85,6 +89,7 @@ import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTok
|
|||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForTldException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AlreadyRedeemedAllocationTokenException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.InvalidAllocationTokenException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.MissingRemovePackageTokenOnPackageDomainException;
|
||||
import google.registry.flows.exceptions.AlreadyPendingTransferException;
|
||||
import google.registry.flows.exceptions.InvalidTransferPeriodValueException;
|
||||
import google.registry.flows.exceptions.MissingTransferRequestAuthInfoException;
|
||||
|
@ -1700,13 +1705,15 @@ class DomainTransferRequestFlowTest
|
|||
.setDomainName("example.tld")
|
||||
.build());
|
||||
doSuccessfulTest(
|
||||
"domain_transfer_request_allocation_token.xml", "domain_transfer_request_response.xml");
|
||||
"domain_transfer_request_allocation_token.xml",
|
||||
"domain_transfer_request_response.xml",
|
||||
ImmutableMap.of("TOKEN", "abc123"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_invalidAllocationToken() throws Exception {
|
||||
setupDomain("example", "tld");
|
||||
setEppInput("domain_transfer_request_allocation_token.xml");
|
||||
setEppInput("domain_transfer_request_allocation_token.xml", ImmutableMap.of("TOKEN", "abc123"));
|
||||
EppException thrown = assertThrows(InvalidAllocationTokenException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
@ -1720,7 +1727,7 @@ class DomainTransferRequestFlowTest
|
|||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("otherdomain.tld")
|
||||
.build());
|
||||
setEppInput("domain_transfer_request_allocation_token.xml");
|
||||
setEppInput("domain_transfer_request_allocation_token.xml", ImmutableMap.of("TOKEN", "abc123"));
|
||||
EppException thrown =
|
||||
assertThrows(AllocationTokenNotValidForDomainException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
|
@ -1741,7 +1748,7 @@ class DomainTransferRequestFlowTest
|
|||
.put(clock.nowUtc().plusDays(60), TokenStatus.ENDED)
|
||||
.build())
|
||||
.build());
|
||||
setEppInput("domain_transfer_request_allocation_token.xml");
|
||||
setEppInput("domain_transfer_request_allocation_token.xml", ImmutableMap.of("TOKEN", "abc123"));
|
||||
EppException thrown = assertThrows(AllocationTokenNotInPromotionException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
@ -1762,7 +1769,7 @@ class DomainTransferRequestFlowTest
|
|||
.put(clock.nowUtc().plusDays(1), TokenStatus.ENDED)
|
||||
.build())
|
||||
.build());
|
||||
setEppInput("domain_transfer_request_allocation_token.xml");
|
||||
setEppInput("domain_transfer_request_allocation_token.xml", ImmutableMap.of("TOKEN", "abc123"));
|
||||
EppException thrown =
|
||||
assertThrows(AllocationTokenNotValidForRegistrarException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
|
@ -1784,7 +1791,7 @@ class DomainTransferRequestFlowTest
|
|||
.put(clock.nowUtc().plusDays(1), TokenStatus.ENDED)
|
||||
.build())
|
||||
.build());
|
||||
setEppInput("domain_transfer_request_allocation_token.xml");
|
||||
setEppInput("domain_transfer_request_allocation_token.xml", ImmutableMap.of("TOKEN", "abc123"));
|
||||
EppException thrown = assertThrows(AllocationTokenNotValidForTldException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
@ -1800,9 +1807,89 @@ class DomainTransferRequestFlowTest
|
|||
.setTokenType(SINGLE_USE)
|
||||
.setRedemptionHistoryEntry(HistoryEntry.createVKey(historyEntryKey))
|
||||
.build());
|
||||
setEppInput("domain_transfer_request_allocation_token.xml");
|
||||
setEppInput("domain_transfer_request_allocation_token.xml", ImmutableMap.of("TOKEN", "abc123"));
|
||||
EppException thrown =
|
||||
assertThrows(AlreadyRedeemedAllocationTokenException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailsPackageDomainInvalidAllocationToken() throws Exception {
|
||||
AllocationToken token =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(PACKAGE)
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("NewRegistrar"))
|
||||
.setAllowedTlds(ImmutableSet.of("example", "tld"))
|
||||
.setRenewalPriceBehavior(SPECIFIED)
|
||||
.build());
|
||||
setupDomain("example", "tld");
|
||||
persistResource(
|
||||
reloadResourceByForeignKey()
|
||||
.asBuilder()
|
||||
.setCurrentPackageToken(token.createVKey())
|
||||
.build());
|
||||
|
||||
setEppInput("domain_transfer_request_allocation_token.xml", ImmutableMap.of("TOKEN", "abc123"));
|
||||
assertThrows(MissingRemovePackageTokenOnPackageDomainException.class, this::runFlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailsToTransferPackageDomainNoRemovePackageToken() throws Exception {
|
||||
AllocationToken token =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(PACKAGE)
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("NewRegistrar"))
|
||||
.setAllowedTlds(ImmutableSet.of("example", "tld"))
|
||||
.setRenewalPriceBehavior(SPECIFIED)
|
||||
.build());
|
||||
setupDomain("example", "tld");
|
||||
persistResource(
|
||||
reloadResourceByForeignKey()
|
||||
.asBuilder()
|
||||
.setCurrentPackageToken(token.createVKey())
|
||||
.build());
|
||||
|
||||
setEppInput("domain_transfer_request.xml");
|
||||
assertThrows(MissingRemovePackageTokenOnPackageDomainException.class, this::runFlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccesfullyAppliesRemovePackageToken() throws Exception {
|
||||
setupDomain("example", "tld");
|
||||
AllocationToken token =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(PACKAGE)
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
|
||||
.setAllowedTlds(ImmutableSet.of("tld"))
|
||||
.setRenewalPriceBehavior(SPECIFIED)
|
||||
.build());
|
||||
domain = loadByEntity(domain);
|
||||
persistResource(
|
||||
loadByKey(domain.getAutorenewBillingEvent())
|
||||
.asBuilder()
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.SPECIFIED)
|
||||
.setRenewalPrice(Money.of(USD, new BigDecimal("10.00")))
|
||||
.build());
|
||||
persistResource(
|
||||
reloadResourceByForeignKey()
|
||||
.asBuilder()
|
||||
.setCurrentPackageToken(token.createVKey())
|
||||
.build());
|
||||
|
||||
doSuccessfulTest(
|
||||
"domain_transfer_request_allocation_token.xml",
|
||||
"domain_transfer_request_response.xml",
|
||||
ImmutableMap.of("TOKEN", "__REMOVEPACKAGE__"));
|
||||
Domain domain = reloadResourceByForeignKey();
|
||||
Truth8.assertThat(domain.getCurrentPackageToken()).isEmpty();
|
||||
RenewalPriceBehavior priceBehavior =
|
||||
loadByKey(domain.getAutorenewBillingEvent()).getRenewalPriceBehavior();
|
||||
assertThat(priceBehavior).isEqualTo(DEFAULT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<allocationToken:allocationToken
|
||||
xmlns:allocationToken=
|
||||
"urn:ietf:params:xml:ns:allocationToken-1.0">
|
||||
abc123
|
||||
%TOKEN%
|
||||
</allocationToken:allocationToken>
|
||||
</extension>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
|
|
|
@ -498,7 +498,7 @@ comes in at the exact millisecond that the domain would have expired.
|
|||
* Resource status prohibits this operation.
|
||||
* The allocation token is not currently valid.
|
||||
* 2305
|
||||
* The __REMOVEPACKAGE__ token is missing on a renew package domain command
|
||||
* The __REMOVEPACKAGE__ token is missing on a package domain command
|
||||
* The __REMOVEPACKAGE__ token is not allowed on non package domains
|
||||
* The allocation token is not valid for this domain.
|
||||
* The allocation token is not valid for this registrar.
|
||||
|
@ -754,6 +754,7 @@ new ones with the correct approval time).
|
|||
* The allocation token is not valid for this registrar.
|
||||
* The allocation token is not valid for this TLD.
|
||||
* The allocation token was already redeemed.
|
||||
* The __REMOVEPACKAGE__ token is missing on a package domain command
|
||||
* 2306
|
||||
* Domain transfer period must be one year.
|
||||
* Domain transfer period must be zero or one year when using the superuser
|
||||
|
|
Loading…
Add table
Reference in a new issue