Allow incorrect fee extensions on domain creates with default tokens (#1927)

* Modify fee extension to accept larger costs on creates with default tokens

* Add tests

* Add some comments to tests
This commit is contained in:
sarahcaseybot 2023-02-28 14:24:03 -05:00 committed by GitHub
parent c07728dab8
commit 9a212314ca
8 changed files with 189 additions and 16 deletions

View file

@ -280,8 +280,12 @@ public final class DomainCreateFlow implements TransactionalFlow {
registrarId, registrarId,
now, now,
eppInput.getSingleExtension(AllocationTokenExtension.class)); eppInput.getSingleExtension(AllocationTokenExtension.class));
boolean defaultTokenUsed = false;
if (!allocationToken.isPresent() && !registry.getDefaultPromoTokens().isEmpty()) { if (!allocationToken.isPresent() && !registry.getDefaultPromoTokens().isEmpty()) {
allocationToken = checkForDefaultToken(registry, command); allocationToken = checkForDefaultToken(registry, command);
if (allocationToken.isPresent()) {
defaultTokenUsed = true;
}
} }
boolean isAnchorTenant = boolean isAnchorTenant =
isAnchorTenant( isAnchorTenant(
@ -340,7 +344,7 @@ public final class DomainCreateFlow implements TransactionalFlow {
FeesAndCredits feesAndCredits = FeesAndCredits feesAndCredits =
pricingLogic.getCreatePrice( pricingLogic.getCreatePrice(
registry, targetId, now, years, isAnchorTenant, allocationToken); registry, targetId, now, years, isAnchorTenant, allocationToken);
validateFeeChallenge(feeCreate, feesAndCredits); validateFeeChallenge(feeCreate, feesAndCredits, defaultTokenUsed);
Optional<SecDnsCreateExtension> secDnsCreate = Optional<SecDnsCreateExtension> secDnsCreate =
validateSecDnsExtension(eppInput.getSingleExtension(SecDnsCreateExtension.class)); validateSecDnsExtension(eppInput.getSingleExtension(SecDnsCreateExtension.class));
DateTime registrationExpirationTime = leapSafeAddYears(now, years); DateTime registrationExpirationTime = leapSafeAddYears(now, years);

View file

@ -778,12 +778,13 @@ public class DomainFlowUtils {
*/ */
public static void validateFeeChallenge( public static void validateFeeChallenge(
final Optional<? extends FeeTransformCommandExtension> feeCommand, final Optional<? extends FeeTransformCommandExtension> feeCommand,
FeesAndCredits feesAndCredits) FeesAndCredits feesAndCredits,
boolean defaultTokenUsed)
throws EppException { throws EppException {
if (feesAndCredits.hasAnyPremiumFees() && !feeCommand.isPresent()) { if (feesAndCredits.hasAnyPremiumFees() && !feeCommand.isPresent()) {
throw new FeesRequiredForPremiumNameException(); throw new FeesRequiredForPremiumNameException();
} }
validateFeesAckedIfPresent(feeCommand, feesAndCredits); validateFeesAckedIfPresent(feeCommand, feesAndCredits, defaultTokenUsed);
} }
/** /**
@ -795,7 +796,8 @@ public class DomainFlowUtils {
*/ */
public static void validateFeesAckedIfPresent( public static void validateFeesAckedIfPresent(
final Optional<? extends FeeTransformCommandExtension> feeCommand, final Optional<? extends FeeTransformCommandExtension> feeCommand,
FeesAndCredits feesAndCredits) FeesAndCredits feesAndCredits,
boolean defaultTokenUsed)
throws EppException { throws EppException {
// Check for the case where a fee command extension was required but not provided. // Check for the case where a fee command extension was required but not provided.
// This only happens when the total fees are non-zero and include custom fees requiring the // This only happens when the total fees are non-zero and include custom fees requiring the
@ -856,9 +858,11 @@ public class DomainFlowUtils {
// Checking if total amount is expected. Extra fees that we are not expecting may be passed in. // Checking if total amount is expected. Extra fees that we are not expecting may be passed in.
// Or if there is only a single fee type expected. // Or if there is only a single fee type expected.
if (!feeTotal.equals(feesAndCredits.getTotalCost())) { if (!feeTotal.equals(feesAndCredits.getTotalCost())) {
if (!defaultTokenUsed || feeTotal.isLessThan(feesAndCredits.getTotalCost())) {
throw new FeesMismatchException(feesAndCredits.getTotalCost()); throw new FeesMismatchException(feesAndCredits.getTotalCost());
} }
} }
}
private static FeeType getOrParseType(Fee fee) throws ParameterValuePolicyErrorException { private static FeeType getOrParseType(Fee fee) throws ParameterValuePolicyErrorException {
if (fee.getType() != null) { if (fee.getType() != null) {

View file

@ -199,7 +199,7 @@ public final class DomainRenewFlow implements TransactionalFlow {
now, now,
years, years,
existingRecurringBillingEvent); existingRecurringBillingEvent);
validateFeeChallenge(feeRenew, feesAndCredits); validateFeeChallenge(feeRenew, feesAndCredits, false);
flowCustomLogic.afterValidation( flowCustomLogic.afterValidation(
AfterValidationParameters.newBuilder() AfterValidationParameters.newBuilder()
.setExistingDomain(existingDomain) .setExistingDomain(existingDomain)

View file

@ -226,7 +226,7 @@ public final class DomainRestoreRequestFlow implements TransactionalFlow {
if (!existingDomain.getGracePeriodStatuses().contains(GracePeriodStatus.REDEMPTION)) { if (!existingDomain.getGracePeriodStatuses().contains(GracePeriodStatus.REDEMPTION)) {
throw new DomainNotEligibleForRestoreException(); throw new DomainNotEligibleForRestoreException();
} }
validateFeeChallenge(feeUpdate, feesAndCredits); validateFeeChallenge(feeUpdate, feesAndCredits, false);
} }
private static Domain performRestore( private static Domain performRestore(

View file

@ -210,7 +210,7 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
} }
if (feesAndCredits.isPresent()) { if (feesAndCredits.isPresent()) {
validateFeeChallenge(feeTransfer, feesAndCredits.get()); validateFeeChallenge(feeTransfer, feesAndCredits.get(), false);
} }
HistoryEntryId domainHistoryId = createHistoryEntryId(existingDomain); HistoryEntryId domainHistoryId = createHistoryEntryId(existingDomain);
historyBuilder historyBuilder

View file

@ -231,7 +231,7 @@ public final class DomainUpdateFlow implements TransactionalFlow {
Optional<FeeUpdateCommandExtension> feeUpdate = Optional<FeeUpdateCommandExtension> feeUpdate =
eppInput.getSingleExtension(FeeUpdateCommandExtension.class); eppInput.getSingleExtension(FeeUpdateCommandExtension.class);
FeesAndCredits feesAndCredits = pricingLogic.getUpdatePrice(registry, targetId, now); FeesAndCredits feesAndCredits = pricingLogic.getUpdatePrice(registry, targetId, now);
validateFeesAckedIfPresent(feeUpdate, feesAndCredits); validateFeesAckedIfPresent(feeUpdate, feesAndCredits, false);
verifyNotInPendingDelete( verifyNotInPendingDelete(
add.getContacts(), add.getContacts(),
command.getInnerChange().getRegistrant(), command.getInnerChange().getRegistrant(),

View file

@ -703,7 +703,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6", "CURRENCY", "USD")); setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6", "CURRENCY", "USD"));
persistContactsAndHosts(); persistContactsAndHosts();
doSuccessfulTest( doSuccessfulTest(
"tld", "domain_create_response_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6")); "tld",
"domain_create_response_fee.xml",
ImmutableMap.of("FEE_VERSION", "0.6", "FEE", "26.00"));
} }
@Test @Test
@ -711,7 +713,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11", "CURRENCY", "USD")); setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11", "CURRENCY", "USD"));
persistContactsAndHosts(); persistContactsAndHosts();
doSuccessfulTest( doSuccessfulTest(
"tld", "domain_create_response_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11")); "tld",
"domain_create_response_fee.xml",
ImmutableMap.of("FEE_VERSION", "0.11", "FEE", "26.00"));
} }
@Test @Test
@ -719,7 +723,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12", "CURRENCY", "USD")); setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12", "CURRENCY", "USD"));
persistContactsAndHosts(); persistContactsAndHosts();
doSuccessfulTest( doSuccessfulTest(
"tld", "domain_create_response_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12")); "tld",
"domain_create_response_fee.xml",
ImmutableMap.of("FEE_VERSION", "0.12", "FEE", "26.00"));
} }
@Test @Test
@ -727,7 +733,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
setEppInput("domain_create_fee_defaults.xml", ImmutableMap.of("FEE_VERSION", "0.6")); setEppInput("domain_create_fee_defaults.xml", ImmutableMap.of("FEE_VERSION", "0.6"));
persistContactsAndHosts(); persistContactsAndHosts();
doSuccessfulTest( doSuccessfulTest(
"tld", "domain_create_response_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6")); "tld",
"domain_create_response_fee.xml",
ImmutableMap.of("FEE_VERSION", "0.6", "FEE", "26.00"));
} }
@Test @Test
@ -735,7 +743,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
setEppInput("domain_create_fee_defaults.xml", ImmutableMap.of("FEE_VERSION", "0.11")); setEppInput("domain_create_fee_defaults.xml", ImmutableMap.of("FEE_VERSION", "0.11"));
persistContactsAndHosts(); persistContactsAndHosts();
doSuccessfulTest( doSuccessfulTest(
"tld", "domain_create_response_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11")); "tld",
"domain_create_response_fee.xml",
ImmutableMap.of("FEE_VERSION", "0.11", "FEE", "26.00"));
} }
@Test @Test
@ -743,7 +753,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
setEppInput("domain_create_fee_defaults.xml", ImmutableMap.of("FEE_VERSION", "0.12")); setEppInput("domain_create_fee_defaults.xml", ImmutableMap.of("FEE_VERSION", "0.12"));
persistContactsAndHosts(); persistContactsAndHosts();
doSuccessfulTest( doSuccessfulTest(
"tld", "domain_create_response_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12")); "tld",
"domain_create_response_fee.xml",
ImmutableMap.of("FEE_VERSION", "0.12", "FEE", "26.00"));
} }
@Test @Test
@ -1111,6 +1123,57 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
assertAboutEppExceptions().that(thrown).marshalsToXml(); assertAboutEppExceptions().that(thrown).marshalsToXml();
} }
@Test
void testSuccess_wrongFeeAmountTooHigh_defaultToken_v06() throws Exception {
AllocationToken defaultToken =
persistResource(
new AllocationToken.Builder()
.setToken("bbbbb")
.setTokenType(DEFAULT_PROMO)
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedTlds(ImmutableSet.of("tld"))
.setDiscountFraction(0.5)
.build());
persistResource(
Registry.get("tld")
.asBuilder()
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
.setCreateBillingCost(Money.of(USD, 8))
.build());
// Expects fee of $26
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6", "CURRENCY", "USD"));
persistContactsAndHosts();
// $12 is equal to 50% off the first year registration and 0% 0ff the 2nd year
runFlowAssertResponse(
loadFile(
"domain_create_response_fee.xml",
ImmutableMap.of("FEE_VERSION", "0.6", "FEE", "12.00")));
}
@Test
void testFailure_wrongFeeAmountTooLow_defaultToken_v06() throws Exception {
AllocationToken defaultToken =
persistResource(
new AllocationToken.Builder()
.setToken("bbbbb")
.setTokenType(DEFAULT_PROMO)
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedTlds(ImmutableSet.of("tld"))
.setDiscountFraction(0.5)
.build());
persistResource(
Registry.get("tld")
.asBuilder()
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
.setCreateBillingCost(Money.of(USD, 100))
.build());
// Expects fee of $26
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6", "CURRENCY", "USD"));
persistContactsAndHosts();
EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test @Test
void testFailure_wrongFeeAmount_v11() { void testFailure_wrongFeeAmount_v11() {
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11", "CURRENCY", "USD")); setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11", "CURRENCY", "USD"));
@ -1121,6 +1184,57 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
assertAboutEppExceptions().that(thrown).marshalsToXml(); assertAboutEppExceptions().that(thrown).marshalsToXml();
} }
@Test
void testSuccess_wrongFeeAmountTooHigh_defaultToken_v11() throws Exception {
AllocationToken defaultToken =
persistResource(
new AllocationToken.Builder()
.setToken("bbbbb")
.setTokenType(DEFAULT_PROMO)
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedTlds(ImmutableSet.of("tld"))
.setDiscountFraction(0.5)
.build());
persistResource(
Registry.get("tld")
.asBuilder()
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
.setCreateBillingCost(Money.of(USD, 8))
.build());
// Expects fee of $26
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11", "CURRENCY", "USD"));
persistContactsAndHosts();
// $12 is equal to 50% off the first year registration and 0% 0ff the 2nd year
runFlowAssertResponse(
loadFile(
"domain_create_response_fee.xml",
ImmutableMap.of("FEE_VERSION", "0.11", "FEE", "12.00")));
}
@Test
void testFailure_wrongFeeAmountTooLow_defaultToken_v11() throws Exception {
AllocationToken defaultToken =
persistResource(
new AllocationToken.Builder()
.setToken("bbbbb")
.setTokenType(DEFAULT_PROMO)
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedTlds(ImmutableSet.of("tld"))
.setDiscountFraction(0.5)
.build());
persistResource(
Registry.get("tld")
.asBuilder()
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
.setCreateBillingCost(Money.of(USD, 100))
.build());
// Expects fee of $26
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11", "CURRENCY", "USD"));
persistContactsAndHosts();
EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test @Test
void testFailure_wrongFeeAmount_v12() { void testFailure_wrongFeeAmount_v12() {
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12", "CURRENCY", "USD")); setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12", "CURRENCY", "USD"));
@ -1131,6 +1245,57 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
assertAboutEppExceptions().that(thrown).marshalsToXml(); assertAboutEppExceptions().that(thrown).marshalsToXml();
} }
@Test
void testSuccess_wrongFeeAmountTooHigh_defaultToken_v12() throws Exception {
AllocationToken defaultToken =
persistResource(
new AllocationToken.Builder()
.setToken("bbbbb")
.setTokenType(DEFAULT_PROMO)
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedTlds(ImmutableSet.of("tld"))
.setDiscountFraction(0.5)
.build());
persistResource(
Registry.get("tld")
.asBuilder()
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
.setCreateBillingCost(Money.of(USD, 8))
.build());
// Expects fee of $26
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12", "CURRENCY", "USD"));
persistContactsAndHosts();
// $12 is equal to 50% off the first year registration and 0% 0ff the 2nd year
runFlowAssertResponse(
loadFile(
"domain_create_response_fee.xml",
ImmutableMap.of("FEE_VERSION", "0.12", "FEE", "12.00")));
}
@Test
void testFailure_wrongFeeAmountTooLow_defaultToken_v12() throws Exception {
AllocationToken defaultToken =
persistResource(
new AllocationToken.Builder()
.setToken("bbbbb")
.setTokenType(DEFAULT_PROMO)
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedTlds(ImmutableSet.of("tld"))
.setDiscountFraction(0.5)
.build());
persistResource(
Registry.get("tld")
.asBuilder()
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
.setCreateBillingCost(Money.of(USD, 100))
.build());
// Expects fee of $26
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12", "CURRENCY", "USD"));
persistContactsAndHosts();
EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test @Test
void testFailure_wrongCurrency_v06() { void testFailure_wrongCurrency_v06() {
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6", "CURRENCY", "EUR")); setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6", "CURRENCY", "EUR"));

View file

@ -14,7 +14,7 @@
<extension> <extension>
<fee:creData xmlns:fee="urn:ietf:params:xml:ns:fee-%FEE_VERSION%"> <fee:creData xmlns:fee="urn:ietf:params:xml:ns:fee-%FEE_VERSION%">
<fee:currency>USD</fee:currency> <fee:currency>USD</fee:currency>
<fee:fee description="create">26.00</fee:fee> <fee:fee description="create">%FEE%</fee:fee>
</fee:creData> </fee:creData>
</extension> </extension>
<trID> <trID>