mirror of
https://github.com/google/nomulus
synced 2026-09-20 15:04:24 +00:00
Check allowedEppActions when validating tokens (#1972)
* Check allowedEppActions when validating tokens * Reflect failed tokens in the fee check * Add tests for domainCheckFlow * Add hyphens to fee class name * Add clarifying comment to catch block * Add specific exception types
This commit is contained in:
@@ -53,6 +53,11 @@ import google.registry.flows.custom.DomainCheckFlowCustomLogic.BeforeResponsePar
|
||||
import google.registry.flows.custom.DomainCheckFlowCustomLogic.BeforeResponseReturnData;
|
||||
import google.registry.flows.domain.token.AllocationTokenDomainCheckResults;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotInPromotionException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForCommandException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForDomainException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForRegistrarException;
|
||||
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForTldException;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.model.ForeignKeyUtils;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
@@ -277,22 +282,52 @@ public final class DomainCheckFlow implements Flow {
|
||||
DomainFlowUtils.checkForDefaultToken(
|
||||
Registry.get(InternetDomainName.from(domainName).parent().toString()),
|
||||
domainName,
|
||||
feeCheckItem.getCommandName(),
|
||||
registrarId,
|
||||
now);
|
||||
FeeCheckResponseExtensionItem.Builder<?> builder = feeCheckItem.createResponseBuilder();
|
||||
Optional<Domain> domain = Optional.ofNullable(domainObjs.get(domainName));
|
||||
handleFeeRequest(
|
||||
feeCheckItem,
|
||||
builder,
|
||||
domainNames.get(domainName),
|
||||
domain,
|
||||
feeCheck.getCurrency(),
|
||||
now,
|
||||
pricingLogic,
|
||||
allocationToken.isPresent() ? allocationToken : defaultToken,
|
||||
availableDomains.contains(domainName),
|
||||
recurrences.getOrDefault(domainName, null));
|
||||
responseItems.add(builder.setDomainNameIfSupported(domainName).build());
|
||||
try {
|
||||
if (allocationToken.isPresent()) {
|
||||
AllocationTokenFlowUtils.validateToken(
|
||||
InternetDomainName.from(domainName),
|
||||
allocationToken.get(),
|
||||
feeCheckItem.getCommandName(),
|
||||
registrarId,
|
||||
now);
|
||||
}
|
||||
handleFeeRequest(
|
||||
feeCheckItem,
|
||||
builder,
|
||||
domainNames.get(domainName),
|
||||
domain,
|
||||
feeCheck.getCurrency(),
|
||||
now,
|
||||
pricingLogic,
|
||||
allocationToken.isPresent() ? allocationToken : defaultToken,
|
||||
availableDomains.contains(domainName),
|
||||
recurrences.getOrDefault(domainName, null));
|
||||
responseItems.add(builder.setDomainNameIfSupported(domainName).build());
|
||||
} catch (AllocationTokenNotValidForCommandException
|
||||
| AllocationTokenNotValidForDomainException
|
||||
| AllocationTokenNotValidForRegistrarException
|
||||
| AllocationTokenNotValidForTldException
|
||||
| AllocationTokenNotInPromotionException e) {
|
||||
// Allocation token is either not an active token or it is not valid for the EPP command,
|
||||
// registrar, domain, or TLD.
|
||||
Registry registry = Registry.get(InternetDomainName.from(domainName).parent().toString());
|
||||
responseItems.add(
|
||||
builder
|
||||
.setDomainNameIfSupported(domainName)
|
||||
.setPeriod(feeCheckItem.getPeriod())
|
||||
.setCommand(
|
||||
feeCheckItem.getCommandName(),
|
||||
feeCheckItem.getPhase(),
|
||||
feeCheckItem.getSubphase())
|
||||
.setCurrencyIfSupported(registry.getCurrency())
|
||||
.setClass("token-not-supported")
|
||||
.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
return ImmutableList.of(feeCheck.createResponse(responseItems.build()));
|
||||
|
||||
@@ -89,6 +89,7 @@ import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.GracePeriod;
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.domain.fee.FeeCreateCommandExtension;
|
||||
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import google.registry.model.domain.launch.LaunchCreateExtension;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
@@ -276,7 +277,8 @@ public final class DomainCreateFlow implements TransactionalFlow {
|
||||
boolean defaultTokenUsed = false;
|
||||
if (!allocationToken.isPresent() && !registry.getDefaultPromoTokens().isEmpty()) {
|
||||
allocationToken =
|
||||
DomainFlowUtils.checkForDefaultToken(registry, command.getDomainName(), registrarId, now);
|
||||
DomainFlowUtils.checkForDefaultToken(
|
||||
registry, command.getDomainName(), CommandName.CREATE, registrarId, now);
|
||||
if (allocationToken.isPresent()) {
|
||||
defaultTokenUsed = true;
|
||||
}
|
||||
|
||||
@@ -97,6 +97,7 @@ import google.registry.model.domain.fee.BaseFee.FeeType;
|
||||
import google.registry.model.domain.fee.Credit;
|
||||
import google.registry.model.domain.fee.Fee;
|
||||
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem;
|
||||
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
|
||||
import google.registry.model.domain.fee.FeeQueryResponseExtensionItem;
|
||||
import google.registry.model.domain.fee.FeeTransformCommandExtension;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
@@ -674,8 +675,6 @@ public class DomainFlowUtils {
|
||||
String feeClass = null;
|
||||
ImmutableList<Fee> fees = ImmutableList.of();
|
||||
switch (feeRequest.getCommandName()) {
|
||||
// TODO(sarahbot@): Add check of valid EPP actions on token before passing the token to the
|
||||
// fee request.
|
||||
case CREATE:
|
||||
// Don't return a create price for reserved names.
|
||||
if (isReserved(domainName, isSunrise) && !isAvailable) {
|
||||
@@ -1204,7 +1203,12 @@ public class DomainFlowUtils {
|
||||
* token found on the TLD's default token list will be returned.
|
||||
*/
|
||||
public static Optional<AllocationToken> checkForDefaultToken(
|
||||
Registry registry, String domainName, String registrarId, DateTime now) throws EppException {
|
||||
Registry registry,
|
||||
String domainName,
|
||||
CommandName commandName,
|
||||
String registrarId,
|
||||
DateTime now)
|
||||
throws EppException {
|
||||
if (isNullOrEmpty(registry.getDefaultPromoTokens())) {
|
||||
return Optional.empty();
|
||||
}
|
||||
@@ -1222,7 +1226,7 @@ public class DomainFlowUtils {
|
||||
for (Optional<AllocationToken> token : tokenList) {
|
||||
try {
|
||||
AllocationTokenFlowUtils.validateToken(
|
||||
InternetDomainName.from(domainName), token.get(), registrarId, now);
|
||||
InternetDomainName.from(domainName), token.get(), commandName, registrarId, now);
|
||||
} catch (AssociationProhibitsOperationException | StatusProhibitsOperationException e) {
|
||||
// Allocation token was not valid for this registration, continue to check the next token in
|
||||
// the list
|
||||
|
||||
@@ -66,6 +66,7 @@ import google.registry.model.domain.GracePeriod;
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.domain.fee.BaseFee.FeeType;
|
||||
import google.registry.model.domain.fee.Fee;
|
||||
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
|
||||
import google.registry.model.domain.fee.FeeRenewCommandExtension;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
@@ -172,13 +173,13 @@ public final class DomainRenewFlow implements TransactionalFlow {
|
||||
Renew command = (Renew) resourceCommand;
|
||||
// Loads the target resource if it exists
|
||||
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
|
||||
// TODO(sarahbot@): Add check for valid EPP actions on the token
|
||||
Optional<AllocationToken> allocationToken =
|
||||
allocationTokenFlowUtils.verifyAllocationTokenIfPresent(
|
||||
existingDomain,
|
||||
Registry.get(existingDomain.getTld()),
|
||||
registrarId,
|
||||
now,
|
||||
CommandName.RENEW,
|
||||
eppInput.getSingleExtension(AllocationTokenExtension.class));
|
||||
verifyRenewAllowed(authInfo, existingDomain, command, allocationToken);
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ import google.registry.model.billing.BillingEvent.RenewalPriceBehavior;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.GracePeriod;
|
||||
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
import google.registry.model.domain.rgp.GracePeriodStatus;
|
||||
import google.registry.model.domain.token.AllocationTokenExtension;
|
||||
@@ -135,6 +136,7 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
|
||||
Registry.get(existingDomain.getTld()),
|
||||
registrarId,
|
||||
now,
|
||||
CommandName.TRANSFER,
|
||||
eppInput.getSingleExtension(AllocationTokenExtension.class));
|
||||
verifyOptionalAuthInfo(authInfo, existingDomain);
|
||||
verifyHasPendingTransfer(existingDomain);
|
||||
|
||||
@@ -57,6 +57,7 @@ import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.DomainCommand.Transfer;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
|
||||
import google.registry.model.domain.fee.FeeTransferCommandExtension;
|
||||
import google.registry.model.domain.fee.FeeTransformResponseExtension;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
@@ -173,6 +174,7 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
|
||||
Registry.get(existingDomain.getTld()),
|
||||
gainingClientId,
|
||||
now,
|
||||
CommandName.TRANSFER,
|
||||
eppInput.getSingleExtension(AllocationTokenExtension.class));
|
||||
Optional<DomainTransferRequestSuperuserExtension> superuserExtension =
|
||||
eppInput.getSingleExtension(DomainTransferRequestSuperuserExtension.class);
|
||||
|
||||
+31
-4
@@ -30,6 +30,7 @@ import google.registry.model.billing.BillingEvent.Recurring;
|
||||
import google.registry.model.billing.BillingEvent.RenewalPriceBehavior;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.DomainCommand;
|
||||
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.domain.token.AllocationToken.TokenBehavior;
|
||||
import google.registry.model.domain.token.AllocationToken.TokenStatus;
|
||||
@@ -78,7 +79,7 @@ public class AllocationTokenFlowUtils {
|
||||
ImmutableMap.Builder<InternetDomainName, String> resultsBuilder = new ImmutableMap.Builder<>();
|
||||
for (InternetDomainName domainName : domainNames) {
|
||||
try {
|
||||
validateToken(domainName, tokenEntity, registrarId, now);
|
||||
validateToken(domainName, tokenEntity, CommandName.CREATE, registrarId, now);
|
||||
validDomainNames.add(domainName);
|
||||
} catch (EppException e) {
|
||||
resultsBuilder.put(domainName, e.getMessage());
|
||||
@@ -109,11 +110,19 @@ public class AllocationTokenFlowUtils {
|
||||
* @throws EppException if the token is invalid in any way
|
||||
*/
|
||||
public static void validateToken(
|
||||
InternetDomainName domainName, AllocationToken token, String registrarId, DateTime now)
|
||||
InternetDomainName domainName,
|
||||
AllocationToken token,
|
||||
CommandName commandName,
|
||||
String registrarId,
|
||||
DateTime now)
|
||||
throws EppException {
|
||||
|
||||
// Only tokens with default behavior require validation
|
||||
if (TokenBehavior.DEFAULT.equals(token.getTokenBehavior())) {
|
||||
if (!token.getAllowedEppActions().isEmpty()
|
||||
&& !token.getAllowedEppActions().contains(commandName)) {
|
||||
throw new AllocationTokenNotValidForCommandException();
|
||||
}
|
||||
if (!token.getAllowedRegistrarIds().isEmpty()
|
||||
&& !token.getAllowedRegistrarIds().contains(registrarId)) {
|
||||
throw new AllocationTokenNotValidForRegistrarException();
|
||||
@@ -173,7 +182,12 @@ public class AllocationTokenFlowUtils {
|
||||
return Optional.empty();
|
||||
}
|
||||
AllocationToken tokenEntity = loadToken(extension.get().getAllocationToken());
|
||||
validateToken(InternetDomainName.from(command.getDomainName()), tokenEntity, registrarId, now);
|
||||
validateToken(
|
||||
InternetDomainName.from(command.getDomainName()),
|
||||
tokenEntity,
|
||||
CommandName.CREATE,
|
||||
registrarId,
|
||||
now);
|
||||
return Optional.of(
|
||||
tokenCustomLogic.validateToken(command, tokenEntity, registry, registrarId, now));
|
||||
}
|
||||
@@ -184,6 +198,7 @@ public class AllocationTokenFlowUtils {
|
||||
Registry registry,
|
||||
String registrarId,
|
||||
DateTime now,
|
||||
CommandName commandName,
|
||||
Optional<AllocationTokenExtension> extension)
|
||||
throws EppException {
|
||||
if (!extension.isPresent()) {
|
||||
@@ -191,7 +206,11 @@ public class AllocationTokenFlowUtils {
|
||||
}
|
||||
AllocationToken tokenEntity = loadToken(extension.get().getAllocationToken());
|
||||
validateToken(
|
||||
InternetDomainName.from(existingDomain.getDomainName()), tokenEntity, registrarId, now);
|
||||
InternetDomainName.from(existingDomain.getDomainName()),
|
||||
tokenEntity,
|
||||
commandName,
|
||||
registrarId,
|
||||
now);
|
||||
return Optional.of(
|
||||
tokenCustomLogic.validateToken(existingDomain, tokenEntity, registry, registrarId, now));
|
||||
}
|
||||
@@ -280,6 +299,14 @@ public class AllocationTokenFlowUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/** The allocation token is not valid for this EPP command. */
|
||||
public static class AllocationTokenNotValidForCommandException
|
||||
extends AssociationProhibitsOperationException {
|
||||
AllocationTokenNotValidForCommandException() {
|
||||
super("Allocation token not valid for the EPP command");
|
||||
}
|
||||
}
|
||||
|
||||
/** The allocation token is invalid. */
|
||||
public static class InvalidAllocationTokenException extends AuthorizationErrorException {
|
||||
InvalidAllocationTokenException() {
|
||||
|
||||
Reference in New Issue
Block a user