diff --git a/docs/flows.md b/docs/flows.md index 7198970d7..d9a5b94ef 100644 --- a/docs/flows.md +++ b/docs/flows.md @@ -314,6 +314,7 @@ An EPP flow that creates a new application for a domain resource. * Specified extension is not implemented. * 2201 * Registrar is not authorized to access this TLD. + * Registrar must be active in order to create domains or applications. * 2202 * Invalid limited registration period token. * 2302 @@ -546,6 +547,7 @@ An EPP flow that creates a new domain resource. * 2201 * Only a tool can pass a metadata extension. * Registrar is not authorized to access this TLD. + * Registrar must be active in order to create domains or applications. * 2202 * Invalid limited registration period token. * 2302 diff --git a/java/google/registry/export/SyncGroupMembersAction.java b/java/google/registry/export/SyncGroupMembersAction.java index 2d6f399e4..b81e2d730 100644 --- a/java/google/registry/export/SyncGroupMembersAction.java +++ b/java/google/registry/export/SyncGroupMembersAction.java @@ -123,7 +123,7 @@ public final class SyncGroupMembersAction implements Runnable { @Override public boolean apply(Registrar registrar) { // Only grab active registrars that require syncing and are of the correct type. - return registrar.isActive() + return registrar.isLive() && registrar.getContactsRequireSyncing() && registrar.getType() == Registrar.Type.REAL; }}) diff --git a/java/google/registry/flows/domain/DomainApplicationCreateFlow.java b/java/google/registry/flows/domain/DomainApplicationCreateFlow.java index 8c0012d86..25147280d 100644 --- a/java/google/registry/flows/domain/DomainApplicationCreateFlow.java +++ b/java/google/registry/flows/domain/DomainApplicationCreateFlow.java @@ -35,6 +35,7 @@ import static google.registry.flows.domain.DomainFlowUtils.verifyLaunchPhaseMatc import static google.registry.flows.domain.DomainFlowUtils.verifyNoCodeMarks; import static google.registry.flows.domain.DomainFlowUtils.verifyNotReserved; import static google.registry.flows.domain.DomainFlowUtils.verifyPremiumNameIsNotBlocked; +import static google.registry.flows.domain.DomainFlowUtils.verifyRegistrarIsActive; import static google.registry.flows.domain.DomainFlowUtils.verifyRegistryStateAllowsLaunchFlows; import static google.registry.flows.domain.DomainFlowUtils.verifyUnitIsYears; import static google.registry.model.EppResourceUtils.createDomainRepoId; @@ -147,6 +148,7 @@ import org.joda.time.DateTime; * @error {@link DomainFlowUtils.NotAuthorizedForTldException} * @error {@link DomainFlowUtils.PremiumNameBlockedException} * @error {@link DomainFlowUtils.RegistrantNotAllowedException} + * @error {@link DomainFlowUtils.RegistrarMustBeActiveToCreateDomainsException} * @error {@link DomainFlowTmchUtils.SignedMarksMustBeEncodedException} * @error {@link DomainFlowTmchUtils.SignedMarkCertificateExpiredException} * @error {@link DomainFlowTmchUtils.SignedMarkCertificateInvalidException} @@ -194,6 +196,7 @@ public final class DomainApplicationCreateFlow implements TransactionalFlow { customLogic.beforeValidation(); extensionManager.validate(); validateClientIsLoggedIn(clientId); + verifyRegistrarIsActive(clientId); DateTime now = ofy().getTransactionTime(); Create command = cloneAndLinkReferences((Create) resourceCommand, now); // Fail if the domain is already registered (e.g. this is a landrush application but the domain diff --git a/java/google/registry/flows/domain/DomainCreateFlow.java b/java/google/registry/flows/domain/DomainCreateFlow.java index c57de6250..21d83ddf6 100644 --- a/java/google/registry/flows/domain/DomainCreateFlow.java +++ b/java/google/registry/flows/domain/DomainCreateFlow.java @@ -35,6 +35,7 @@ import static google.registry.flows.domain.DomainFlowUtils.verifyLaunchPhaseMatc import static google.registry.flows.domain.DomainFlowUtils.verifyNoCodeMarks; import static google.registry.flows.domain.DomainFlowUtils.verifyNotReserved; import static google.registry.flows.domain.DomainFlowUtils.verifyPremiumNameIsNotBlocked; +import static google.registry.flows.domain.DomainFlowUtils.verifyRegistrarIsActive; import static google.registry.flows.domain.DomainFlowUtils.verifyUnitIsYears; import static google.registry.model.EppResourceUtils.createDomainRepoId; import static google.registry.model.eppcommon.StatusValue.SERVER_TRANSFER_PROHIBITED; @@ -155,6 +156,7 @@ import org.joda.time.Duration; * @error {@link NameserversNotSpecifiedForTldWithNameserverWhitelistException} * @error {@link DomainFlowUtils.PremiumNameBlockedException} * @error {@link DomainFlowUtils.RegistrantNotAllowedException} + * @error {@link DomainFlowUtils.RegistrarMustBeActiveToCreateDomainsException} * @error {@link DomainFlowUtils.TldDoesNotExistException} * @error {@link DomainFlowUtils.TooManyDsRecordsException} * @error {@link DomainFlowUtils.TooManyNameserversException} @@ -196,6 +198,7 @@ public class DomainCreateFlow implements TransactionalFlow { customLogic.beforeValidation(); extensionManager.validate(); validateClientIsLoggedIn(clientId); + verifyRegistrarIsActive(clientId); DateTime now = ofy().getTransactionTime(); Create command = cloneAndLinkReferences((Create) resourceCommand, now); Period period = command.getPeriod(); diff --git a/java/google/registry/flows/domain/DomainFlowUtils.java b/java/google/registry/flows/domain/DomainFlowUtils.java index 955d4618c..bc21e9f45 100644 --- a/java/google/registry/flows/domain/DomainFlowUtils.java +++ b/java/google/registry/flows/domain/DomainFlowUtils.java @@ -102,6 +102,7 @@ import google.registry.model.eppoutput.EppResponse.ResponseExtension; import google.registry.model.host.HostResource; import google.registry.model.poll.PollMessage; import google.registry.model.registrar.Registrar; +import google.registry.model.registrar.Registrar.State; import google.registry.model.registry.Registry; import google.registry.model.registry.Registry.TldState; import google.registry.model.registry.label.ReservationType; @@ -753,6 +754,19 @@ public class DomainFlowUtils { } } + /** + * Check that the registrar with the given client ID is active. + * + *
Non-active registrars are not allowed to create domain applications or domain resources.
+ */
+ static void verifyRegistrarIsActive(String clientId)
+ throws RegistrarMustBeActiveToCreateDomainsException {
+ Registrar registrar = Registrar.loadByClientIdCached(clientId).get();
+ if (registrar.getState() != State.ACTIVE) {
+ throw new RegistrarMustBeActiveToCreateDomainsException();
+ }
+ }
+
/** Check that the registry phase is not incompatible with launch extension flows. */
static void verifyRegistryStateAllowsLaunchFlows(Registry registry, DateTime now)
throws BadCommandForRegistryPhaseException {
@@ -1426,4 +1440,12 @@ public class DomainFlowUtils {
MAX_REGISTRATION_YEARS));
}
}
+
+ /** Registrar must be active in order to create domains or applications. */
+ static class RegistrarMustBeActiveToCreateDomainsException extends AuthorizationErrorException {
+ public RegistrarMustBeActiveToCreateDomainsException() {
+ super("Registrar must be active in order to create domains or applications");
+ }
+ }
+
}
diff --git a/java/google/registry/model/registrar/Registrar.java b/java/google/registry/model/registrar/Registrar.java
index f6255733c..4d27b3a59 100644
--- a/java/google/registry/model/registrar/Registrar.java
+++ b/java/google/registry/model/registrar/Registrar.java
@@ -145,10 +145,8 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
/** Represents the state of a persisted registrar entity. */
public enum State {
- /**
- * This registrar is provisioned and may have access to the testing environment, but is not yet
- * allowed to access the production environment.
- */
+
+ /** This registrar is provisioned but not yet active, and cannot log in. */
PENDING,
/** This is an active registrar account which is allowed to provision and modify domains. */
@@ -177,8 +175,8 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
/** Regex for telephone support passcode (5 digit string). */
public static final Pattern PHONE_PASSCODE_PATTERN = Pattern.compile("\\d{5}");
- /** The states in which a {@link Registrar} is considered {@link #isActive active}. */
- private static final ImmutableSet A live registrar is one that can have live domains/contacts/hosts in the registry, meaning
+ * that it is either currently active or used to be active (i.e. suspended).
+ */
+ public boolean isLive() {
+ return LIVE_STATES.contains(state);
}
/** Returns {@code true} if registrar should be visible in WHOIS results. */
- public boolean isActiveAndPubliclyVisible() {
- return ACTIVE_STATES.contains(state) && PUBLICLY_VISIBLE_TYPES.contains(type);
+ public boolean isLiveAndPubliclyVisible() {
+ return LIVE_STATES.contains(state) && PUBLICLY_VISIBLE_TYPES.contains(type);
}
public String getClientCertificate() {
diff --git a/java/google/registry/rdap/RdapActionBase.java b/java/google/registry/rdap/RdapActionBase.java
index af4a073f6..52ece11ed 100644
--- a/java/google/registry/rdap/RdapActionBase.java
+++ b/java/google/registry/rdap/RdapActionBase.java
@@ -239,7 +239,7 @@ public abstract class RdapActionBase implements Runnable {
* 2. The request did not specify a registrar to filter on, or the registrar matches.
*/
boolean shouldBeVisible(Registrar registrar) {
- return (registrar.isActiveAndPubliclyVisible()
+ return (registrar.isLiveAndPubliclyVisible()
|| (shouldIncludeDeleted()
&& getAuthorization().isAuthorizedForClientId(registrar.getClientId())))
&& (!registrarParam.isPresent() || registrarParam.get().equals(registrar.getClientId()));
diff --git a/java/google/registry/rdap/RdapEntityAction.java b/java/google/registry/rdap/RdapEntityAction.java
index 3fd51f2ed..169656794 100644
--- a/java/google/registry/rdap/RdapEntityAction.java
+++ b/java/google/registry/rdap/RdapEntityAction.java
@@ -101,7 +101,7 @@ public class RdapEntityAction extends RdapActionBase {
if (ianaIdentifier != null) {
wasValidKey = true;
Optional