mirror of
https://github.com/google/nomulus.git
synced 2025-04-30 12:07:51 +02:00
Prohibit renewals of package domains unless REMOVEPACKAGE token is included (#1758)
This commit is contained in:
parent
b75ee28058
commit
86db66c01f
6 changed files with 198 additions and 31 deletions
|
@ -30,6 +30,7 @@ import static google.registry.flows.domain.DomainFlowUtils.validateFeeChallenge;
|
||||||
import static google.registry.flows.domain.DomainFlowUtils.validateRegistrationPeriod;
|
import static google.registry.flows.domain.DomainFlowUtils.validateRegistrationPeriod;
|
||||||
import static google.registry.flows.domain.DomainFlowUtils.verifyRegistrarIsActive;
|
import static google.registry.flows.domain.DomainFlowUtils.verifyRegistrarIsActive;
|
||||||
import static google.registry.flows.domain.DomainFlowUtils.verifyUnitIsYears;
|
import static google.registry.flows.domain.DomainFlowUtils.verifyUnitIsYears;
|
||||||
|
import static google.registry.flows.domain.token.AllocationTokenFlowUtils.verifyTokenAllowedOnDomain;
|
||||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_RENEW;
|
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_RENEW;
|
||||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||||
import static google.registry.util.DateTimeUtils.leapSafeAddYears;
|
import static google.registry.util.DateTimeUtils.leapSafeAddYears;
|
||||||
|
@ -119,6 +120,10 @@ import org.joda.time.Duration;
|
||||||
* @error {@link DomainFlowUtils.UnsupportedFeeAttributeException}
|
* @error {@link DomainFlowUtils.UnsupportedFeeAttributeException}
|
||||||
* @error {@link DomainRenewFlow.IncorrectCurrentExpirationDateException}
|
* @error {@link DomainRenewFlow.IncorrectCurrentExpirationDateException}
|
||||||
* @error {@link
|
* @error {@link
|
||||||
|
* google.registry.flows.domain.token.AllocationTokenFlowUtils.MissingRemovePackageTokenOnPackageDomainException}
|
||||||
|
* @error {@link
|
||||||
|
* google.registry.flows.domain.token.AllocationTokenFlowUtils.RemovePackageTokenOnNonPackageDomainException}
|
||||||
|
* @error {@link
|
||||||
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForDomainException}
|
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForDomainException}
|
||||||
* @error {@link
|
* @error {@link
|
||||||
* google.registry.flows.domain.token.AllocationTokenFlowUtils.InvalidAllocationTokenException}
|
* google.registry.flows.domain.token.AllocationTokenFlowUtils.InvalidAllocationTokenException}
|
||||||
|
@ -174,7 +179,7 @@ public final class DomainRenewFlow implements TransactionalFlow {
|
||||||
registrarId,
|
registrarId,
|
||||||
now,
|
now,
|
||||||
eppInput.getSingleExtension(AllocationTokenExtension.class));
|
eppInput.getSingleExtension(AllocationTokenExtension.class));
|
||||||
verifyRenewAllowed(authInfo, existingDomain, command);
|
verifyRenewAllowed(authInfo, existingDomain, command, allocationToken);
|
||||||
int years = command.getPeriod().getValue();
|
int years = command.getPeriod().getValue();
|
||||||
DateTime newExpirationTime =
|
DateTime newExpirationTime =
|
||||||
leapSafeAddYears(existingDomain.getRegistrationExpirationTime(), years); // Uncapped
|
leapSafeAddYears(existingDomain.getRegistrationExpirationTime(), years); // Uncapped
|
||||||
|
@ -302,10 +307,16 @@ public final class DomainRenewFlow implements TransactionalFlow {
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyRenewAllowed(Optional<AuthInfo> authInfo, Domain existingDomain, Renew command)
|
private void verifyRenewAllowed(
|
||||||
|
Optional<AuthInfo> authInfo,
|
||||||
|
Domain existingDomain,
|
||||||
|
Renew command,
|
||||||
|
Optional<AllocationToken> allocationToken)
|
||||||
throws EppException {
|
throws EppException {
|
||||||
verifyOptionalAuthInfo(authInfo, existingDomain);
|
verifyOptionalAuthInfo(authInfo, existingDomain);
|
||||||
verifyNoDisallowedStatuses(existingDomain, RENEW_DISALLOWED_STATUSES);
|
verifyNoDisallowedStatuses(existingDomain, RENEW_DISALLOWED_STATUSES);
|
||||||
|
// We only allow __REMOVE_PACKAGE__ token on promo package domains for now
|
||||||
|
verifyTokenAllowedOnDomain(existingDomain, allocationToken);
|
||||||
if (!isSuperuser) {
|
if (!isSuperuser) {
|
||||||
verifyResourceOwnership(registrarId, existingDomain);
|
verifyResourceOwnership(registrarId, existingDomain);
|
||||||
checkAllowedAccessToTld(registrarId, existingDomain.getTld());
|
checkAllowedAccessToTld(registrarId, existingDomain.getTld());
|
||||||
|
|
|
@ -29,6 +29,7 @@ import google.registry.flows.EppException.StatusProhibitsOperationException;
|
||||||
import google.registry.model.domain.Domain;
|
import google.registry.model.domain.Domain;
|
||||||
import google.registry.model.domain.DomainCommand;
|
import google.registry.model.domain.DomainCommand;
|
||||||
import google.registry.model.domain.token.AllocationToken;
|
import google.registry.model.domain.token.AllocationToken;
|
||||||
|
import google.registry.model.domain.token.AllocationToken.TokenBehavior;
|
||||||
import google.registry.model.domain.token.AllocationToken.TokenStatus;
|
import google.registry.model.domain.token.AllocationToken.TokenStatus;
|
||||||
import google.registry.model.domain.token.AllocationToken.TokenType;
|
import google.registry.model.domain.token.AllocationToken.TokenType;
|
||||||
import google.registry.model.domain.token.AllocationTokenExtension;
|
import google.registry.model.domain.token.AllocationTokenExtension;
|
||||||
|
@ -109,23 +110,27 @@ public class AllocationTokenFlowUtils {
|
||||||
private void validateToken(
|
private void validateToken(
|
||||||
InternetDomainName domainName, AllocationToken token, String registrarId, DateTime now)
|
InternetDomainName domainName, AllocationToken token, String registrarId, DateTime now)
|
||||||
throws EppException {
|
throws EppException {
|
||||||
if (!token.getAllowedRegistrarIds().isEmpty()
|
|
||||||
&& !token.getAllowedRegistrarIds().contains(registrarId)) {
|
// Only tokens with default behavior require validation
|
||||||
throw new AllocationTokenNotValidForRegistrarException();
|
if (TokenBehavior.DEFAULT.equals(token.getTokenBehavior())) {
|
||||||
}
|
if (!token.getAllowedRegistrarIds().isEmpty()
|
||||||
if (!token.getAllowedTlds().isEmpty()
|
&& !token.getAllowedRegistrarIds().contains(registrarId)) {
|
||||||
&& !token.getAllowedTlds().contains(domainName.parent().toString())) {
|
throw new AllocationTokenNotValidForRegistrarException();
|
||||||
throw new AllocationTokenNotValidForTldException();
|
}
|
||||||
}
|
if (!token.getAllowedTlds().isEmpty()
|
||||||
if (token.getDomainName().isPresent()
|
&& !token.getAllowedTlds().contains(domainName.parent().toString())) {
|
||||||
&& !token.getDomainName().get().equals(domainName.toString())) {
|
throw new AllocationTokenNotValidForTldException();
|
||||||
throw new AllocationTokenNotValidForDomainException();
|
}
|
||||||
}
|
if (token.getDomainName().isPresent()
|
||||||
// Tokens without status transitions will just have a single-entry NOT_STARTED map, so only
|
&& !token.getDomainName().get().equals(domainName.toString())) {
|
||||||
// check the status transitions map if it's non-trivial.
|
throw new AllocationTokenNotValidForDomainException();
|
||||||
if (token.getTokenStatusTransitions().size() > 1
|
}
|
||||||
&& !TokenStatus.VALID.equals(token.getTokenStatusTransitions().getValueAtTime(now))) {
|
// Tokens without status transitions will just have a single-entry NOT_STARTED map, so only
|
||||||
throw new AllocationTokenNotInPromotionException();
|
// check the status transitions map if it's non-trivial.
|
||||||
|
if (token.getTokenStatusTransitions().size() > 1
|
||||||
|
&& !TokenStatus.VALID.equals(token.getTokenStatusTransitions().getValueAtTime(now))) {
|
||||||
|
throw new AllocationTokenNotInPromotionException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,8 +142,15 @@ public class AllocationTokenFlowUtils {
|
||||||
// See https://tools.ietf.org/html/draft-ietf-regext-allocation-token-04#section-2.1
|
// See https://tools.ietf.org/html/draft-ietf-regext-allocation-token-04#section-2.1
|
||||||
throw new InvalidAllocationTokenException();
|
throw new InvalidAllocationTokenException();
|
||||||
}
|
}
|
||||||
Optional<AllocationToken> maybeTokenEntity =
|
|
||||||
|
Optional<AllocationToken> maybeTokenEntity = AllocationToken.maybeGetStaticTokenInstance(token);
|
||||||
|
if (maybeTokenEntity.isPresent()) {
|
||||||
|
return maybeTokenEntity.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
maybeTokenEntity =
|
||||||
tm().transact(() -> tm().loadByKeyIfPresent(VKey.create(AllocationToken.class, token)));
|
tm().transact(() -> tm().loadByKeyIfPresent(VKey.create(AllocationToken.class, token)));
|
||||||
|
|
||||||
if (!maybeTokenEntity.isPresent()) {
|
if (!maybeTokenEntity.isPresent()) {
|
||||||
throw new InvalidAllocationTokenException();
|
throw new InvalidAllocationTokenException();
|
||||||
}
|
}
|
||||||
|
@ -187,6 +199,21 @@ public class AllocationTokenFlowUtils {
|
||||||
tokenCustomLogic.validateToken(existingDomain, tokenEntity, registry, registrarId, now));
|
tokenCustomLogic.validateToken(existingDomain, tokenEntity, registry, registrarId, now));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void verifyTokenAllowedOnDomain(
|
||||||
|
Domain domain, Optional<AllocationToken> allocationToken) throws EppException {
|
||||||
|
|
||||||
|
boolean domainHasPackageToken = domain.getCurrentPackageToken().isPresent();
|
||||||
|
boolean hasRemovePackageToken =
|
||||||
|
allocationToken.isPresent()
|
||||||
|
&& TokenBehavior.REMOVE_PACKAGE.equals(allocationToken.get().getTokenBehavior());
|
||||||
|
|
||||||
|
if (hasRemovePackageToken && !domainHasPackageToken) {
|
||||||
|
throw new RemovePackageTokenOnNonPackageDomainException();
|
||||||
|
} else if (!hasRemovePackageToken && domainHasPackageToken) {
|
||||||
|
throw new MissingRemovePackageTokenOnPackageDomainException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Note: exception messages should be <= 32 characters long for domain check results
|
// Note: exception messages should be <= 32 characters long for domain check results
|
||||||
|
|
||||||
/** The allocation token is not currently valid. */
|
/** The allocation token is not currently valid. */
|
||||||
|
@ -234,4 +261,20 @@ public class AllocationTokenFlowUtils {
|
||||||
super("The allocation token is invalid");
|
super("The allocation token is invalid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The __REMOVEPACKAGE__ token is missing on a renew package domain command */
|
||||||
|
public static class MissingRemovePackageTokenOnPackageDomainException
|
||||||
|
extends AssociationProhibitsOperationException {
|
||||||
|
MissingRemovePackageTokenOnPackageDomainException() {
|
||||||
|
super("Domains that are inside packages cannot be explicitly renewed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The __REMOVEPACKAGE__ token is not allowed on non package domains */
|
||||||
|
public static class RemovePackageTokenOnNonPackageDomainException
|
||||||
|
extends AssociationProhibitsOperationException {
|
||||||
|
RemovePackageTokenOnNonPackageDomainException() {
|
||||||
|
super("__REMOVEPACKAGE__ token is not allowed on non package domains");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableMultimap;
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.ImmutableSortedMap;
|
import com.google.common.collect.ImmutableSortedMap;
|
||||||
|
@ -79,6 +80,10 @@ import org.joda.time.DateTime;
|
||||||
public class AllocationToken extends BackupGroupRoot implements Buildable {
|
public class AllocationToken extends BackupGroupRoot implements Buildable {
|
||||||
|
|
||||||
private static final long serialVersionUID = -3954475393220876903L;
|
private static final long serialVersionUID = -3954475393220876903L;
|
||||||
|
private static final String REMOVE_PACKAGE = "__REMOVEPACKAGE__";
|
||||||
|
|
||||||
|
private static final ImmutableMap<String, TokenBehavior> STATIC_TOKEN_BEHAVIORS =
|
||||||
|
ImmutableMap.of(REMOVE_PACKAGE, TokenBehavior.REMOVE_PACKAGE);
|
||||||
|
|
||||||
// Promotions should only move forward, and ENDED / CANCELLED are terminal states.
|
// Promotions should only move forward, and ENDED / CANCELLED are terminal states.
|
||||||
private static final ImmutableMultimap<TokenStatus, TokenStatus> VALID_TOKEN_STATUS_TRANSITIONS =
|
private static final ImmutableMultimap<TokenStatus, TokenStatus> VALID_TOKEN_STATUS_TRANSITIONS =
|
||||||
|
@ -87,6 +92,18 @@ public class AllocationToken extends BackupGroupRoot implements Buildable {
|
||||||
.putAll(VALID, ENDED, CANCELLED)
|
.putAll(VALID, ENDED, CANCELLED)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
private static final ImmutableMap<String, AllocationToken> BEHAVIORAL_TOKENS =
|
||||||
|
ImmutableMap.of(
|
||||||
|
REMOVE_PACKAGE,
|
||||||
|
new AllocationToken.Builder()
|
||||||
|
.setTokenType(TokenType.UNLIMITED_USE)
|
||||||
|
.setToken(REMOVE_PACKAGE)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
public static Optional<AllocationToken> maybeGetStaticTokenInstance(String name) {
|
||||||
|
return Optional.ofNullable(BEHAVIORAL_TOKENS.get(name));
|
||||||
|
}
|
||||||
|
|
||||||
/** Any special behavior that should be used when registering domains using this token. */
|
/** Any special behavior that should be used when registering domains using this token. */
|
||||||
public enum RegistrationBehavior {
|
public enum RegistrationBehavior {
|
||||||
/** No special behavior */
|
/** No special behavior */
|
||||||
|
@ -110,7 +127,21 @@ public class AllocationToken extends BackupGroupRoot implements Buildable {
|
||||||
public enum TokenType {
|
public enum TokenType {
|
||||||
PACKAGE,
|
PACKAGE,
|
||||||
SINGLE_USE,
|
SINGLE_USE,
|
||||||
UNLIMITED_USE
|
UNLIMITED_USE,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* System behaves differently based on a token it gets inside a command. This enumerates different
|
||||||
|
* types of behaviors we support.
|
||||||
|
*/
|
||||||
|
public enum TokenBehavior {
|
||||||
|
/** No special behavior */
|
||||||
|
DEFAULT,
|
||||||
|
/**
|
||||||
|
* REMOVE_PACKAGE triggers domain removal from promotional package, bypasses DEFAULT token
|
||||||
|
* validations.
|
||||||
|
*/
|
||||||
|
REMOVE_PACKAGE
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The status of this token with regard to any potential promotion. */
|
/** The status of this token with regard to any potential promotion. */
|
||||||
|
@ -255,6 +286,10 @@ public class AllocationToken extends BackupGroupRoot implements Buildable {
|
||||||
return registrationBehavior;
|
return registrationBehavior;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TokenBehavior getTokenBehavior() {
|
||||||
|
return STATIC_TOKEN_BEHAVIORS.getOrDefault(token, TokenBehavior.DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VKey<AllocationToken> createVKey() {
|
public VKey<AllocationToken> createVKey() {
|
||||||
return VKey.create(AllocationToken.class, getToken(), Key.create(this));
|
return VKey.create(AllocationToken.class, getToken(), Key.create(this));
|
||||||
|
|
|
@ -20,6 +20,7 @@ import static google.registry.flows.domain.DomainTransferFlowTestCase.persistWit
|
||||||
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.DEFAULT;
|
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.DEFAULT;
|
||||||
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.NONPREMIUM;
|
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.NONPREMIUM;
|
||||||
import static google.registry.model.billing.BillingEvent.RenewalPriceBehavior.SPECIFIED;
|
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.SINGLE_USE;
|
||||||
import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE;
|
import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE;
|
||||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||||
|
@ -73,6 +74,8 @@ import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTok
|
||||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForTldException;
|
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForTldException;
|
||||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AlreadyRedeemedAllocationTokenException;
|
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AlreadyRedeemedAllocationTokenException;
|
||||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.InvalidAllocationTokenException;
|
import google.registry.flows.domain.token.AllocationTokenFlowUtils.InvalidAllocationTokenException;
|
||||||
|
import google.registry.flows.domain.token.AllocationTokenFlowUtils.MissingRemovePackageTokenOnPackageDomainException;
|
||||||
|
import google.registry.flows.domain.token.AllocationTokenFlowUtils.RemovePackageTokenOnNonPackageDomainException;
|
||||||
import google.registry.flows.exceptions.ResourceStatusProhibitsOperationException;
|
import google.registry.flows.exceptions.ResourceStatusProhibitsOperationException;
|
||||||
import google.registry.model.billing.BillingEvent;
|
import google.registry.model.billing.BillingEvent;
|
||||||
import google.registry.model.billing.BillingEvent.Flag;
|
import google.registry.model.billing.BillingEvent.Flag;
|
||||||
|
@ -591,7 +594,8 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
|
||||||
@Test
|
@Test
|
||||||
void testSuccess_allocationToken() throws Exception {
|
void testSuccess_allocationToken() throws Exception {
|
||||||
setEppInput(
|
setEppInput(
|
||||||
"domain_renew_allocationtoken.xml", ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
|
"domain_renew_allocationtoken.xml",
|
||||||
|
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "abc123"));
|
||||||
persistDomain();
|
persistDomain();
|
||||||
AllocationToken allocationToken =
|
AllocationToken allocationToken =
|
||||||
persistResource(
|
persistResource(
|
||||||
|
@ -611,7 +615,8 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
|
||||||
@Test
|
@Test
|
||||||
void testSuccess_allocationTokenMultiUse() throws Exception {
|
void testSuccess_allocationTokenMultiUse() throws Exception {
|
||||||
setEppInput(
|
setEppInput(
|
||||||
"domain_renew_allocationtoken.xml", ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
|
"domain_renew_allocationtoken.xml",
|
||||||
|
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "abc123"));
|
||||||
persistDomain();
|
persistDomain();
|
||||||
persistResource(
|
persistResource(
|
||||||
new AllocationToken.Builder().setToken("abc123").setTokenType(UNLIMITED_USE).build());
|
new AllocationToken.Builder().setToken("abc123").setTokenType(UNLIMITED_USE).build());
|
||||||
|
@ -622,7 +627,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
|
||||||
clock.advanceOneMilli();
|
clock.advanceOneMilli();
|
||||||
setEppInput(
|
setEppInput(
|
||||||
"domain_renew_allocationtoken.xml",
|
"domain_renew_allocationtoken.xml",
|
||||||
ImmutableMap.of("DOMAIN", "other-example.tld", "YEARS", "2"));
|
ImmutableMap.of("DOMAIN", "other-example.tld", "YEARS", "2", "TOKEN", "abc123"));
|
||||||
persistDomain();
|
persistDomain();
|
||||||
runFlowAssertResponse(
|
runFlowAssertResponse(
|
||||||
loadFile(
|
loadFile(
|
||||||
|
@ -633,7 +638,8 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
|
||||||
@Test
|
@Test
|
||||||
void testFailure_invalidAllocationToken() throws Exception {
|
void testFailure_invalidAllocationToken() throws Exception {
|
||||||
setEppInput(
|
setEppInput(
|
||||||
"domain_renew_allocationtoken.xml", ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
|
"domain_renew_allocationtoken.xml",
|
||||||
|
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "abc123"));
|
||||||
persistDomain();
|
persistDomain();
|
||||||
EppException thrown = assertThrows(InvalidAllocationTokenException.class, this::runFlow);
|
EppException thrown = assertThrows(InvalidAllocationTokenException.class, this::runFlow);
|
||||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||||
|
@ -642,7 +648,8 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
|
||||||
@Test
|
@Test
|
||||||
void testFailure_allocationTokenIsForADifferentDomain() throws Exception {
|
void testFailure_allocationTokenIsForADifferentDomain() throws Exception {
|
||||||
setEppInput(
|
setEppInput(
|
||||||
"domain_renew_allocationtoken.xml", ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
|
"domain_renew_allocationtoken.xml",
|
||||||
|
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "abc123"));
|
||||||
persistDomain();
|
persistDomain();
|
||||||
persistResource(
|
persistResource(
|
||||||
new AllocationToken.Builder()
|
new AllocationToken.Builder()
|
||||||
|
@ -660,7 +667,8 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
|
||||||
@Test
|
@Test
|
||||||
void testFailure_promotionNotActive() throws Exception {
|
void testFailure_promotionNotActive() throws Exception {
|
||||||
setEppInput(
|
setEppInput(
|
||||||
"domain_renew_allocationtoken.xml", ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
|
"domain_renew_allocationtoken.xml",
|
||||||
|
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "abc123"));
|
||||||
persistDomain();
|
persistDomain();
|
||||||
persistResource(
|
persistResource(
|
||||||
new AllocationToken.Builder()
|
new AllocationToken.Builder()
|
||||||
|
@ -682,7 +690,8 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
|
||||||
@Test
|
@Test
|
||||||
void testFailure_promoTokenNotValidForRegistrar() throws Exception {
|
void testFailure_promoTokenNotValidForRegistrar() throws Exception {
|
||||||
setEppInput(
|
setEppInput(
|
||||||
"domain_renew_allocationtoken.xml", ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
|
"domain_renew_allocationtoken.xml",
|
||||||
|
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "abc123"));
|
||||||
persistDomain();
|
persistDomain();
|
||||||
persistResource(
|
persistResource(
|
||||||
new AllocationToken.Builder()
|
new AllocationToken.Builder()
|
||||||
|
@ -706,7 +715,8 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
|
||||||
@Test
|
@Test
|
||||||
void testFailure_promoTokenNotValidForTld() throws Exception {
|
void testFailure_promoTokenNotValidForTld() throws Exception {
|
||||||
setEppInput(
|
setEppInput(
|
||||||
"domain_renew_allocationtoken.xml", ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
|
"domain_renew_allocationtoken.xml",
|
||||||
|
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "abc123"));
|
||||||
persistDomain();
|
persistDomain();
|
||||||
persistResource(
|
persistResource(
|
||||||
new AllocationToken.Builder()
|
new AllocationToken.Builder()
|
||||||
|
@ -730,7 +740,8 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
|
||||||
@Test
|
@Test
|
||||||
void testFailure_alreadyRedemeedAllocationToken() throws Exception {
|
void testFailure_alreadyRedemeedAllocationToken() throws Exception {
|
||||||
setEppInput(
|
setEppInput(
|
||||||
"domain_renew_allocationtoken.xml", ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
|
"domain_renew_allocationtoken.xml",
|
||||||
|
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "abc123"));
|
||||||
persistDomain();
|
persistDomain();
|
||||||
Domain domain = persistActiveDomain("foo.tld");
|
Domain domain = persistActiveDomain("foo.tld");
|
||||||
Key<HistoryEntry> historyEntryKey = Key.create(Key.create(domain), HistoryEntry.class, 505L);
|
Key<HistoryEntry> historyEntryKey = Key.create(Key.create(domain), HistoryEntry.class, 505L);
|
||||||
|
@ -1185,4 +1196,69 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
|
||||||
TransactionReportField.netRenewsFieldFromYears(5),
|
TransactionReportField.netRenewsFieldFromYears(5),
|
||||||
1));
|
1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFailsPackageDomainInvalidAllocationToken() throws Exception {
|
||||||
|
AllocationToken token =
|
||||||
|
persistResource(
|
||||||
|
new AllocationToken.Builder()
|
||||||
|
.setToken("abc123")
|
||||||
|
.setTokenType(PACKAGE)
|
||||||
|
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
|
||||||
|
.setAllowedTlds(ImmutableSet.of("tld"))
|
||||||
|
.setRenewalPriceBehavior(SPECIFIED)
|
||||||
|
.build());
|
||||||
|
persistDomain();
|
||||||
|
persistResource(
|
||||||
|
reloadResourceByForeignKey()
|
||||||
|
.asBuilder()
|
||||||
|
.setCurrentPackageToken(token.createVKey())
|
||||||
|
.build());
|
||||||
|
|
||||||
|
setEppInput(
|
||||||
|
"domain_renew_allocationtoken.xml",
|
||||||
|
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "abc123"));
|
||||||
|
|
||||||
|
EppException thrown =
|
||||||
|
assertThrows(MissingRemovePackageTokenOnPackageDomainException.class, this::runFlow);
|
||||||
|
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFailsToRenewPackageDomainNoRemovePackageToken() throws Exception {
|
||||||
|
AllocationToken token =
|
||||||
|
persistResource(
|
||||||
|
new AllocationToken.Builder()
|
||||||
|
.setToken("abc123")
|
||||||
|
.setTokenType(PACKAGE)
|
||||||
|
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
|
||||||
|
.setAllowedTlds(ImmutableSet.of("tld"))
|
||||||
|
.setRenewalPriceBehavior(SPECIFIED)
|
||||||
|
.build());
|
||||||
|
persistDomain();
|
||||||
|
persistResource(
|
||||||
|
reloadResourceByForeignKey()
|
||||||
|
.asBuilder()
|
||||||
|
.setCurrentPackageToken(token.createVKey())
|
||||||
|
.build());
|
||||||
|
|
||||||
|
setEppInput("domain_renew.xml", ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "5"));
|
||||||
|
|
||||||
|
EppException thrown =
|
||||||
|
assertThrows(MissingRemovePackageTokenOnPackageDomainException.class, this::runFlow);
|
||||||
|
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFailsToRenewNonPackageDomainWithRemovePackageToken() throws Exception {
|
||||||
|
persistDomain();
|
||||||
|
|
||||||
|
setEppInput(
|
||||||
|
"domain_renew_allocationtoken.xml",
|
||||||
|
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "__REMOVEPACKAGE__"));
|
||||||
|
|
||||||
|
EppException thrown =
|
||||||
|
assertThrows(RemovePackageTokenOnNonPackageDomainException.class, this::runFlow);
|
||||||
|
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
<allocationToken:allocationToken
|
<allocationToken:allocationToken
|
||||||
xmlns:allocationToken=
|
xmlns:allocationToken=
|
||||||
"urn:ietf:params:xml:ns:allocationToken-1.0">
|
"urn:ietf:params:xml:ns:allocationToken-1.0">
|
||||||
abc123
|
%TOKEN%
|
||||||
</allocationToken:allocationToken>
|
</allocationToken:allocationToken>
|
||||||
</extension>
|
</extension>
|
||||||
<clTRID>ABC-12345</clTRID>
|
<clTRID>ABC-12345</clTRID>
|
||||||
|
|
|
@ -497,6 +497,8 @@ comes in at the exact millisecond that the domain would have expired.
|
||||||
* Resource status prohibits this operation.
|
* Resource status prohibits this operation.
|
||||||
* The allocation token is not currently valid.
|
* The allocation token is not currently valid.
|
||||||
* 2305
|
* 2305
|
||||||
|
* The __REMOVEPACKAGE__ token is missing on a renew 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 domain.
|
||||||
* The allocation token is not valid for this registrar.
|
* The allocation token is not valid for this registrar.
|
||||||
* The allocation token is not valid for this TLD.
|
* The allocation token is not valid for this TLD.
|
||||||
|
|
Loading…
Add table
Reference in a new issue