Check PAK is present on billing domain flows (#1605)

* Check PAK on domain create

* Add unit test

* update docs

* Remove unneccesary setup

* Fix blank line

* Add check and test to all relevant flows

* Change error message
This commit is contained in:
sarahcaseybot 2022-04-29 14:30:24 -04:00 committed by GitHub
parent e1d36bd728
commit cea132f536
14 changed files with 184 additions and 0 deletions

View file

@ -20,6 +20,7 @@ import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static google.registry.flows.FlowUtils.validateRegistrarIsLoggedIn; import static google.registry.flows.FlowUtils.validateRegistrarIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyTargetIdCount; import static google.registry.flows.ResourceFlowUtils.verifyTargetIdCount;
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld; import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
import static google.registry.flows.domain.DomainFlowUtils.checkHasBillingAccount;
import static google.registry.flows.domain.DomainFlowUtils.getReservationTypes; import static google.registry.flows.domain.DomainFlowUtils.getReservationTypes;
import static google.registry.flows.domain.DomainFlowUtils.handleFeeRequest; import static google.registry.flows.domain.DomainFlowUtils.handleFeeRequest;
import static google.registry.flows.domain.DomainFlowUtils.isAnchorTenant; import static google.registry.flows.domain.DomainFlowUtils.isAnchorTenant;
@ -100,6 +101,7 @@ import org.joda.time.DateTime;
* @error {@link DomainFlowUtils.InvalidIdnDomainLabelException} * @error {@link DomainFlowUtils.InvalidIdnDomainLabelException}
* @error {@link DomainFlowUtils.InvalidPunycodeException} * @error {@link DomainFlowUtils.InvalidPunycodeException}
* @error {@link DomainFlowUtils.LeadingDashException} * @error {@link DomainFlowUtils.LeadingDashException}
* @error {@link DomainFlowUtils.MissingBillingAccountMapException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException} * @error {@link DomainFlowUtils.NotAuthorizedForTldException}
* @error {@link DomainFlowUtils.RestoresAreAlwaysForOneYearException} * @error {@link DomainFlowUtils.RestoresAreAlwaysForOneYearException}
* @error {@link DomainFlowUtils.TldDoesNotExistException} * @error {@link DomainFlowUtils.TldDoesNotExistException}
@ -153,6 +155,7 @@ public final class DomainCheckFlow implements Flow {
boolean tldFirstTimeSeen = seenTlds.add(tld); boolean tldFirstTimeSeen = seenTlds.add(tld);
if (tldFirstTimeSeen && !isSuperuser) { if (tldFirstTimeSeen && !isSuperuser) {
checkAllowedAccessToTld(registrarId, tld); checkAllowedAccessToTld(registrarId, tld);
checkHasBillingAccount(registrarId, tld);
verifyNotInPredelegation(Registry.get(tld), now); verifyNotInPredelegation(Registry.get(tld), now);
} }
} }

View file

@ -17,6 +17,7 @@ package google.registry.flows.domain;
import static google.registry.flows.FlowUtils.validateRegistrarIsLoggedIn; import static google.registry.flows.FlowUtils.validateRegistrarIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyTargetIdCount; import static google.registry.flows.ResourceFlowUtils.verifyTargetIdCount;
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld; import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
import static google.registry.flows.domain.DomainFlowUtils.checkHasBillingAccount;
import static google.registry.flows.domain.DomainFlowUtils.validateDomainName; import static google.registry.flows.domain.DomainFlowUtils.validateDomainName;
import static google.registry.flows.domain.DomainFlowUtils.validateDomainNameWithIdnTables; import static google.registry.flows.domain.DomainFlowUtils.validateDomainNameWithIdnTables;
import static google.registry.flows.domain.DomainFlowUtils.verifyClaimsPeriodNotEnded; import static google.registry.flows.domain.DomainFlowUtils.verifyClaimsPeriodNotEnded;
@ -60,6 +61,7 @@ import org.joda.time.DateTime;
* @error {@link google.registry.flows.FlowUtils.NotLoggedInException} * @error {@link google.registry.flows.FlowUtils.NotLoggedInException}
* @error {@link DomainFlowUtils.BadCommandForRegistryPhaseException} * @error {@link DomainFlowUtils.BadCommandForRegistryPhaseException}
* @error {@link DomainFlowUtils.ClaimsPeriodEndedException} * @error {@link DomainFlowUtils.ClaimsPeriodEndedException}
* @error {@link DomainFlowUtils.MissingBillingAccountMapException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException} * @error {@link DomainFlowUtils.NotAuthorizedForTldException}
* @error {@link DomainFlowUtils.TldDoesNotExistException} * @error {@link DomainFlowUtils.TldDoesNotExistException}
* @error {@link DomainClaimsCheckNotAllowedWithAllocationTokens} * @error {@link DomainClaimsCheckNotAllowedWithAllocationTokens}
@ -99,6 +101,7 @@ public final class DomainClaimsCheckFlow implements Flow {
if (seenTlds.add(tld)) { if (seenTlds.add(tld)) {
if (!isSuperuser) { if (!isSuperuser) {
checkAllowedAccessToTld(registrarId, tld); checkAllowedAccessToTld(registrarId, tld);
checkHasBillingAccount(registrarId, tld);
Registry registry = Registry.get(tld); Registry registry = Registry.get(tld);
DateTime now = clock.nowUtc(); DateTime now = clock.nowUtc();
verifyNotInPredelegation(registry, now); verifyNotInPredelegation(registry, now);

View file

@ -20,6 +20,7 @@ import static google.registry.flows.FlowUtils.validateRegistrarIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyResourceDoesNotExist; import static google.registry.flows.ResourceFlowUtils.verifyResourceDoesNotExist;
import static google.registry.flows.domain.DomainFlowUtils.COLLISION_MESSAGE; import static google.registry.flows.domain.DomainFlowUtils.COLLISION_MESSAGE;
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld; import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
import static google.registry.flows.domain.DomainFlowUtils.checkHasBillingAccount;
import static google.registry.flows.domain.DomainFlowUtils.cloneAndLinkReferences; import static google.registry.flows.domain.DomainFlowUtils.cloneAndLinkReferences;
import static google.registry.flows.domain.DomainFlowUtils.createFeeCreateResponse; import static google.registry.flows.domain.DomainFlowUtils.createFeeCreateResponse;
import static google.registry.flows.domain.DomainFlowUtils.getReservationTypes; import static google.registry.flows.domain.DomainFlowUtils.getReservationTypes;
@ -180,6 +181,7 @@ import org.joda.time.Duration;
* @error {@link DomainFlowUtils.MalformedTcnIdException} * @error {@link DomainFlowUtils.MalformedTcnIdException}
* @error {@link DomainFlowUtils.MaxSigLifeNotSupportedException} * @error {@link DomainFlowUtils.MaxSigLifeNotSupportedException}
* @error {@link DomainFlowUtils.MissingAdminContactException} * @error {@link DomainFlowUtils.MissingAdminContactException}
* @error {@link DomainFlowUtils.MissingBillingAccountMapException}
* @error {@link DomainFlowUtils.MissingClaimsNoticeException} * @error {@link DomainFlowUtils.MissingClaimsNoticeException}
* @error {@link DomainFlowUtils.MissingContactTypeException} * @error {@link DomainFlowUtils.MissingContactTypeException}
* @error {@link DomainFlowUtils.MissingRegistrantException} * @error {@link DomainFlowUtils.MissingRegistrantException}
@ -265,6 +267,7 @@ public final class DomainCreateFlow implements TransactionalFlow {
// registering premium domains. // registering premium domains.
if (!isSuperuser) { if (!isSuperuser) {
checkAllowedAccessToTld(registrarId, registry.getTldStr()); checkAllowedAccessToTld(registrarId, registry.getTldStr());
checkHasBillingAccount(registrarId, registry.getTldStr());
boolean isValidReservedCreate = isValidReservedCreate(domainName, allocationToken); boolean isValidReservedCreate = isValidReservedCreate(domainName, allocationToken);
verifyIsGaOrIsSpecialCase(tldState, isAnchorTenant, isValidReservedCreate, hasSignedMarks); verifyIsGaOrIsSpecialCase(tldState, isAnchorTenant, isValidReservedCreate, hasSignedMarks);
if (launchCreate.isPresent()) { if (launchCreate.isPresent()) {

View file

@ -293,6 +293,17 @@ public class DomainFlowUtils {
} }
} }
/** Check if the registrar has the correct billing account map configured. */
public static void checkHasBillingAccount(String registrarId, String tld) throws EppException {
CurrencyUnit currency = Registry.get(tld).getCurrency();
if (!Registrar.loadByRegistrarIdCached(registrarId)
.get()
.getBillingAccountMap()
.containsKey(currency)) {
throw new DomainFlowUtils.MissingBillingAccountMapException(currency);
}
}
/** Check that the DS data that will be set on a domain is valid. */ /** Check that the DS data that will be set on a domain is valid. */
static void validateDsData(Set<DelegationSignerData> dsData) throws EppException { static void validateDsData(Set<DelegationSignerData> dsData) throws EppException {
if (dsData != null) { if (dsData != null) {
@ -1501,6 +1512,13 @@ public class DomainFlowUtils {
} }
} }
/** Registrar is missing the billing account map for this currency type. */
public static class MissingBillingAccountMapException extends AuthorizationErrorException {
public MissingBillingAccountMapException(CurrencyUnit currency) {
super("Registrar is not fully onboarded for TLDs that bill in " + currency);
}
}
/** Registrant is not allow-listed for this TLD. */ /** Registrant is not allow-listed for this TLD. */
public static class RegistrantNotAllowedException extends StatusProhibitsOperationException { public static class RegistrantNotAllowedException extends StatusProhibitsOperationException {
public RegistrantNotAllowedException(String contactId) { public RegistrantNotAllowedException(String contactId) {

View file

@ -22,6 +22,7 @@ import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo; import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo;
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership; import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld; import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
import static google.registry.flows.domain.DomainFlowUtils.checkHasBillingAccount;
import static google.registry.flows.domain.DomainFlowUtils.newAutorenewBillingEvent; import static google.registry.flows.domain.DomainFlowUtils.newAutorenewBillingEvent;
import static google.registry.flows.domain.DomainFlowUtils.newAutorenewPollMessage; import static google.registry.flows.domain.DomainFlowUtils.newAutorenewPollMessage;
import static google.registry.flows.domain.DomainFlowUtils.updateAutorenewRecurrenceEndTime; import static google.registry.flows.domain.DomainFlowUtils.updateAutorenewRecurrenceEndTime;
@ -106,6 +107,7 @@ import org.joda.time.Duration;
* @error {@link DomainFlowUtils.ExceedsMaxRegistrationYearsException} * @error {@link DomainFlowUtils.ExceedsMaxRegistrationYearsException}
* @error {@link DomainFlowUtils.FeesMismatchException} * @error {@link DomainFlowUtils.FeesMismatchException}
* @error {@link DomainFlowUtils.FeesRequiredForPremiumNameException} * @error {@link DomainFlowUtils.FeesRequiredForPremiumNameException}
* @error {@link DomainFlowUtils.MissingBillingAccountMapException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException} * @error {@link DomainFlowUtils.NotAuthorizedForTldException}
* @error {@link DomainFlowUtils.RegistrarMustBeActiveForThisOperationException} * @error {@link DomainFlowUtils.RegistrarMustBeActiveForThisOperationException}
* @error {@link DomainFlowUtils.UnsupportedFeeAttributeException} * @error {@link DomainFlowUtils.UnsupportedFeeAttributeException}
@ -263,6 +265,7 @@ public final class DomainRenewFlow implements TransactionalFlow {
if (!isSuperuser) { if (!isSuperuser) {
verifyResourceOwnership(registrarId, existingDomain); verifyResourceOwnership(registrarId, existingDomain);
checkAllowedAccessToTld(registrarId, existingDomain.getTld()); checkAllowedAccessToTld(registrarId, existingDomain.getTld());
checkHasBillingAccount(registrarId, existingDomain.getTld());
} }
verifyUnitIsYears(command.getPeriod()); verifyUnitIsYears(command.getPeriod());
// If the date they specify doesn't match the expiration, fail. (This is an idempotence check). // If the date they specify doesn't match the expiration, fail. (This is an idempotence check).

View file

@ -20,6 +20,7 @@ import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo; import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo;
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership; import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld; import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
import static google.registry.flows.domain.DomainFlowUtils.checkHasBillingAccount;
import static google.registry.flows.domain.DomainFlowUtils.newAutorenewBillingEvent; import static google.registry.flows.domain.DomainFlowUtils.newAutorenewBillingEvent;
import static google.registry.flows.domain.DomainFlowUtils.newAutorenewPollMessage; import static google.registry.flows.domain.DomainFlowUtils.newAutorenewPollMessage;
import static google.registry.flows.domain.DomainFlowUtils.validateFeeChallenge; import static google.registry.flows.domain.DomainFlowUtils.validateFeeChallenge;
@ -104,6 +105,7 @@ import org.joda.time.DateTime;
* @error {@link DomainFlowUtils.DomainReservedException} * @error {@link DomainFlowUtils.DomainReservedException}
* @error {@link DomainFlowUtils.FeesMismatchException} * @error {@link DomainFlowUtils.FeesMismatchException}
* @error {@link DomainFlowUtils.FeesRequiredForPremiumNameException} * @error {@link DomainFlowUtils.FeesRequiredForPremiumNameException}
* @error {@link DomainFlowUtils.MissingBillingAccountMapException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException} * @error {@link DomainFlowUtils.NotAuthorizedForTldException}
* @error {@link DomainFlowUtils.PremiumNameBlockedException} * @error {@link DomainFlowUtils.PremiumNameBlockedException}
* @error {@link DomainFlowUtils.RegistrarMustBeActiveForThisOperationException} * @error {@link DomainFlowUtils.RegistrarMustBeActiveForThisOperationException}
@ -216,6 +218,7 @@ public final class DomainRestoreRequestFlow implements TransactionalFlow {
verifyNotReserved(InternetDomainName.from(targetId), false); verifyNotReserved(InternetDomainName.from(targetId), false);
verifyPremiumNameIsNotBlocked(targetId, now, registrarId); verifyPremiumNameIsNotBlocked(targetId, now, registrarId);
checkAllowedAccessToTld(registrarId, existingDomain.getTld()); checkAllowedAccessToTld(registrarId, existingDomain.getTld());
checkHasBillingAccount(registrarId, existingDomain.getTld());
} }
// No other changes can be specified on a restore request. // No other changes can be specified on a restore request.
if (!command.noChangesPresent()) { if (!command.noChangesPresent()) {

View file

@ -22,6 +22,7 @@ import static google.registry.flows.ResourceFlowUtils.verifyAuthInfo;
import static google.registry.flows.ResourceFlowUtils.verifyAuthInfoPresentForResourceTransfer; import static google.registry.flows.ResourceFlowUtils.verifyAuthInfoPresentForResourceTransfer;
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses; import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld; import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
import static google.registry.flows.domain.DomainFlowUtils.checkHasBillingAccount;
import static google.registry.flows.domain.DomainFlowUtils.updateAutorenewRecurrenceEndTime; import static google.registry.flows.domain.DomainFlowUtils.updateAutorenewRecurrenceEndTime;
import static google.registry.flows.domain.DomainFlowUtils.validateFeeChallenge; import static google.registry.flows.domain.DomainFlowUtils.validateFeeChallenge;
import static google.registry.flows.domain.DomainFlowUtils.verifyPremiumNameIsNotBlocked; import static google.registry.flows.domain.DomainFlowUtils.verifyPremiumNameIsNotBlocked;
@ -111,6 +112,7 @@ import org.joda.time.DateTime;
* @error {@link DomainFlowUtils.CurrencyValueScaleException} * @error {@link DomainFlowUtils.CurrencyValueScaleException}
* @error {@link DomainFlowUtils.FeesMismatchException} * @error {@link DomainFlowUtils.FeesMismatchException}
* @error {@link DomainFlowUtils.FeesRequiredForPremiumNameException} * @error {@link DomainFlowUtils.FeesRequiredForPremiumNameException}
* @error {@link DomainFlowUtils.MissingBillingAccountMapException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException} * @error {@link DomainFlowUtils.NotAuthorizedForTldException}
* @error {@link DomainFlowUtils.PremiumNameBlockedException} * @error {@link DomainFlowUtils.PremiumNameBlockedException}
* @error {@link DomainFlowUtils.RegistrarMustBeActiveForThisOperationException} * @error {@link DomainFlowUtils.RegistrarMustBeActiveForThisOperationException}
@ -273,6 +275,7 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
verifyTransferPeriod(period, superuserExtension); verifyTransferPeriod(period, superuserExtension);
if (!isSuperuser) { if (!isSuperuser) {
checkAllowedAccessToTld(gainingClientId, existingDomain.getTld()); checkAllowedAccessToTld(gainingClientId, existingDomain.getTld());
checkHasBillingAccount(gainingClientId, existingDomain.getTld());
verifyPremiumNameIsNotBlocked(targetId, now, gainingClientId); verifyPremiumNameIsNotBlocked(targetId, now, gainingClientId);
} }
} }

View file

@ -30,6 +30,7 @@ import static google.registry.testing.DatabaseHelper.persistReservedList;
import static google.registry.testing.DatabaseHelper.persistResource; import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions; import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
import static google.registry.util.DateTimeUtils.START_OF_TIME; import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.money.CurrencyUnit.JPY;
import static org.joda.money.CurrencyUnit.USD; import static org.joda.money.CurrencyUnit.USD;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
@ -57,6 +58,7 @@ import google.registry.flows.domain.DomainFlowUtils.FeeChecksDontSupportPhasesEx
import google.registry.flows.domain.DomainFlowUtils.InvalidIdnDomainLabelException; import google.registry.flows.domain.DomainFlowUtils.InvalidIdnDomainLabelException;
import google.registry.flows.domain.DomainFlowUtils.InvalidPunycodeException; import google.registry.flows.domain.DomainFlowUtils.InvalidPunycodeException;
import google.registry.flows.domain.DomainFlowUtils.LeadingDashException; import google.registry.flows.domain.DomainFlowUtils.LeadingDashException;
import google.registry.flows.domain.DomainFlowUtils.MissingBillingAccountMapException;
import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException; import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException;
import google.registry.flows.domain.DomainFlowUtils.RestoresAreAlwaysForOneYearException; import google.registry.flows.domain.DomainFlowUtils.RestoresAreAlwaysForOneYearException;
import google.registry.flows.domain.DomainFlowUtils.TldDoesNotExistException; import google.registry.flows.domain.DomainFlowUtils.TldDoesNotExistException;
@ -600,6 +602,24 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
assertAboutEppExceptions().that(thrown).marshalsToXml(); assertAboutEppExceptions().that(thrown).marshalsToXml();
} }
@TestOfyAndSql
void testFailure_missingBillingAccount() {
persistResource(
Registry.get("tld")
.asBuilder()
.setCurrency(JPY)
.setCreateBillingCost(Money.ofMajor(JPY, 800))
.setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800)))
.setRenewBillingCostTransitions(
ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800)))
.setRegistryLockOrUnlockBillingCost(Money.ofMajor(JPY, 800))
.setServerStatusChangeBillingCost(Money.ofMajor(JPY, 800))
.setRestoreBillingCost(Money.ofMajor(JPY, 800))
.build());
EppException thrown = assertThrows(MissingBillingAccountMapException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@TestOfyAndSql @TestOfyAndSql
void testSuccess_superuserNotAuthorizedForTld() throws Exception { void testSuccess_superuserNotAuthorizedForTld() throws Exception {
persistActiveDomain("example2.tld"); persistActiveDomain("example2.tld");

View file

@ -21,16 +21,20 @@ import static google.registry.testing.DatabaseHelper.createTlds;
import static google.registry.testing.DatabaseHelper.loadRegistrar; import static google.registry.testing.DatabaseHelper.loadRegistrar;
import static google.registry.testing.DatabaseHelper.persistResource; import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions; import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.money.CurrencyUnit.JPY;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.FlowUtils.NotLoggedInException; import google.registry.flows.FlowUtils.NotLoggedInException;
import google.registry.flows.ResourceFlowTestCase; import google.registry.flows.ResourceFlowTestCase;
import google.registry.flows.domain.DomainClaimsCheckFlow.DomainClaimsCheckNotAllowedWithAllocationTokens; import google.registry.flows.domain.DomainClaimsCheckFlow.DomainClaimsCheckNotAllowedWithAllocationTokens;
import google.registry.flows.domain.DomainFlowUtils.BadCommandForRegistryPhaseException; import google.registry.flows.domain.DomainFlowUtils.BadCommandForRegistryPhaseException;
import google.registry.flows.domain.DomainFlowUtils.ClaimsPeriodEndedException; import google.registry.flows.domain.DomainFlowUtils.ClaimsPeriodEndedException;
import google.registry.flows.domain.DomainFlowUtils.MissingBillingAccountMapException;
import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException; import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException;
import google.registry.flows.domain.DomainFlowUtils.TldDoesNotExistException; import google.registry.flows.domain.DomainFlowUtils.TldDoesNotExistException;
import google.registry.flows.exceptions.TooManyResourceChecksException; import google.registry.flows.exceptions.TooManyResourceChecksException;
@ -40,6 +44,7 @@ import google.registry.model.tld.Registry.TldState;
import google.registry.testing.DualDatabaseTest; import google.registry.testing.DualDatabaseTest;
import google.registry.testing.ReplayExtension; import google.registry.testing.ReplayExtension;
import google.registry.testing.TestOfyAndSql; import google.registry.testing.TestOfyAndSql;
import org.joda.money.Money;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.api.extension.RegisterExtension;
@ -133,6 +138,24 @@ public class DomainClaimsCheckFlowTest
assertAboutEppExceptions().that(thrown).marshalsToXml(); assertAboutEppExceptions().that(thrown).marshalsToXml();
} }
@TestOfyAndSql
void testFailure_missingBillingAccount() {
persistResource(
Registry.get("tld")
.asBuilder()
.setCurrency(JPY)
.setCreateBillingCost(Money.ofMajor(JPY, 800))
.setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800)))
.setRenewBillingCostTransitions(
ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800)))
.setRegistryLockOrUnlockBillingCost(Money.ofMajor(JPY, 800))
.setServerStatusChangeBillingCost(Money.ofMajor(JPY, 800))
.setRestoreBillingCost(Money.ofMajor(JPY, 800))
.build());
EppException thrown = assertThrows(MissingBillingAccountMapException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@TestOfyAndSql @TestOfyAndSql
void testSuccess_superuserNotAuthorizedForTld() throws Exception { void testSuccess_superuserNotAuthorizedForTld() throws Exception {
persistClaimsList( persistClaimsList(

View file

@ -59,6 +59,7 @@ import static google.registry.tmch.LordnTaskUtils.QUEUE_CLAIMS;
import static google.registry.tmch.LordnTaskUtils.QUEUE_SUNRISE; import static google.registry.tmch.LordnTaskUtils.QUEUE_SUNRISE;
import static google.registry.util.DateTimeUtils.END_OF_TIME; import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static google.registry.util.DateTimeUtils.START_OF_TIME; import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.money.CurrencyUnit.JPY;
import static org.joda.money.CurrencyUnit.USD; import static org.joda.money.CurrencyUnit.USD;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
@ -117,6 +118,7 @@ import google.registry.flows.domain.DomainFlowUtils.LinkedResourcesDoNotExistExc
import google.registry.flows.domain.DomainFlowUtils.MalformedTcnIdException; import google.registry.flows.domain.DomainFlowUtils.MalformedTcnIdException;
import google.registry.flows.domain.DomainFlowUtils.MaxSigLifeNotSupportedException; import google.registry.flows.domain.DomainFlowUtils.MaxSigLifeNotSupportedException;
import google.registry.flows.domain.DomainFlowUtils.MissingAdminContactException; import google.registry.flows.domain.DomainFlowUtils.MissingAdminContactException;
import google.registry.flows.domain.DomainFlowUtils.MissingBillingAccountMapException;
import google.registry.flows.domain.DomainFlowUtils.MissingClaimsNoticeException; import google.registry.flows.domain.DomainFlowUtils.MissingClaimsNoticeException;
import google.registry.flows.domain.DomainFlowUtils.MissingContactTypeException; import google.registry.flows.domain.DomainFlowUtils.MissingContactTypeException;
import google.registry.flows.domain.DomainFlowUtils.MissingRegistrantException; import google.registry.flows.domain.DomainFlowUtils.MissingRegistrantException;
@ -2222,6 +2224,25 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
assertAboutEppExceptions().that(thrown).marshalsToXml(); assertAboutEppExceptions().that(thrown).marshalsToXml();
} }
@TestOfyAndSql
void testFailure_missingBillingAccountMap() {
persistContactsAndHosts();
persistResource(
Registry.get("tld")
.asBuilder()
.setCurrency(JPY)
.setCreateBillingCost(Money.ofMajor(JPY, 800))
.setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800)))
.setRenewBillingCostTransitions(
ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800)))
.setRegistryLockOrUnlockBillingCost(Money.ofMajor(JPY, 800))
.setServerStatusChangeBillingCost(Money.ofMajor(JPY, 800))
.setRestoreBillingCost(Money.ofMajor(JPY, 800))
.build());
EppException thrown = assertThrows(MissingBillingAccountMapException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@TestOfyAndSql @TestOfyAndSql
void testFailure_registrantNotAllowListed() { void testFailure_registrantNotAllowListed() {
persistActiveContact("someone"); persistActiveContact("someone");

View file

@ -35,6 +35,7 @@ import static google.registry.testing.TestDataHelper.updateSubstitutions;
import static google.registry.util.DateTimeUtils.END_OF_TIME; import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static google.registry.util.DateTimeUtils.START_OF_TIME; import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.money.CurrencyUnit.EUR; import static org.joda.money.CurrencyUnit.EUR;
import static org.joda.money.CurrencyUnit.JPY;
import static org.joda.money.CurrencyUnit.USD; import static org.joda.money.CurrencyUnit.USD;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
@ -55,6 +56,7 @@ import google.registry.flows.domain.DomainFlowUtils.CurrencyValueScaleException;
import google.registry.flows.domain.DomainFlowUtils.ExceedsMaxRegistrationYearsException; import google.registry.flows.domain.DomainFlowUtils.ExceedsMaxRegistrationYearsException;
import google.registry.flows.domain.DomainFlowUtils.FeesMismatchException; import google.registry.flows.domain.DomainFlowUtils.FeesMismatchException;
import google.registry.flows.domain.DomainFlowUtils.FeesRequiredForPremiumNameException; import google.registry.flows.domain.DomainFlowUtils.FeesRequiredForPremiumNameException;
import google.registry.flows.domain.DomainFlowUtils.MissingBillingAccountMapException;
import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException; import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException;
import google.registry.flows.domain.DomainFlowUtils.RegistrarMustBeActiveForThisOperationException; import google.registry.flows.domain.DomainFlowUtils.RegistrarMustBeActiveForThisOperationException;
import google.registry.flows.domain.DomainFlowUtils.UnsupportedFeeAttributeException; import google.registry.flows.domain.DomainFlowUtils.UnsupportedFeeAttributeException;
@ -122,6 +124,11 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, DomainBa
@BeforeEach @BeforeEach
void initDomainTest() { void initDomainTest() {
createTld("tld"); createTld("tld");
persistResource(
loadRegistrar("TheRegistrar")
.asBuilder()
.setBillingAccountMap(ImmutableMap.of(USD, "123", EUR, "567"))
.build());
setEppInput("domain_renew.xml", ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "5")); setEppInput("domain_renew.xml", ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "5"));
} }
@ -759,6 +766,25 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, DomainBa
assertAboutEppExceptions().that(thrown).marshalsToXml(); assertAboutEppExceptions().that(thrown).marshalsToXml();
} }
@TestOfyAndSql
void testFailure_missingBillingAccountMap() throws Exception {
persistDomain();
persistResource(
Registry.get("tld")
.asBuilder()
.setCurrency(JPY)
.setCreateBillingCost(Money.ofMajor(JPY, 800))
.setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800)))
.setRenewBillingCostTransitions(
ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800)))
.setRegistryLockOrUnlockBillingCost(Money.ofMajor(JPY, 800))
.setServerStatusChangeBillingCost(Money.ofMajor(JPY, 800))
.setRestoreBillingCost(Money.ofMajor(JPY, 800))
.build());
EppException thrown = assertThrows(MissingBillingAccountMapException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@TestOfyAndSql @TestOfyAndSql
void testFailure_pendingTransfer() throws Exception { void testFailure_pendingTransfer() throws Exception {
persistDomain(); persistDomain();

View file

@ -34,6 +34,7 @@ import static google.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
import static google.registry.util.DateTimeUtils.END_OF_TIME; import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static google.registry.util.DateTimeUtils.START_OF_TIME; import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.money.CurrencyUnit.EUR; import static org.joda.money.CurrencyUnit.EUR;
import static org.joda.money.CurrencyUnit.JPY;
import static org.joda.money.CurrencyUnit.USD; import static org.joda.money.CurrencyUnit.USD;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
@ -53,6 +54,7 @@ import google.registry.flows.domain.DomainFlowUtils.CurrencyValueScaleException;
import google.registry.flows.domain.DomainFlowUtils.DomainReservedException; import google.registry.flows.domain.DomainFlowUtils.DomainReservedException;
import google.registry.flows.domain.DomainFlowUtils.FeesMismatchException; import google.registry.flows.domain.DomainFlowUtils.FeesMismatchException;
import google.registry.flows.domain.DomainFlowUtils.FeesRequiredForPremiumNameException; import google.registry.flows.domain.DomainFlowUtils.FeesRequiredForPremiumNameException;
import google.registry.flows.domain.DomainFlowUtils.MissingBillingAccountMapException;
import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException; import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException;
import google.registry.flows.domain.DomainFlowUtils.PremiumNameBlockedException; import google.registry.flows.domain.DomainFlowUtils.PremiumNameBlockedException;
import google.registry.flows.domain.DomainFlowUtils.RegistrarMustBeActiveForThisOperationException; import google.registry.flows.domain.DomainFlowUtils.RegistrarMustBeActiveForThisOperationException;
@ -106,6 +108,11 @@ class DomainRestoreRequestFlowTest
@BeforeEach @BeforeEach
void initDomainTest() { void initDomainTest() {
createTld("tld"); createTld("tld");
persistResource(
loadRegistrar("TheRegistrar")
.asBuilder()
.setBillingAccountMap(ImmutableMap.of(USD, "123", EUR, "567"))
.build());
setEppInput("domain_update_restore_request.xml", ImmutableMap.of("DOMAIN", "example.tld")); setEppInput("domain_update_restore_request.xml", ImmutableMap.of("DOMAIN", "example.tld"));
} }
@ -705,6 +712,25 @@ class DomainRestoreRequestFlowTest
assertAboutEppExceptions().that(thrown).marshalsToXml(); assertAboutEppExceptions().that(thrown).marshalsToXml();
} }
@TestOfyAndSql
void testFailure_missingBillingAccount() throws Exception {
persistPendingDeleteDomain();
persistResource(
Registry.get("tld")
.asBuilder()
.setCurrency(JPY)
.setCreateBillingCost(Money.ofMajor(JPY, 800))
.setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800)))
.setRenewBillingCostTransitions(
ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800)))
.setRegistryLockOrUnlockBillingCost(Money.ofMajor(JPY, 800))
.setServerStatusChangeBillingCost(Money.ofMajor(JPY, 800))
.setRestoreBillingCost(Money.ofMajor(JPY, 800))
.build());
EppException thrown = assertThrows(MissingBillingAccountMapException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@TestOfyAndSql @TestOfyAndSql
void testSuccess_superuserNotAuthorizedForTld() throws Exception { void testSuccess_superuserNotAuthorizedForTld() throws Exception {
persistResource( persistResource(

View file

@ -44,6 +44,7 @@ import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptio
import static google.registry.testing.HistoryEntrySubject.assertAboutHistoryEntries; import static google.registry.testing.HistoryEntrySubject.assertAboutHistoryEntries;
import static google.registry.testing.HostResourceSubject.assertAboutHosts; import static google.registry.testing.HostResourceSubject.assertAboutHosts;
import static google.registry.util.DateTimeUtils.START_OF_TIME; import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.money.CurrencyUnit.JPY;
import static org.joda.money.CurrencyUnit.USD; import static org.joda.money.CurrencyUnit.USD;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
@ -70,6 +71,7 @@ import google.registry.flows.domain.DomainFlowUtils.CurrencyUnitMismatchExceptio
import google.registry.flows.domain.DomainFlowUtils.CurrencyValueScaleException; import google.registry.flows.domain.DomainFlowUtils.CurrencyValueScaleException;
import google.registry.flows.domain.DomainFlowUtils.FeesMismatchException; import google.registry.flows.domain.DomainFlowUtils.FeesMismatchException;
import google.registry.flows.domain.DomainFlowUtils.FeesRequiredForPremiumNameException; import google.registry.flows.domain.DomainFlowUtils.FeesRequiredForPremiumNameException;
import google.registry.flows.domain.DomainFlowUtils.MissingBillingAccountMapException;
import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException; import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException;
import google.registry.flows.domain.DomainFlowUtils.PremiumNameBlockedException; import google.registry.flows.domain.DomainFlowUtils.PremiumNameBlockedException;
import google.registry.flows.domain.DomainFlowUtils.RegistrarMustBeActiveForThisOperationException; import google.registry.flows.domain.DomainFlowUtils.RegistrarMustBeActiveForThisOperationException;
@ -1065,6 +1067,30 @@ class DomainTransferRequestFlowTest
assertAboutEppExceptions().that(thrown).marshalsToXml(); assertAboutEppExceptions().that(thrown).marshalsToXml();
} }
@TestOfyAndSql
void testFailure_missingBillingAccount() {
setupDomain("example", "tld");
persistResource(
Registry.get("tld")
.asBuilder()
.setCurrency(JPY)
.setCreateBillingCost(Money.ofMajor(JPY, 800))
.setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800)))
.setRenewBillingCostTransitions(
ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800)))
.setRegistryLockOrUnlockBillingCost(Money.ofMajor(JPY, 800))
.setServerStatusChangeBillingCost(Money.ofMajor(JPY, 800))
.setRestoreBillingCost(Money.ofMajor(JPY, 800))
.build());
EppException thrown =
assertThrows(
MissingBillingAccountMapException.class,
() ->
doSuccessfulTest(
"domain_transfer_request.xml", "domain_transfer_request_response.xml"));
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@TestOfyAndSql @TestOfyAndSql
void testSuccess_superuserNotAuthorizedForTld() throws Exception { void testSuccess_superuserNotAuthorizedForTld() throws Exception {
setupDomain("example", "tld"); setupDomain("example", "tld");

View file

@ -269,6 +269,7 @@ information.
* Domain name must have exactly one part above the TLD. * Domain name must have exactly one part above the TLD.
* Domain name must not equal an existing multi-part TLD. * Domain name must not equal an existing multi-part TLD.
* 2201 * 2201
* Registrar is missing the billing account map for this currency type.
* Registrar is not authorized to access this TLD. * Registrar is not authorized to access this TLD.
* 2306 * 2306
* Too many resource checks requested in one check command. * Too many resource checks requested in one check command.
@ -304,6 +305,7 @@ An EPP flow that checks whether domain labels are trademarked.
* 2004 * 2004
* Domain name is under tld which doesn't exist. * Domain name is under tld which doesn't exist.
* 2201 * 2201
* Registrar is missing the billing account map for this currency type.
* Registrar is not authorized to access this TLD. * Registrar is not authorized to access this TLD.
* 2304 * 2304
* The claims period for this TLD has ended. * The claims period for this TLD has ended.
@ -361,6 +363,7 @@ An EPP flow that creates a new domain resource.
* The allocation token is invalid. * The allocation token is invalid.
* Only a tool can pass a metadata extension. * Only a tool can pass a metadata extension.
* Registrar is not authorized to access this TLD. * Registrar is not authorized to access this TLD.
* Registrar is missing the billing account map for this currency type.
* Registrar must be active in order to perform this operation. * Registrar must be active in order to perform this operation.
* 2302 * 2302
* Resource with this id already exists. * Resource with this id already exists.
@ -501,6 +504,7 @@ comes in at the exact millisecond that the domain would have expired.
server policy. server policy.
* 2201 * 2201
* The specified resource belongs to another client. * The specified resource belongs to another client.
* Registrar is missing the billing account map for this currency type.
* Registrar is not authorized to access this TLD. * Registrar is not authorized to access this TLD.
* Registrar must be active in order to perform this operation. * Registrar must be active in order to perform this operation.
* 2303 * 2303
@ -561,6 +565,7 @@ regardless of what the original expiration time was.
* Specified extension is not implemented. * Specified extension is not implemented.
* 2201 * 2201
* The specified resource belongs to another client. * The specified resource belongs to another client.
* Registrar is missing the billing account map for this currency type.
* Registrar is not authorized to access this TLD. * Registrar is not authorized to access this TLD.
* Registrar must be active in order to perform this operation. * Registrar must be active in order to perform this operation.
* 2303 * 2303
@ -736,6 +741,7 @@ new ones with the correct approval time).
server policy. server policy.
* 2201 * 2201
* Authorization info is required to request a transfer. * Authorization info is required to request a transfer.
* Registrar is missing the billing account map for this currency type.
* Registrar is not authorized to access this TLD. * Registrar is not authorized to access this TLD.
* Registrar must be active in order to perform this operation. * Registrar must be active in order to perform this operation.
* 2202 * 2202