diff --git a/java/google/registry/flows/ExtensionManager.java b/java/google/registry/flows/ExtensionManager.java
new file mode 100644
index 000000000..7b9a7eb07
--- /dev/null
+++ b/java/google/registry/flows/ExtensionManager.java
@@ -0,0 +1,163 @@
+// Copyright 2016 The Nomulus Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package google.registry.flows;
+
+import static com.google.common.collect.Sets.difference;
+import static com.google.common.collect.Sets.intersection;
+import static google.registry.model.domain.fee.Fee.FEE_EXTENSION_URIS;
+import static google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension.getCommandExtensionUri;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+import google.registry.flows.EppException.CommandUseErrorException;
+import google.registry.flows.EppException.SyntaxErrorException;
+import google.registry.flows.EppException.UnimplementedExtensionException;
+import google.registry.flows.FlowModule.ClientId;
+import google.registry.flows.exceptions.OnlyToolCanPassMetadataException;
+import google.registry.model.domain.metadata.MetadataExtension;
+import google.registry.model.eppinput.EppInput;
+import google.registry.model.eppinput.EppInput.CommandExtension;
+import google.registry.util.FormattingLogger;
+import java.util.Collection;
+import java.util.Set;
+import javax.inject.Inject;
+
+/**
+ * Helper to validate extensions on an EPP command.
+ *
+ *
This class checks that the declared extension URIs in an EPP request as well as the actually
+ * supplied extensions in the XML are compatible with the extensions supported by a flow.
+ */
+public final class ExtensionManager {
+
+ private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();
+
+ /** Blacklist of extension URIs that cause an error if they are used without being declared. */
+ private static final ImmutableSet UNDECLARED_URIS_BLACKLIST = FEE_EXTENSION_URIS;
+
+ private final ImmutableSet.Builder> implementedBuilder =
+ new ImmutableSet.Builder<>();
+ private final ImmutableSet.Builder> implementedGroupsBuilder =
+ new ImmutableSet.Builder<>();
+
+ @Inject EppInput eppInput;
+ @Inject SessionMetadata sessionMetadata;
+ @Inject @ClientId String clientId;
+ @Inject Class extends Flow> flowClass;
+ @Inject EppRequestSource eppRequestSource;
+ @Inject ExtensionManager() {}
+
+ @SafeVarargs
+ public final void register(Class extends CommandExtension>... extension) {
+ implementedBuilder.add(extension);
+ }
+
+ public void registerAsGroup(
+ Collection> extensions) {
+ implementedBuilder.addAll(extensions);
+ implementedGroupsBuilder.add(ImmutableSet.copyOf(extensions));
+ }
+
+ public void validate() throws EppException {
+ ImmutableSet.Builder> suppliedBuilder =
+ new ImmutableSet.Builder<>();
+ for (CommandExtension extension : eppInput.getCommandWrapper().getExtensions()) {
+ suppliedBuilder.add(extension.getClass());
+ }
+ ImmutableSet> suppliedExtensions = suppliedBuilder.build();
+ ImmutableSet> implementedExtensions =
+ implementedBuilder.build();
+ ImmutableSet> implementedExtensionGroups =
+ implementedGroupsBuilder.build();
+ checkForDuplicateExtensions(suppliedExtensions, implementedExtensionGroups);
+ checkForUndeclaredExtensions(suppliedExtensions);
+ checkForRestrictedExtensions(suppliedExtensions);
+ checkForUnimplementedExtensions(suppliedExtensions, implementedExtensions);
+ }
+
+ private void checkForDuplicateExtensions(
+ ImmutableSet> suppliedExtensions,
+ ImmutableSet> implementedExtensionGroups)
+ throws UnsupportedRepeatedExtensionException {
+ if (suppliedExtensions.size() < eppInput.getCommandWrapper().getExtensions().size()) {
+ throw new UnsupportedRepeatedExtensionException();
+ }
+ // No more than one extension in an extension group can be present.
+ for (ImmutableSet> group : implementedExtensionGroups) {
+ if (intersection(suppliedExtensions, group).size() > 1) {
+ throw new UnsupportedRepeatedExtensionException();
+ }
+ }
+ }
+
+ private void checkForUndeclaredExtensions(
+ ImmutableSet> suppliedExtensions)
+ throws UndeclaredServiceExtensionException {
+ ImmutableSet.Builder suppliedUris = new ImmutableSet.Builder<>();
+ for (Class extends CommandExtension> extension : suppliedExtensions) {
+ suppliedUris.add(getCommandExtensionUri(extension));
+ }
+ Set declaredUris = sessionMetadata.getServiceExtensionUris();
+ Set undeclaredUris = difference(suppliedUris.build(), declaredUris);
+ if (undeclaredUris.isEmpty()) {
+ return;
+ }
+ Set undeclaredUrisThatError = intersection(undeclaredUris, UNDECLARED_URIS_BLACKLIST);
+ if (!undeclaredUrisThatError.isEmpty()) {
+ throw new UndeclaredServiceExtensionException(undeclaredUrisThatError);
+ }
+ logger.infofmt(
+ "Client %s is attempting to run %s without declaring URIs %s on login",
+ clientId,
+ flowClass.getSimpleName(),
+ undeclaredUris);
+ }
+
+ private void checkForRestrictedExtensions(
+ ImmutableSet> suppliedExtensions)
+ throws OnlyToolCanPassMetadataException {
+ if (suppliedExtensions.contains(MetadataExtension.class)
+ && !eppRequestSource.equals(EppRequestSource.TOOL)) {
+ throw new OnlyToolCanPassMetadataException();
+ }
+ }
+
+ private void checkForUnimplementedExtensions(
+ ImmutableSet> suppliedExtensions,
+ ImmutableSet> implementedExtensions)
+ throws UnimplementedExtensionException {
+ Set> unimplementedExtensions =
+ difference(suppliedExtensions, implementedExtensions);
+ if (!unimplementedExtensions.isEmpty()) {
+ logger.infofmt("Unimplemented extensions: %s", unimplementedExtensions);
+ throw new UnimplementedExtensionException();
+ }
+ }
+
+ /** Unsupported repetition of an extension. */
+ static class UnsupportedRepeatedExtensionException extends SyntaxErrorException {
+ public UnsupportedRepeatedExtensionException() {
+ super("Unsupported repetition of an extension");
+ }
+ }
+
+ /** Service extension(s) must be declared at login. */
+ public static class UndeclaredServiceExtensionException extends CommandUseErrorException {
+ public UndeclaredServiceExtensionException(Set undeclaredUris) {
+ super(String.format("Service extension(s) must be declared at login: %s",
+ Joiner.on(", ").join(undeclaredUris)));
+ }
+ }
+}
diff --git a/java/google/registry/flows/Flow.java b/java/google/registry/flows/Flow.java
index 5f1ffd59b..154b32ff8 100644
--- a/java/google/registry/flows/Flow.java
+++ b/java/google/registry/flows/Flow.java
@@ -15,20 +15,14 @@
package google.registry.flows;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
import google.registry.model.eppcommon.Trid;
import google.registry.model.eppinput.EppInput;
-import google.registry.model.eppinput.EppInput.CommandExtension;
import google.registry.model.eppoutput.EppOutput;
import google.registry.model.eppoutput.EppResponse;
import google.registry.model.eppoutput.EppResponse.ResponseData;
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
import google.registry.model.eppoutput.Result;
import google.registry.model.poll.MessageQueueInfo;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
@@ -49,9 +43,6 @@ public abstract class Flow {
/** Whether this flow is being run in a superuser mode that can skip some checks. */
protected boolean isSuperuser;
- /** The collection of allowed extensions for the flow. */
- private Set> validExtensions = new HashSet<>();
-
/** Flows can override this for custom initialization. */
@SuppressWarnings("unused")
protected void initFlow() throws EppException {}
@@ -107,27 +98,6 @@ public abstract class Flow {
this.now = now;
this.isSuperuser = isSuperuser;
initFlow();
- validExtensions = ImmutableSet.copyOf(validExtensions);
return this;
}
-
- /**
- * Add an extension class as a valid extension for a flow.
- * Must be called in the init series of methods, as the validExtensions
- * becomes immutable once init is complete.
- */
- @SafeVarargs
- protected final void registerExtensions(Class extends CommandExtension>... extensions) {
- Collections.addAll(validExtensions, extensions);
- }
-
- protected final
- void registerExtensions(List> extensions) {
- validExtensions.addAll(extensions);
- }
-
- /** Get the legal command extension types for this flow. */
- protected final Set> getValidRequestExtensions() {
- return ImmutableSet.copyOf(validExtensions);
- }
}
diff --git a/java/google/registry/flows/FlowModule.java b/java/google/registry/flows/FlowModule.java
index 4202f6ede..bfe92367d 100644
--- a/java/google/registry/flows/FlowModule.java
+++ b/java/google/registry/flows/FlowModule.java
@@ -21,7 +21,6 @@ import com.google.common.base.Optional;
import com.google.common.base.Strings;
import dagger.Module;
import dagger.Provides;
-import google.registry.flows.exceptions.OnlyToolCanPassMetadataException;
import google.registry.flows.picker.FlowPicker;
import google.registry.model.domain.launch.ApplicationIdTargetExtension;
import google.registry.model.domain.metadata.MetadataExtension;
@@ -230,7 +229,6 @@ public class FlowModule {
@InputXml byte[] inputXmlBytes,
@Superuser boolean isSuperuser,
@ClientId String clientId,
- EppRequestSource eppRequestSource,
EppInput eppInput) {
HistoryEntry.Builder historyBuilder = new HistoryEntry.Builder()
.setTrid(trid)
@@ -239,9 +237,6 @@ public class FlowModule {
.setClientId(clientId);
MetadataExtension metadataExtension = eppInput.getSingleExtension(MetadataExtension.class);
if (metadataExtension != null) {
- if (!eppRequestSource.equals(EppRequestSource.TOOL)) {
- throw new EppExceptionInProviderException(new OnlyToolCanPassMetadataException());
- }
historyBuilder
.setReason(metadataExtension.getReason())
.setRequestedByRegistrar(metadataExtension.getRequestedByRegistrar());
diff --git a/java/google/registry/flows/FlowUtils.java b/java/google/registry/flows/FlowUtils.java
new file mode 100644
index 000000000..c21d926c6
--- /dev/null
+++ b/java/google/registry/flows/FlowUtils.java
@@ -0,0 +1,37 @@
+// Copyright 2016 The Nomulus Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package google.registry.flows;
+
+import google.registry.flows.EppException.CommandUseErrorException;
+
+/** Static utility functions for flows. */
+public final class FlowUtils {
+
+ private FlowUtils() {}
+
+ /** Validate that there is a logged in client. */
+ public static void validateClientIsLoggedIn(String clientId) throws EppException {
+ if (clientId.isEmpty()) {
+ throw new NotLoggedInException();
+ }
+ }
+
+ /** Registrar is not logged in. */
+ public static class NotLoggedInException extends CommandUseErrorException {
+ public NotLoggedInException() {
+ super("Registrar is not logged in.");
+ }
+ }
+}
diff --git a/java/google/registry/flows/HttpSessionMetadata.java b/java/google/registry/flows/HttpSessionMetadata.java
index eb85dc1b0..7e540be68 100644
--- a/java/google/registry/flows/HttpSessionMetadata.java
+++ b/java/google/registry/flows/HttpSessionMetadata.java
@@ -48,7 +48,7 @@ public class HttpSessionMetadata implements SessionMetadata {
@Override
@SuppressWarnings("unchecked")
public Set getServiceExtensionUris() {
- return (Set) session.getAttribute(SERVICE_EXTENSIONS);
+ return nullToEmpty((Set) session.getAttribute(SERVICE_EXTENSIONS));
}
@Override
diff --git a/java/google/registry/flows/LoggedInFlow.java b/java/google/registry/flows/LoggedInFlow.java
deleted file mode 100644
index db241f08d..000000000
--- a/java/google/registry/flows/LoggedInFlow.java
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2016 The Nomulus Authors. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package google.registry.flows;
-
-import static com.google.common.base.Verify.verifyNotNull;
-import static com.google.common.collect.Sets.difference;
-import static com.google.common.collect.Sets.intersection;
-import static google.registry.model.domain.fee.Fee.FEE_EXTENSION_URIS;
-import static google.registry.model.registry.Registries.getTlds;
-import static google.registry.util.CollectionUtils.nullToEmpty;
-
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableSet;
-import google.registry.flows.EppException.CommandUseErrorException;
-import google.registry.flows.EppException.SyntaxErrorException;
-import google.registry.flows.EppException.UnimplementedExtensionException;
-import google.registry.flows.FlowModule.ClientId;
-import google.registry.model.eppcommon.ProtocolDefinition;
-import google.registry.model.eppinput.EppInput.CommandExtension;
-import google.registry.model.registrar.Registrar;
-import google.registry.util.FormattingLogger;
-import java.util.Set;
-import javax.inject.Inject;
-
-/** A flow that requires being logged in. */
-public abstract class LoggedInFlow extends Flow {
-
- static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();
-
- /**
- * A blacklist of service extension URIs that will cause an error if they are used without being
- * declared on login.
- */
- private static final ImmutableSet UNDECLARED_URIS_BLACKLIST = FEE_EXTENSION_URIS;
-
- /**
- * The TLDs on which the logged-in registrar is allowed access domains.
- */
- private ImmutableSet allowedTlds;
-
- @Inject @ClientId String clientId;
-
- protected ImmutableSet getAllowedTlds() {
- return allowedTlds;
- }
-
- @Override
- public final void initFlow() throws EppException {
- if (clientId.isEmpty()) {
- throw new NotLoggedInException();
- }
- // Validate that the extensions in the input match what this flow expects.
- ImmutableSet> extensionClasses = FluentIterable
- .from(eppInput.getCommandWrapper().getExtensions())
- .transform(new Function>() {
- @Override
- public Class extends CommandExtension> apply(CommandExtension extension) {
- return extension.getClass();
- }})
- .toSet();
- if (extensionClasses.size() != eppInput.getCommandWrapper().getExtensions().size()) {
- throw new UnsupportedRepeatedExtensionException();
- }
- // Validate that we did not receive any undeclared extensions.
- ImmutableSet extensionUris = FluentIterable
- .from(extensionClasses)
- .transform(new Function, String>() {
- @Override
- public String apply(Class extends CommandExtension> clazz) {
- return ProtocolDefinition.ServiceExtension.getCommandExtensionUri(clazz);
- }})
- .toSet();
- Set undeclaredUris = difference(
- extensionUris, nullToEmpty(sessionMetadata.getServiceExtensionUris()));
- if (!undeclaredUris.isEmpty()) {
- Set undeclaredUrisThatError = intersection(undeclaredUris, UNDECLARED_URIS_BLACKLIST);
- if (!undeclaredUrisThatError.isEmpty()) {
- throw new UndeclaredServiceExtensionException(undeclaredUrisThatError);
- } else {
- logger.infofmt(
- "Client (%s) is attempting to run flow (%s) without declaring URIs %s on login",
- clientId, getClass().getSimpleName(), undeclaredUris);
- }
- }
- if (isSuperuser) {
- allowedTlds = getTlds();
- } else {
- Registrar registrar = verifyNotNull(
- Registrar.loadByClientId(clientId),
- "Could not load registrar %s", clientId);
- allowedTlds = registrar.getAllowedTlds();
- }
- initLoggedInFlow();
- Set> unimplementedExtensions =
- difference(extensionClasses, getValidRequestExtensions());
- if (!unimplementedExtensions.isEmpty()) {
- logger.infofmt("Unimplemented extensions: %s", unimplementedExtensions);
- throw new UnimplementedExtensionException();
- }
- }
-
- @SuppressWarnings("unused")
- protected void initLoggedInFlow() throws EppException {}
-
- /** Registrar is not logged in. */
- public static class NotLoggedInException extends CommandUseErrorException {
- public NotLoggedInException() {
- super("Registrar is not logged in.");
- }
- }
-
- /** Unsupported repetition of an extension. */
- static class UnsupportedRepeatedExtensionException extends SyntaxErrorException {
- public UnsupportedRepeatedExtensionException() {
- super("Unsupported repetition of an extension");
- }
- }
-
- /** Service extension(s) must be declared at login. */
- public static class UndeclaredServiceExtensionException extends CommandUseErrorException {
- public UndeclaredServiceExtensionException(Set undeclaredUris) {
- super(String.format("Service extension(s) must be declared at login: %s",
- Joiner.on(", ").join(undeclaredUris)));
- }
- }
-}
diff --git a/java/google/registry/flows/ResourceFlowUtils.java b/java/google/registry/flows/ResourceFlowUtils.java
index 4ae804c19..a1b7dfd97 100644
--- a/java/google/registry/flows/ResourceFlowUtils.java
+++ b/java/google/registry/flows/ResourceFlowUtils.java
@@ -65,8 +65,10 @@ import java.util.List;
import java.util.Set;
import org.joda.time.DateTime;
-/** Static utility functions for resource transfer flows. */
-public class ResourceFlowUtils {
+/** Static utility functions for resource flows. */
+public final class ResourceFlowUtils {
+
+ private ResourceFlowUtils() {}
/** Statuses for which an exDate should be added to transfer responses. */
private static final ImmutableSet ADD_EXDATE_STATUSES = Sets.immutableEnumSet(
diff --git a/java/google/registry/flows/contact/ContactCheckFlow.java b/java/google/registry/flows/contact/ContactCheckFlow.java
index 571357c4e..4897837db 100644
--- a/java/google/registry/flows/contact/ContactCheckFlow.java
+++ b/java/google/registry/flows/contact/ContactCheckFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.contact;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyTargetIdCount;
import static google.registry.model.EppResourceUtils.checkResourcesExist;
import static google.registry.model.eppoutput.Result.Code.SUCCESS;
@@ -21,7 +22,9 @@ import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import com.google.common.collect.ImmutableList;
import google.registry.config.ConfigModule.Config;
import google.registry.flows.EppException;
-import google.registry.flows.LoggedInFlow;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
+import google.registry.flows.FlowModule.ClientId;
import google.registry.model.contact.ContactCommand.Check;
import google.registry.model.contact.ContactResource;
import google.registry.model.eppinput.ResourceCommand;
@@ -39,14 +42,18 @@ import javax.inject.Inject;
*
* @error {@link google.registry.flows.exceptions.TooManyResourceChecksException}
*/
-public final class ContactCheckFlow extends LoggedInFlow {
+public final class ContactCheckFlow extends Flow {
@Inject ResourceCommand resourceCommand;
+ @Inject @ClientId String clientId;
+ @Inject ExtensionManager extensionManager;
@Inject @Config("maxChecks") int maxChecks;
@Inject ContactCheckFlow() {}
@Override
public final EppOutput run() throws EppException {
+ extensionManager.validate(); // There are no legal extensions for this flow.
+ validateClientIsLoggedIn(clientId);
List targetIds = ((Check) resourceCommand).getTargetIds();
verifyTargetIdCount(targetIds, maxChecks);
Set existingIds = checkResourcesExist(ContactResource.class, targetIds, now);
diff --git a/java/google/registry/flows/contact/ContactCreateFlow.java b/java/google/registry/flows/contact/ContactCreateFlow.java
index 9d7a7109c..14d8c8774 100644
--- a/java/google/registry/flows/contact/ContactCreateFlow.java
+++ b/java/google/registry/flows/contact/ContactCreateFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.contact;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyResourceDoesNotExist;
import static google.registry.flows.contact.ContactFlowUtils.validateAsciiPostalInfo;
import static google.registry.flows.contact.ContactFlowUtils.validateContactAgainstPolicy;
@@ -23,9 +24,10 @@ import static google.registry.model.ofy.ObjectifyService.ofy;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.model.contact.ContactCommand.Create;
import google.registry.model.contact.ContactResource;
@@ -47,21 +49,20 @@ import javax.inject.Inject;
* @error {@link ContactFlowUtils.BadInternationalizedPostalInfoException}
* @error {@link ContactFlowUtils.DeclineContactDisclosureFieldDisallowedPolicyException}
*/
-public final class ContactCreateFlow extends LoggedInFlow implements TransactionalFlow {
+public final class ContactCreateFlow extends Flow implements TransactionalFlow {
@Inject ResourceCommand resourceCommand;
+ @Inject ExtensionManager extensionManager;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
@Inject ContactCreateFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(MetadataExtension.class);
- }
-
@Override
protected final EppOutput run() throws EppException {
+ extensionManager.register(MetadataExtension.class);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
Create command = (Create) resourceCommand;
verifyResourceDoesNotExist(ContactResource.class, targetId, now);
Builder builder = new Builder();
diff --git a/java/google/registry/flows/contact/ContactDeleteFlow.java b/java/google/registry/flows/contact/ContactDeleteFlow.java
index 9ed280d3c..0e057f29b 100644
--- a/java/google/registry/flows/contact/ContactDeleteFlow.java
+++ b/java/google/registry/flows/contact/ContactDeleteFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.contact;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.failfastForAsyncDelete;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
@@ -27,9 +28,10 @@ import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.async.AsyncFlowEnqueuer;
import google.registry.model.contact.ContactResource;
@@ -55,7 +57,7 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}
* @error {@link google.registry.flows.exceptions.ResourceToDeleteIsReferencedException}
*/
-public final class ContactDeleteFlow extends LoggedInFlow implements TransactionalFlow {
+public final class ContactDeleteFlow extends Flow implements TransactionalFlow {
private static final ImmutableSet DISALLOWED_STATUSES = ImmutableSet.of(
StatusValue.LINKED,
@@ -70,20 +72,19 @@ public final class ContactDeleteFlow extends LoggedInFlow implements Transaction
return domain.getReferencedContacts();
}};
- @Inject AsyncFlowEnqueuer asyncFlowEnqueuer;
+ @Inject ExtensionManager extensionManager;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject Optional authInfo;
@Inject HistoryEntry.Builder historyBuilder;
+ @Inject AsyncFlowEnqueuer asyncFlowEnqueuer;
@Inject ContactDeleteFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(MetadataExtension.class);
- }
-
@Override
public final EppOutput run() throws EppException {
+ extensionManager.register(MetadataExtension.class);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
failfastForAsyncDelete(targetId, now, ContactResource.class, GET_REFERENCED_CONTACTS);
ContactResource existingContact = loadAndVerifyExistence(ContactResource.class, targetId, now);
verifyNoDisallowedStatuses(existingContact, DISALLOWED_STATUSES);
diff --git a/java/google/registry/flows/contact/ContactInfoFlow.java b/java/google/registry/flows/contact/ContactInfoFlow.java
index a524d2f01..efc06b677 100644
--- a/java/google/registry/flows/contact/ContactInfoFlow.java
+++ b/java/google/registry/flows/contact/ContactInfoFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.contact;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
import static google.registry.model.EppResourceUtils.cloneResourceWithLinkedStatus;
@@ -21,9 +22,10 @@ import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import com.google.common.base.Optional;
import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.model.contact.ContactResource;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppoutput.EppOutput;
@@ -39,8 +41,9 @@ import javax.inject.Inject;
*
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
*/
-public final class ContactInfoFlow extends LoggedInFlow {
+public final class ContactInfoFlow extends Flow {
+ @Inject ExtensionManager extensionManager;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject Optional authInfo;
@@ -48,6 +51,8 @@ public final class ContactInfoFlow extends LoggedInFlow {
@Override
public final EppOutput run() throws EppException {
+ extensionManager.validate(); // There are no legal extensions for this flow.
+ validateClientIsLoggedIn(clientId);
ContactResource contact = loadAndVerifyExistence(ContactResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, contact);
if (!clientId.equals(contact.getCurrentSponsorClientId()) && !authInfo.isPresent()) {
diff --git a/java/google/registry/flows/contact/ContactTransferApproveFlow.java b/java/google/registry/flows/contact/ContactTransferApproveFlow.java
index 57c73a09e..184a2b5bd 100644
--- a/java/google/registry/flows/contact/ContactTransferApproveFlow.java
+++ b/java/google/registry/flows/contact/ContactTransferApproveFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.contact;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.approvePendingTransfer;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
@@ -26,9 +27,10 @@ import static google.registry.model.ofy.ObjectifyService.ofy;
import com.google.common.base.Optional;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.exceptions.NotPendingTransferException;
import google.registry.model.contact.ContactResource;
@@ -55,26 +57,25 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.exceptions.NotPendingTransferException}
*/
-public final class ContactTransferApproveFlow extends LoggedInFlow implements TransactionalFlow {
+public final class ContactTransferApproveFlow extends Flow implements TransactionalFlow {
@Inject ResourceCommand resourceCommand;
+ @Inject ExtensionManager extensionManager;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject Optional authInfo;
@Inject HistoryEntry.Builder historyBuilder;
@Inject ContactTransferApproveFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(MetadataExtension.class);
- }
-
/**
* The logic in this flow, which handles client approvals, very closely parallels the logic in
* {@link ContactResource#cloneProjectedAtTime} which handles implicit server approvals.
*/
@Override
public final EppOutput run() throws EppException {
+ extensionManager.register(MetadataExtension.class);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
ContactResource existingContact = loadAndVerifyExistence(ContactResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, existingContact);
TransferData transferData = existingContact.getTransferData();
diff --git a/java/google/registry/flows/contact/ContactTransferCancelFlow.java b/java/google/registry/flows/contact/ContactTransferCancelFlow.java
index 46b3ee22e..b7413c3da 100644
--- a/java/google/registry/flows/contact/ContactTransferCancelFlow.java
+++ b/java/google/registry/flows/contact/ContactTransferCancelFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.contact;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.denyPendingTransfer;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
@@ -25,9 +26,10 @@ import static google.registry.model.ofy.ObjectifyService.ofy;
import com.google.common.base.Optional;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.exceptions.NotPendingTransferException;
import google.registry.flows.exceptions.NotTransferInitiatorException;
@@ -55,22 +57,21 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.exceptions.NotPendingTransferException}
* @error {@link google.registry.flows.exceptions.NotTransferInitiatorException}
*/
-public final class ContactTransferCancelFlow extends LoggedInFlow implements TransactionalFlow {
+public final class ContactTransferCancelFlow extends Flow implements TransactionalFlow {
@Inject ResourceCommand resourceCommand;
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
@Inject ContactTransferCancelFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(MetadataExtension.class);
- }
-
@Override
protected final EppOutput run() throws EppException {
+ extensionManager.register(MetadataExtension.class);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
ContactResource existingContact = loadAndVerifyExistence(ContactResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, existingContact);
TransferData transferData = existingContact.getTransferData();
diff --git a/java/google/registry/flows/contact/ContactTransferQueryFlow.java b/java/google/registry/flows/contact/ContactTransferQueryFlow.java
index e7a9d2054..30c6c1828 100644
--- a/java/google/registry/flows/contact/ContactTransferQueryFlow.java
+++ b/java/google/registry/flows/contact/ContactTransferQueryFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.contact;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
import static google.registry.flows.contact.ContactFlowUtils.createTransferResponse;
@@ -21,9 +22,10 @@ import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import com.google.common.base.Optional;
import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.exceptions.NoTransferHistoryToQueryException;
import google.registry.flows.exceptions.NotAuthorizedToViewTransferException;
import google.registry.model.contact.ContactResource;
@@ -46,8 +48,9 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.exceptions.NoTransferHistoryToQueryException}
* @error {@link google.registry.flows.exceptions.NotAuthorizedToViewTransferException}
*/
-public final class ContactTransferQueryFlow extends LoggedInFlow {
+public final class ContactTransferQueryFlow extends Flow {
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@@ -55,6 +58,8 @@ public final class ContactTransferQueryFlow extends LoggedInFlow {
@Override
public final EppOutput run() throws EppException {
+ extensionManager.validate(); // There are no legal extensions for this flow.
+ validateClientIsLoggedIn(clientId);
ContactResource contact = loadAndVerifyExistence(ContactResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, contact);
// Most of the fields on the transfer response are required, so there's no way to return valid
diff --git a/java/google/registry/flows/contact/ContactTransferRejectFlow.java b/java/google/registry/flows/contact/ContactTransferRejectFlow.java
index fedcc3e09..3ca325099 100644
--- a/java/google/registry/flows/contact/ContactTransferRejectFlow.java
+++ b/java/google/registry/flows/contact/ContactTransferRejectFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.contact;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.denyPendingTransfer;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
@@ -26,9 +27,10 @@ import static google.registry.model.ofy.ObjectifyService.ofy;
import com.google.common.base.Optional;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.exceptions.NotPendingTransferException;
import google.registry.model.contact.ContactResource;
@@ -54,21 +56,20 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
* @error {@link google.registry.flows.exceptions.NotPendingTransferException}
*/
-public final class ContactTransferRejectFlow extends LoggedInFlow implements TransactionalFlow {
+public final class ContactTransferRejectFlow extends Flow implements TransactionalFlow {
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
@Inject ContactTransferRejectFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(MetadataExtension.class);
- }
-
@Override
protected final EppOutput run() throws EppException {
+ extensionManager.register(MetadataExtension.class);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
ContactResource existingContact = loadAndVerifyExistence(ContactResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, existingContact);
TransferData transferData = existingContact.getTransferData();
diff --git a/java/google/registry/flows/contact/ContactTransferRequestFlow.java b/java/google/registry/flows/contact/ContactTransferRequestFlow.java
index d5cad7021..53b2bac50 100644
--- a/java/google/registry/flows/contact/ContactTransferRequestFlow.java
+++ b/java/google/registry/flows/contact/ContactTransferRequestFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.contact;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
import static google.registry.flows.ResourceFlowUtils.verifyRequiredAuthInfoForResourceTransfer;
@@ -28,9 +29,10 @@ import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import google.registry.config.ConfigModule.Config;
import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.exceptions.AlreadyPendingTransferException;
import google.registry.flows.exceptions.ObjectAlreadySponsoredException;
@@ -62,13 +64,14 @@ import org.joda.time.Duration;
* @error {@link google.registry.flows.exceptions.MissingTransferRequestAuthInfoException}
* @error {@link google.registry.flows.exceptions.ObjectAlreadySponsoredException}
*/
-public final class ContactTransferRequestFlow extends LoggedInFlow implements TransactionalFlow {
+public final class ContactTransferRequestFlow extends Flow implements TransactionalFlow {
private static final ImmutableSet DISALLOWED_STATUSES = ImmutableSet.of(
StatusValue.CLIENT_TRANSFER_PROHIBITED,
StatusValue.PENDING_DELETE,
StatusValue.SERVER_TRANSFER_PROHIBITED);
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String gainingClientId;
@Inject @TargetId String targetId;
@@ -76,13 +79,11 @@ public final class ContactTransferRequestFlow extends LoggedInFlow implements Tr
@Inject HistoryEntry.Builder historyBuilder;
@Inject ContactTransferRequestFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(MetadataExtension.class);
- }
-
@Override
protected final EppOutput run() throws EppException {
+ extensionManager.register(MetadataExtension.class);
+ extensionManager.validate();
+ validateClientIsLoggedIn(gainingClientId);
ContactResource existingContact = loadAndVerifyExistence(ContactResource.class, targetId, now);
verifyRequiredAuthInfoForResourceTransfer(authInfo, existingContact);
// Verify that the resource does not already have a pending transfer.
diff --git a/java/google/registry/flows/contact/ContactUpdateFlow.java b/java/google/registry/flows/contact/ContactUpdateFlow.java
index 52e915dcc..46ac20e41 100644
--- a/java/google/registry/flows/contact/ContactUpdateFlow.java
+++ b/java/google/registry/flows/contact/ContactUpdateFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.contact;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
@@ -28,9 +29,10 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.exceptions.AddRemoveSameValueEppException;
import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException;
@@ -59,7 +61,7 @@ import javax.inject.Inject;
* @error {@link ContactFlowUtils.BadInternationalizedPostalInfoException}
* @error {@link ContactFlowUtils.DeclineContactDisclosureFieldDisallowedPolicyException}
*/
-public final class ContactUpdateFlow extends LoggedInFlow implements TransactionalFlow {
+public final class ContactUpdateFlow extends Flow implements TransactionalFlow {
/**
* Note that CLIENT_UPDATE_PROHIBITED is intentionally not in this list. This is because it
@@ -71,19 +73,18 @@ public final class ContactUpdateFlow extends LoggedInFlow implements Transaction
StatusValue.SERVER_UPDATE_PROHIBITED);
@Inject ResourceCommand resourceCommand;
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
@Inject ContactUpdateFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(MetadataExtension.class);
- }
-
@Override
public final EppOutput run() throws EppException {
+ extensionManager.register(MetadataExtension.class);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
Update command = (Update) resourceCommand;
ContactResource existingContact = loadAndVerifyExistence(ContactResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, existingContact);
diff --git a/java/google/registry/flows/domain/ClaimsCheckFlow.java b/java/google/registry/flows/domain/ClaimsCheckFlow.java
index 66aea6fbe..cd02db10b 100644
--- a/java/google/registry/flows/domain/ClaimsCheckFlow.java
+++ b/java/google/registry/flows/domain/ClaimsCheckFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.domain;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyTargetIdCount;
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
import static google.registry.flows.domain.DomainFlowUtils.validateDomainName;
@@ -29,7 +30,9 @@ import com.google.common.net.InternetDomainName;
import google.registry.config.ConfigModule.Config;
import google.registry.flows.EppException;
import google.registry.flows.EppException.CommandUseErrorException;
-import google.registry.flows.LoggedInFlow;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
+import google.registry.flows.FlowModule.ClientId;
import google.registry.model.domain.DomainCommand.Check;
import google.registry.model.domain.launch.LaunchCheckExtension;
import google.registry.model.domain.launch.LaunchCheckResponseExtension;
@@ -55,19 +58,19 @@ import javax.inject.Inject;
* @error {@link DomainFlowUtils.TldDoesNotExistException}
* @error {@link ClaimsCheckNotAllowedInSunrise}
*/
-public final class ClaimsCheckFlow extends LoggedInFlow {
+public final class ClaimsCheckFlow extends Flow {
+ @Inject ExtensionManager extensionManager;
@Inject ResourceCommand resourceCommand;
+ @Inject @ClientId String clientId;
@Inject @Config("maxChecks") int maxChecks;
@Inject ClaimsCheckFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(LaunchCheckExtension.class);
- }
-
@Override
public EppOutput run() throws EppException {
+ extensionManager.register(LaunchCheckExtension.class);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
List targetIds = ((Check) resourceCommand).getTargetIds();
verifyTargetIdCount(targetIds, maxChecks);
Set seenTlds = new HashSet<>();
@@ -78,7 +81,7 @@ public final class ClaimsCheckFlow extends LoggedInFlow {
String tld = domainName.parent().toString();
// Only validate access to a TLD the first time it is encountered.
if (seenTlds.add(tld)) {
- checkAllowedAccessToTld(getAllowedTlds(), tld);
+ checkAllowedAccessToTld(clientId, tld);
Registry registry = Registry.get(tld);
if (!isSuperuser) {
verifyNotInPredelegation(registry, now);
diff --git a/java/google/registry/flows/domain/DomainAllocateFlow.java b/java/google/registry/flows/domain/DomainAllocateFlow.java
index 497ad03fe..b7647ab87 100644
--- a/java/google/registry/flows/domain/DomainAllocateFlow.java
+++ b/java/google/registry/flows/domain/DomainAllocateFlow.java
@@ -16,6 +16,7 @@ package google.registry.flows.domain;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.getOnlyElement;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyResourceDoesNotExist;
import static google.registry.flows.domain.DomainFlowUtils.cloneAndLinkReferences;
import static google.registry.flows.domain.DomainFlowUtils.createFeeCreateResponse;
@@ -46,9 +47,10 @@ import google.registry.flows.EppException;
import google.registry.flows.EppException.AuthorizationErrorException;
import google.registry.flows.EppException.ObjectDoesNotExistException;
import google.registry.flows.EppException.StatusProhibitsOperationException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.domain.TldSpecificLogicProxy.EppCommandOperations;
import google.registry.model.ImmutableObject;
@@ -95,13 +97,14 @@ import org.joda.time.DateTime;
* @error {@link DomainAllocateFlow.MissingApplicationException}
* @error {@link DomainAllocateFlow.OnlySuperuserCanAllocateException}
*/
-public class DomainAllocateFlow extends LoggedInFlow implements TransactionalFlow {
+public class DomainAllocateFlow extends Flow implements TransactionalFlow {
private static final String COLLISION_MESSAGE =
"Domain on the name collision list was allocated. But by policy, the domain will not be "
+ "delegated. Please visit https://www.icann.org/namecollision for more information on name "
+ "collision.";
+ @Inject ExtensionManager extensionManager;
@Inject AuthInfo authInfo;
@Inject ResourceCommand resourceCommand;
@Inject @ClientId String clientId;
@@ -110,17 +113,15 @@ public class DomainAllocateFlow extends LoggedInFlow implements TransactionalFlo
@Inject DomainAllocateFlow() {}
@Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(FEE_CREATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
- registerExtensions(
+ public final EppOutput run() throws EppException {
+ extensionManager.register(
SecDnsCreateExtension.class,
FlagsCreateCommandExtension.class,
MetadataExtension.class,
AllocateCreateExtension.class);
- }
-
- @Override
- public final EppOutput run() throws EppException {
+ extensionManager.registerAsGroup(FEE_CREATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
verifyIsSuperuser();
Create command = cloneAndLinkReferences((Create) resourceCommand, now);
failfastForCreate(targetId, now);
diff --git a/java/google/registry/flows/domain/DomainApplicationCreateFlow.java b/java/google/registry/flows/domain/DomainApplicationCreateFlow.java
index 4e68a2851..53ae5d420 100644
--- a/java/google/registry/flows/domain/DomainApplicationCreateFlow.java
+++ b/java/google/registry/flows/domain/DomainApplicationCreateFlow.java
@@ -15,6 +15,7 @@
package google.registry.flows.domain;
import static com.google.common.collect.Iterables.getOnlyElement;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyResourceDoesNotExist;
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
import static google.registry.flows.domain.DomainFlowUtils.cloneAndLinkReferences;
@@ -54,9 +55,10 @@ import google.registry.flows.EppException;
import google.registry.flows.EppException.CommandUseErrorException;
import google.registry.flows.EppException.ObjectAlreadyExistsException;
import google.registry.flows.EppException.RequiredParameterMissingException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.domain.TldSpecificLogicProxy.EppCommandOperations;
import google.registry.model.ImmutableObject;
@@ -151,8 +153,9 @@ import javax.inject.Inject;
* @error {@link DomainFlowUtils.UnsupportedFeeAttributeException}
* @error {@link DomainFlowUtils.UnsupportedMarkTypeException}
*/
-public final class DomainApplicationCreateFlow extends LoggedInFlow implements TransactionalFlow {
+public final class DomainApplicationCreateFlow extends Flow implements TransactionalFlow {
+ @Inject ExtensionManager extensionManager;
@Inject AuthInfo authInfo;
@Inject ResourceCommand resourceCommand;
@Inject @ClientId String clientId;
@@ -161,17 +164,15 @@ public final class DomainApplicationCreateFlow extends LoggedInFlow implements T
@Inject DomainApplicationCreateFlow() {}
@Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(FEE_CREATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
- registerExtensions(
+ public final EppOutput run() throws EppException {
+ extensionManager.register(
SecDnsCreateExtension.class,
FlagsCreateCommandExtension.class,
MetadataExtension.class,
LaunchCreateExtension.class);
- }
-
- @Override
- public final EppOutput run() throws EppException {
+ extensionManager.registerAsGroup(FEE_CREATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
Create command = cloneAndLinkReferences((Create) resourceCommand, now);
failfastForCreate(targetId, now);
// Fail if the domain is already registered (e.g. this is a landrush application but the domain
@@ -182,7 +183,7 @@ public final class DomainApplicationCreateFlow extends LoggedInFlow implements T
InternetDomainName domainName = validateDomainName(targetId);
String idnTableName = validateDomainNameWithIdnTables(domainName);
String tld = domainName.parent().toString();
- checkAllowedAccessToTld(getAllowedTlds(), tld);
+ checkAllowedAccessToTld(clientId, tld);
Registry registry = Registry.get(tld);
EppCommandOperations commandOperations = TldSpecificLogicProxy.getCreatePrice(
registry, targetId, clientId, now, command.getPeriod().getValue(), eppInput);
diff --git a/java/google/registry/flows/domain/DomainApplicationDeleteFlow.java b/java/google/registry/flows/domain/DomainApplicationDeleteFlow.java
index 3a4edad5a..6bb5949ef 100644
--- a/java/google/registry/flows/domain/DomainApplicationDeleteFlow.java
+++ b/java/google/registry/flows/domain/DomainApplicationDeleteFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.domain;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.handlePendingTransferOnDelete;
import static google.registry.flows.ResourceFlowUtils.prepareDeletedResourceAsBuilder;
import static google.registry.flows.ResourceFlowUtils.updateForeignKeyIndexDeletionTime;
@@ -32,10 +33,11 @@ import com.google.common.base.Optional;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.flows.EppException.StatusProhibitsOperationException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ApplicationId;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.model.domain.DomainApplication;
import google.registry.model.domain.launch.LaunchDeleteExtension;
@@ -60,8 +62,9 @@ import javax.inject.Inject;
* @error {@link DomainFlowUtils.LaunchPhaseMismatchException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
*/
-public final class DomainApplicationDeleteFlow extends LoggedInFlow implements TransactionalFlow {
+public final class DomainApplicationDeleteFlow extends Flow implements TransactionalFlow {
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@@ -69,20 +72,17 @@ public final class DomainApplicationDeleteFlow extends LoggedInFlow implements T
@Inject HistoryEntry.Builder historyBuilder;
@Inject DomainApplicationDeleteFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(MetadataExtension.class);
- registerExtensions(LaunchDeleteExtension.class);
- }
-
@Override
public final EppOutput run() throws EppException {
+ extensionManager.register(MetadataExtension.class, LaunchDeleteExtension.class);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
DomainApplication existingApplication = verifyExistence(
DomainApplication.class, applicationId, loadDomainApplication(applicationId, now));
verifyApplicationDomainMatchesTargetId(existingApplication, targetId);
verifyOptionalAuthInfoForResource(authInfo, existingApplication);
String tld = existingApplication.getTld();
- checkAllowedAccessToTld(getAllowedTlds(), tld);
+ checkAllowedAccessToTld(clientId, tld);
if (!isSuperuser) {
Registry registry = Registry.get(tld);
verifyRegistryStateAllowsLaunchFlows(registry, now);
diff --git a/java/google/registry/flows/domain/DomainApplicationInfoFlow.java b/java/google/registry/flows/domain/DomainApplicationInfoFlow.java
index 2d7449ffb..79601f601 100644
--- a/java/google/registry/flows/domain/DomainApplicationInfoFlow.java
+++ b/java/google/registry/flows/domain/DomainApplicationInfoFlow.java
@@ -15,6 +15,7 @@
package google.registry.flows.domain;
import static google.registry.flows.EppXmlTransformer.unmarshal;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
@@ -28,10 +29,11 @@ import com.google.common.collect.ImmutableList;
import google.registry.flows.EppException;
import google.registry.flows.EppException.ParameterValuePolicyErrorException;
import google.registry.flows.EppException.RequiredParameterMissingException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ApplicationId;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.model.domain.DomainApplication;
import google.registry.model.domain.DomainCommand.Info;
import google.registry.model.domain.launch.LaunchInfoExtension;
@@ -57,22 +59,21 @@ import javax.inject.Inject;
* @error {@link DomainApplicationInfoFlow.ApplicationLaunchPhaseMismatchException}
* @error {@link MissingApplicationIdException}
*/
-public final class DomainApplicationInfoFlow extends LoggedInFlow {
+public final class DomainApplicationInfoFlow extends Flow {
@Inject ResourceCommand resourceCommand;
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject @ApplicationId String applicationId;
@Inject DomainApplicationInfoFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(LaunchInfoExtension.class);
- }
-
@Override
public final EppOutput run() throws EppException {
+ extensionManager.register(LaunchInfoExtension.class);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
if (applicationId.isEmpty()) {
throw new MissingApplicationIdException();
}
diff --git a/java/google/registry/flows/domain/DomainApplicationUpdateFlow.java b/java/google/registry/flows/domain/DomainApplicationUpdateFlow.java
index ddbc12d4b..b42061681 100644
--- a/java/google/registry/flows/domain/DomainApplicationUpdateFlow.java
+++ b/java/google/registry/flows/domain/DomainApplicationUpdateFlow.java
@@ -16,6 +16,7 @@ package google.registry.flows.domain;
import static com.google.common.base.CaseFormat.LOWER_CAMEL;
import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
@@ -45,10 +46,11 @@ import com.google.common.collect.Sets;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.flows.EppException.StatusProhibitsOperationException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ApplicationId;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.exceptions.AddRemoveSameValueEppException;
import google.registry.model.ImmutableObject;
@@ -97,7 +99,7 @@ import javax.inject.Inject;
* @error {@link DomainFlowUtils.UrgentAttributeNotSupportedException}
* @error {@link DomainApplicationUpdateFlow.ApplicationStatusProhibitsUpdateException}
*/
-public class DomainApplicationUpdateFlow extends LoggedInFlow implements TransactionalFlow {
+public class DomainApplicationUpdateFlow extends Flow implements TransactionalFlow {
/**
* Note that CLIENT_UPDATE_PROHIBITED is intentionally not in this list. This is because it
@@ -116,6 +118,7 @@ public class DomainApplicationUpdateFlow extends LoggedInFlow implements Transac
ApplicationStatus.ALLOCATED);
@Inject ResourceCommand resourceCommand;
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@@ -123,15 +126,15 @@ public class DomainApplicationUpdateFlow extends LoggedInFlow implements Transac
@Inject HistoryEntry.Builder historyBuilder;
@Inject DomainApplicationUpdateFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(FEE_UPDATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
- registerExtensions(
- MetadataExtension.class, LaunchUpdateExtension.class, SecDnsUpdateExtension.class);
- }
-
@Override
public final EppOutput run() throws EppException {
+ extensionManager.register(
+ LaunchUpdateExtension.class,
+ MetadataExtension.class,
+ SecDnsUpdateExtension.class);
+ extensionManager.registerAsGroup(FEE_UPDATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
Update command = cloneAndLinkReferences((Update) resourceCommand, now);
DomainApplication existingApplication = verifyExistence(
DomainApplication.class, applicationId, loadDomainApplication(applicationId, now));
@@ -154,7 +157,7 @@ public class DomainApplicationUpdateFlow extends LoggedInFlow implements Transac
verifyStatusChangesAreClientSettable(command);
}
String tld = existingApplication.getTld();
- checkAllowedAccessToTld(getAllowedTlds(), tld);
+ checkAllowedAccessToTld(clientId, tld);
if (UPDATE_DISALLOWED_APPLICATION_STATUSES
.contains(existingApplication.getApplicationStatus())) {
throw new ApplicationStatusProhibitsUpdateException(
diff --git a/java/google/registry/flows/domain/DomainCheckFlow.java b/java/google/registry/flows/domain/DomainCheckFlow.java
index ac4daddb1..d8909eb7a 100644
--- a/java/google/registry/flows/domain/DomainCheckFlow.java
+++ b/java/google/registry/flows/domain/DomainCheckFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.domain;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyTargetIdCount;
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
import static google.registry.flows.domain.DomainFlowUtils.getReservationType;
@@ -40,8 +41,9 @@ import com.google.common.net.InternetDomainName;
import google.registry.config.ConfigModule.Config;
import google.registry.flows.EppException;
import google.registry.flows.EppException.ParameterValuePolicyErrorException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
-import google.registry.flows.LoggedInFlow;
import google.registry.model.domain.DomainApplication;
import google.registry.model.domain.DomainCommand.Check;
import google.registry.model.domain.DomainResource;
@@ -88,7 +90,7 @@ import javax.inject.Inject;
* @error {@link DomainFlowUtils.UnknownFeeCommandException}
* @error {@link OnlyCheckedNamesCanBeFeeCheckedException}
*/
-public final class DomainCheckFlow extends LoggedInFlow {
+public final class DomainCheckFlow extends Flow {
/**
* The TLD states during which we want to report a domain with pending applications as
@@ -98,18 +100,17 @@ public final class DomainCheckFlow extends LoggedInFlow {
Sets.immutableEnumSet(TldState.GENERAL_AVAILABILITY, TldState.QUIET_PERIOD);
@Inject ResourceCommand resourceCommand;
+ @Inject ExtensionManager extensionManager;
@Inject @ClientId String clientId;
@Inject @Config("maxChecks") int maxChecks;
@Inject DomainCheckFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(LaunchCheckExtension.class);
- registerExtensions(FEE_CHECK_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
- }
-
@Override
public EppOutput run() throws EppException {
+ extensionManager.register(LaunchCheckExtension.class);
+ extensionManager.registerAsGroup(FEE_CHECK_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
List targetIds = ((Check) resourceCommand).getTargetIds();
verifyTargetIdCount(targetIds, maxChecks);
ImmutableMap.Builder domains = new ImmutableMap.Builder<>();
@@ -122,7 +123,7 @@ public final class DomainCheckFlow extends LoggedInFlow {
domains.put(targetId, domainName);
String tld = domainName.parent().toString();
if (seenTlds.add(tld)) {
- checkAllowedAccessToTld(getAllowedTlds(), tld);
+ checkAllowedAccessToTld(clientId, tld);
if (!isSuperuser) {
verifyNotInPredelegation(Registry.get(tld), now);
}
diff --git a/java/google/registry/flows/domain/DomainCreateFlow.java b/java/google/registry/flows/domain/DomainCreateFlow.java
index 92a421109..54f6cc5ff 100644
--- a/java/google/registry/flows/domain/DomainCreateFlow.java
+++ b/java/google/registry/flows/domain/DomainCreateFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.domain;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyResourceDoesNotExist;
import static google.registry.flows.domain.DomainFlowUtils.checkAllowedAccessToTld;
import static google.registry.flows.domain.DomainFlowUtils.cloneAndLinkReferences;
@@ -52,9 +53,10 @@ import google.registry.dns.DnsQueue;
import google.registry.flows.EppException;
import google.registry.flows.EppException.CommandUseErrorException;
import google.registry.flows.EppException.StatusProhibitsOperationException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.domain.TldSpecificLogicProxy.EppCommandOperations;
import google.registry.model.ImmutableObject;
@@ -99,7 +101,7 @@ import org.joda.time.DateTime;
* @error {@link google.registry.flows.exceptions.OnlyToolCanPassMetadataException}
* @error {@link google.registry.flows.exceptions.ResourceAlreadyExistsException}
* @error {@link google.registry.flows.EppException.UnimplementedExtensionException}
- * @error {@link google.registry.flows.LoggedInFlow.UndeclaredServiceExtensionException}
+ * @error {@link google.registry.flows.ExtensionManager.UndeclaredServiceExtensionException}
* @error {@link google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException}
* @error {@link DomainCreateFlow.SignedMarksNotAcceptedInCurrentPhaseException}
* @error {@link DomainFlowUtils.AcceptedTooLongAgoException}
@@ -147,11 +149,12 @@ import org.joda.time.DateTime;
* @error {@link DomainCreateFlow.NoGeneralRegistrationsInCurrentPhaseException}
*/
-public class DomainCreateFlow extends LoggedInFlow implements TransactionalFlow {
+public class DomainCreateFlow extends Flow implements TransactionalFlow {
private static final Set QLP_SMD_ALLOWED_STATES =
Sets.immutableEnumSet(TldState.SUNRISE, TldState.SUNRUSH);
+ @Inject ExtensionManager extensionManager;
@Inject AuthInfo authInfo;
@Inject ResourceCommand resourceCommand;
@Inject @ClientId String clientId;
@@ -160,17 +163,15 @@ public class DomainCreateFlow extends LoggedInFlow implements TransactionalFlow
@Inject DomainCreateFlow() {}
@Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(FEE_CREATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
- registerExtensions(
+ public final EppOutput run() throws EppException {
+ extensionManager.register(
SecDnsCreateExtension.class,
FlagsCreateCommandExtension.class,
MetadataExtension.class,
LaunchCreateExtension.class);
- }
-
- @Override
- public final EppOutput run() throws EppException {
+ extensionManager.registerAsGroup(FEE_CREATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
Create command = cloneAndLinkReferences((Create) resourceCommand, now);
Period period = command.getPeriod();
verifyUnitIsYears(period);
@@ -204,7 +205,7 @@ public class DomainCreateFlow extends LoggedInFlow implements TransactionalFlow
// notice without specifying a claims key, ignore the registry phase, and override blocks on
// registering premium domains.
if (!isSuperuser) {
- checkAllowedAccessToTld(getAllowedTlds(), registry.getTldStr());
+ checkAllowedAccessToTld(clientId, registry.getTldStr());
if (launchCreate != null) {
verifyLaunchPhaseMatchesRegistryPhase(registry, launchCreate, now);
}
diff --git a/java/google/registry/flows/domain/DomainDeleteFlow.java b/java/google/registry/flows/domain/DomainDeleteFlow.java
index de0a531e9..9435bf43a 100644
--- a/java/google/registry/flows/domain/DomainDeleteFlow.java
+++ b/java/google/registry/flows/domain/DomainDeleteFlow.java
@@ -15,6 +15,7 @@
package google.registry.flows.domain;
import static com.google.common.base.Preconditions.checkNotNull;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.handlePendingTransferOnDelete;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.prepareDeletedResourceAsBuilder;
@@ -38,9 +39,10 @@ import com.googlecode.objectify.Key;
import google.registry.dns.DnsQueue;
import google.registry.flows.EppException;
import google.registry.flows.EppException.AssociationProhibitsOperationException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent;
@@ -55,7 +57,7 @@ import google.registry.model.domain.fee11.FeeDeleteResponseExtensionV11;
import google.registry.model.domain.fee12.FeeDeleteResponseExtensionV12;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.domain.rgp.GracePeriodStatus;
-import google.registry.model.domain.secdns.SecDnsUpdateExtension;
+import google.registry.model.domain.secdns.SecDnsCreateExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension;
import google.registry.model.eppcommon.StatusValue;
@@ -82,7 +84,7 @@ import org.joda.time.DateTime;
* @error {@link DomainFlowUtils.BadCommandForRegistryPhaseException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
*/
-public final class DomainDeleteFlow extends LoggedInFlow implements TransactionalFlow {
+public final class DomainDeleteFlow extends Flow implements TransactionalFlow {
private static final ImmutableSet DISALLOWED_STATUSES = ImmutableSet.of(
StatusValue.LINKED,
@@ -90,6 +92,7 @@ public final class DomainDeleteFlow extends LoggedInFlow implements Transactiona
StatusValue.PENDING_DELETE,
StatusValue.SERVER_DELETE_PROHIBITED);
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@@ -97,15 +100,11 @@ public final class DomainDeleteFlow extends LoggedInFlow implements Transactiona
@Inject DnsQueue dnsQueue;
@Inject DomainDeleteFlow() {}
- @Override
- @SuppressWarnings("unchecked")
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(MetadataExtension.class);
- registerExtensions(SecDnsUpdateExtension.class);
- }
-
@Override
public final EppOutput run() throws EppException {
+ extensionManager.register(MetadataExtension.class, SecDnsCreateExtension.class);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
// Loads the target resource if it exists
DomainResource existingDomain = loadAndVerifyExistence(DomainResource.class, targetId, now);
Registry registry = Registry.get(existingDomain.getTld());
@@ -165,7 +164,7 @@ public final class DomainDeleteFlow extends LoggedInFlow implements Transactiona
verifyResourceOwnership(clientId, existingDomain);
verifyNotInPredelegation(registry, now);
}
- checkAllowedAccessToTld(getAllowedTlds(), registry.getTld().toString());
+ checkAllowedAccessToTld(clientId, registry.getTld().toString());
if (!existingDomain.getSubordinateHosts().isEmpty()) {
throw new DomainToDeleteHasHostsException();
}
diff --git a/java/google/registry/flows/domain/DomainFlowUtils.java b/java/google/registry/flows/domain/DomainFlowUtils.java
index e565fe11d..c1ea80dfa 100644
--- a/java/google/registry/flows/domain/DomainFlowUtils.java
+++ b/java/google/registry/flows/domain/DomainFlowUtils.java
@@ -247,9 +247,9 @@ public class DomainFlowUtils {
}
/** Check if the registrar running the flow has access to the TLD in question. */
- public static void checkAllowedAccessToTld(Set allowedTlds, String tld)
+ public static void checkAllowedAccessToTld(String clientId, String tld)
throws EppException {
- if (!allowedTlds.contains(tld)) {
+ if (!Registrar.loadByClientId(clientId).getAllowedTlds().contains(tld)) {
throw new DomainFlowUtils.NotAuthorizedForTldException(tld);
}
}
diff --git a/java/google/registry/flows/domain/DomainInfoFlow.java b/java/google/registry/flows/domain/DomainInfoFlow.java
index f439b74ca..f04b6b6b5 100644
--- a/java/google/registry/flows/domain/DomainInfoFlow.java
+++ b/java/google/registry/flows/domain/DomainInfoFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.domain;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
import static google.registry.flows.domain.DomainFlowUtils.addSecDnsExtensionIfPresent;
@@ -26,9 +27,10 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.net.InternetDomainName;
import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.model.domain.DomainCommand.Info;
import google.registry.model.domain.DomainCommand.Info.HostsRequest;
import google.registry.model.domain.DomainResource;
@@ -59,21 +61,20 @@ import javax.inject.Inject;
* @error {@link DomainFlowUtils.FeeChecksDontSupportPhasesException}
* @error {@link DomainFlowUtils.RestoresAreAlwaysForOneYearException}
*/
-public final class DomainInfoFlow extends LoggedInFlow {
+public final class DomainInfoFlow extends Flow {
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject ResourceCommand resourceCommand;
@Inject DomainInfoFlow() {}
- @Override
- protected void initLoggedInFlow() throws EppException {
- registerExtensions(FeeInfoCommandExtensionV06.class);
- }
-
@Override
public final EppOutput run() throws EppException {
+ extensionManager.register(FeeInfoCommandExtensionV06.class);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
DomainResource domain = loadAndVerifyExistence(DomainResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, domain);
return createOutput(
diff --git a/java/google/registry/flows/domain/DomainRenewFlow.java b/java/google/registry/flows/domain/DomainRenewFlow.java
index 47bacfacb..10ccd2666 100644
--- a/java/google/registry/flows/domain/DomainRenewFlow.java
+++ b/java/google/registry/flows/domain/DomainRenewFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.domain;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
@@ -38,9 +39,10 @@ import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.flows.EppException.ObjectPendingTransferException;
import google.registry.flows.EppException.ParameterValueRangeErrorException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.domain.TldSpecificLogicProxy.EppCommandOperations;
import google.registry.model.billing.BillingEvent;
@@ -95,7 +97,7 @@ import org.joda.time.DateTime;
* @error {@link DomainRenewFlow.ExceedsMaxRegistrationYearsException}
* @error {@link DomainRenewFlow.IncorrectCurrentExpirationDateException}
*/
-public final class DomainRenewFlow extends LoggedInFlow implements TransactionalFlow {
+public final class DomainRenewFlow extends Flow implements TransactionalFlow {
private static final ImmutableSet RENEW_DISALLOWED_STATUSES = ImmutableSet.of(
StatusValue.CLIENT_RENEW_PROHIBITED,
@@ -103,20 +105,19 @@ public final class DomainRenewFlow extends LoggedInFlow implements Transactional
StatusValue.SERVER_RENEW_PROHIBITED);
@Inject ResourceCommand resourceCommand;
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
@Inject DomainRenewFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(MetadataExtension.class);
- registerExtensions(FEE_RENEW_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
- }
-
@Override
public final EppOutput run() throws EppException {
+ extensionManager.register(MetadataExtension.class);
+ extensionManager.registerAsGroup(FEE_RENEW_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
Renew command = (Renew) resourceCommand;
// Loads the target resource if it exists
DomainResource existingDomain = loadAndVerifyExistence(DomainResource.class, targetId, now);
@@ -185,7 +186,7 @@ public final class DomainRenewFlow extends LoggedInFlow implements Transactional
if (!isSuperuser) {
verifyResourceOwnership(clientId, existingDomain);
}
- checkAllowedAccessToTld(getAllowedTlds(), existingDomain.getTld());
+ checkAllowedAccessToTld(clientId, existingDomain.getTld());
// Verify that the resource does not have a pending transfer on it.
if (existingDomain.getTransferData().getTransferStatus() == TransferStatus.PENDING) {
throw new DomainHasPendingTransferException(targetId);
diff --git a/java/google/registry/flows/domain/DomainRestoreRequestFlow.java b/java/google/registry/flows/domain/DomainRestoreRequestFlow.java
index c875b777e..6b02e8d4b 100644
--- a/java/google/registry/flows/domain/DomainRestoreRequestFlow.java
+++ b/java/google/registry/flows/domain/DomainRestoreRequestFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.domain;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.updateForeignKeyIndexDeletionTime;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
@@ -38,9 +39,10 @@ import google.registry.dns.DnsQueue;
import google.registry.flows.EppException;
import google.registry.flows.EppException.CommandUseErrorException;
import google.registry.flows.EppException.StatusProhibitsOperationException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.domain.TldSpecificLogicProxy.EppCommandOperations;
import google.registry.model.ImmutableObject;
@@ -101,9 +103,10 @@ import org.joda.time.DateTime;
* @error {@link DomainRestoreRequestFlow.DomainNotEligibleForRestoreException}
* @error {@link DomainRestoreRequestFlow.RestoreCommandIncludesChangesException}
*/
-public final class DomainRestoreRequestFlow extends LoggedInFlow implements TransactionalFlow {
+public final class DomainRestoreRequestFlow extends Flow implements TransactionalFlow {
@Inject ResourceCommand resourceCommand;
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@@ -111,14 +114,12 @@ public final class DomainRestoreRequestFlow extends LoggedInFlow implements Tran
@Inject DnsQueue dnsQueue;
@Inject DomainRestoreRequestFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(MetadataExtension.class, RgpUpdateExtension.class);
- registerExtensions(FEE_UPDATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
- }
-
@Override
public final EppOutput run() throws EppException {
+ extensionManager.register(MetadataExtension.class, RgpUpdateExtension.class);
+ extensionManager.registerAsGroup(FEE_UPDATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
Update command = (Update) resourceCommand;
DomainResource existingDomain = loadAndVerifyExistence(DomainResource.class, targetId, now);
Money restoreCost = Registry.get(existingDomain.getTld()).getStandardRestoreCost();
@@ -197,7 +198,7 @@ public final class DomainRestoreRequestFlow extends LoggedInFlow implements Tran
if (!existingDomain.getGracePeriodStatuses().contains(GracePeriodStatus.REDEMPTION)) {
throw new DomainNotEligibleForRestoreException();
}
- checkAllowedAccessToTld(getAllowedTlds(), existingDomain.getTld());
+ checkAllowedAccessToTld(clientId, existingDomain.getTld());
validateFeeChallenge(targetId, existingDomain.getTld(), now, feeUpdate, restoreCost, renewCost);
}
diff --git a/java/google/registry/flows/domain/DomainTransferApproveFlow.java b/java/google/registry/flows/domain/DomainTransferApproveFlow.java
index 3e76fd365..02c909169 100644
--- a/java/google/registry/flows/domain/DomainTransferApproveFlow.java
+++ b/java/google/registry/flows/domain/DomainTransferApproveFlow.java
@@ -16,6 +16,7 @@ package google.registry.flows.domain;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.getOnlyElement;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.approvePendingTransfer;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyHasPendingTransfer;
@@ -36,9 +37,10 @@ import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent;
@@ -76,31 +78,30 @@ import org.joda.time.DateTime;
* @error {@link google.registry.flows.exceptions.NotPendingTransferException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
*/
-public final class DomainTransferApproveFlow extends LoggedInFlow implements TransactionalFlow {
+public final class DomainTransferApproveFlow extends Flow implements TransactionalFlow {
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
@Inject DomainTransferApproveFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(MetadataExtension.class);
- }
-
/**
* The logic in this flow, which handles client approvals, very closely parallels the logic in
* {@link DomainResource#cloneProjectedAtTime} which handles implicit server approvals.
*/
@Override
public final EppOutput run() throws EppException {
+ extensionManager.register(MetadataExtension.class);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
DomainResource existingDomain = loadAndVerifyExistence(DomainResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, existingDomain);
verifyHasPendingTransfer(existingDomain);
verifyResourceOwnership(clientId, existingDomain);
String tld = existingDomain.getTld();
- checkAllowedAccessToTld(getAllowedTlds(), tld);
+ checkAllowedAccessToTld(clientId, tld);
HistoryEntry historyEntry = historyBuilder
.setType(HistoryEntry.Type.DOMAIN_TRANSFER_APPROVE)
.setModificationTime(now)
diff --git a/java/google/registry/flows/domain/DomainTransferCancelFlow.java b/java/google/registry/flows/domain/DomainTransferCancelFlow.java
index 2929de5ec..25dfc837c 100644
--- a/java/google/registry/flows/domain/DomainTransferCancelFlow.java
+++ b/java/google/registry/flows/domain/DomainTransferCancelFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.domain;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.denyPendingTransfer;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyHasPendingTransfer;
@@ -30,9 +31,10 @@ import static google.registry.util.DateTimeUtils.END_OF_TIME;
import com.google.common.base.Optional;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.model.ImmutableObject;
import google.registry.model.domain.DomainResource;
@@ -61,26 +63,25 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.exceptions.NotTransferInitiatorException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
*/
-public final class DomainTransferCancelFlow extends LoggedInFlow implements TransactionalFlow {
+public final class DomainTransferCancelFlow extends Flow implements TransactionalFlow {
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
@Inject DomainTransferCancelFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(MetadataExtension.class);
- }
-
@Override
public final EppOutput run() throws EppException {
+ extensionManager.register(MetadataExtension.class);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
DomainResource existingDomain = loadAndVerifyExistence(DomainResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, existingDomain);
verifyHasPendingTransfer(existingDomain);
verifyIsGainingRegistrar(existingDomain, clientId);
- checkAllowedAccessToTld(getAllowedTlds(), existingDomain.getTld());
+ checkAllowedAccessToTld(clientId, existingDomain.getTld());
HistoryEntry historyEntry = historyBuilder
.setType(HistoryEntry.Type.DOMAIN_TRANSFER_CANCEL)
.setModificationTime(now)
diff --git a/java/google/registry/flows/domain/DomainTransferQueryFlow.java b/java/google/registry/flows/domain/DomainTransferQueryFlow.java
index fbdaf9447..975bef0b6 100644
--- a/java/google/registry/flows/domain/DomainTransferQueryFlow.java
+++ b/java/google/registry/flows/domain/DomainTransferQueryFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.domain;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
import static google.registry.flows.domain.DomainFlowUtils.createTransferResponse;
@@ -22,9 +23,10 @@ import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import com.google.common.base.Optional;
import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.exceptions.NoTransferHistoryToQueryException;
import google.registry.flows.exceptions.NotAuthorizedToViewTransferException;
import google.registry.model.domain.DomainResource;
@@ -50,8 +52,9 @@ import org.joda.time.DateTime;
* @error {@link google.registry.flows.exceptions.NoTransferHistoryToQueryException}
* @error {@link google.registry.flows.exceptions.NotAuthorizedToViewTransferException}
*/
-public final class DomainTransferQueryFlow extends LoggedInFlow {
+public final class DomainTransferQueryFlow extends Flow {
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@@ -59,6 +62,8 @@ public final class DomainTransferQueryFlow extends LoggedInFlow {
@Override
public final EppOutput run() throws EppException {
+ extensionManager.validate(); // There are no legal extensions for this flow.
+ validateClientIsLoggedIn(clientId);
DomainResource domain = loadAndVerifyExistence(DomainResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, domain);
// Most of the fields on the transfer response are required, so there's no way to return valid
diff --git a/java/google/registry/flows/domain/DomainTransferRejectFlow.java b/java/google/registry/flows/domain/DomainTransferRejectFlow.java
index 1174492f7..b2cdbdc77 100644
--- a/java/google/registry/flows/domain/DomainTransferRejectFlow.java
+++ b/java/google/registry/flows/domain/DomainTransferRejectFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.domain;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.denyPendingTransfer;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyHasPendingTransfer;
@@ -30,9 +31,10 @@ import static google.registry.util.DateTimeUtils.END_OF_TIME;
import com.google.common.base.Optional;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.model.ImmutableObject;
import google.registry.model.domain.DomainResource;
@@ -61,21 +63,20 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.exceptions.NotPendingTransferException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
*/
-public final class DomainTransferRejectFlow extends LoggedInFlow implements TransactionalFlow {
+public final class DomainTransferRejectFlow extends Flow implements TransactionalFlow {
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
@Inject DomainTransferRejectFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(MetadataExtension.class);
- }
-
@Override
public final EppOutput run() throws EppException {
+ extensionManager.register(MetadataExtension.class);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
DomainResource existingDomain = loadAndVerifyExistence(DomainResource.class, targetId, now);
HistoryEntry historyEntry = historyBuilder
.setType(HistoryEntry.Type.DOMAIN_TRANSFER_REJECT)
@@ -85,7 +86,7 @@ public final class DomainTransferRejectFlow extends LoggedInFlow implements Tran
verifyOptionalAuthInfoForResource(authInfo, existingDomain);
verifyHasPendingTransfer(existingDomain);
verifyResourceOwnership(clientId, existingDomain);
- checkAllowedAccessToTld(getAllowedTlds(), existingDomain.getTld());
+ checkAllowedAccessToTld(clientId, existingDomain.getTld());
DomainResource newDomain =
denyPendingTransfer(existingDomain, TransferStatus.CLIENT_REJECTED, now);
ofy().save().entities(
diff --git a/java/google/registry/flows/domain/DomainTransferRequestFlow.java b/java/google/registry/flows/domain/DomainTransferRequestFlow.java
index 3c9bccc2d..ac8c3b33d 100644
--- a/java/google/registry/flows/domain/DomainTransferRequestFlow.java
+++ b/java/google/registry/flows/domain/DomainTransferRequestFlow.java
@@ -16,6 +16,7 @@ package google.registry.flows.domain;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.getOnlyElement;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
import static google.registry.flows.ResourceFlowUtils.verifyRequiredAuthInfoForResourceTransfer;
@@ -39,9 +40,10 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.exceptions.AlreadyPendingTransferException;
import google.registry.flows.exceptions.ObjectAlreadySponsoredException;
@@ -104,7 +106,7 @@ import org.joda.time.Duration;
* @error {@link DomainFlowUtils.PremiumNameBlockedException}
* @error {@link DomainFlowUtils.UnsupportedFeeAttributeException}
*/
-public final class DomainTransferRequestFlow extends LoggedInFlow implements TransactionalFlow {
+public final class DomainTransferRequestFlow extends Flow implements TransactionalFlow {
private static final ImmutableSet DISALLOWED_STATUSES = ImmutableSet.of(
StatusValue.CLIENT_TRANSFER_PROHIBITED,
@@ -112,20 +114,19 @@ public final class DomainTransferRequestFlow extends LoggedInFlow implements Tra
StatusValue.SERVER_TRANSFER_PROHIBITED);
@Inject ResourceCommand resourceCommand;
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String gainingClientId;
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
@Inject DomainTransferRequestFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(MetadataExtension.class, FlagsTransferCommandExtension.class);
- registerExtensions(FEE_TRANSFER_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
- }
-
@Override
public final EppOutput run() throws EppException {
+ extensionManager.register(FlagsTransferCommandExtension.class, MetadataExtension.class);
+ extensionManager.registerAsGroup(FEE_TRANSFER_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
+ extensionManager.validate();
+ validateClientIsLoggedIn(gainingClientId);
Period period = ((Transfer) resourceCommand).getPeriod();
int years = period.getValue();
DomainResource existingDomain = loadAndVerifyExistence(DomainResource.class, targetId, now);
@@ -194,7 +195,7 @@ public final class DomainTransferRequestFlow extends LoggedInFlow implements Tra
if (gainingClientId.equals(existingDomain.getCurrentSponsorClientId())) {
throw new ObjectAlreadySponsoredException();
}
- checkAllowedAccessToTld(getAllowedTlds(), existingDomain.getTld());
+ checkAllowedAccessToTld(gainingClientId, existingDomain.getTld());
verifyUnitIsYears(period);
if (!isSuperuser) {
verifyPremiumNameIsNotBlocked(targetId, now, gainingClientId);
diff --git a/java/google/registry/flows/domain/DomainUpdateFlow.java b/java/google/registry/flows/domain/DomainUpdateFlow.java
index 4c5b0fb0c..ae44a027f 100644
--- a/java/google/registry/flows/domain/DomainUpdateFlow.java
+++ b/java/google/registry/flows/domain/DomainUpdateFlow.java
@@ -15,6 +15,7 @@
package google.registry.flows.domain;
import static com.google.common.collect.Sets.symmetricDifference;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
@@ -44,9 +45,10 @@ import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import google.registry.dns.DnsQueue;
import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.domain.DomainFlowUtils.FeesRequiredForNonFreeUpdateException;
import google.registry.flows.domain.TldSpecificLogicProxy.EppCommandOperations;
@@ -116,7 +118,7 @@ import org.joda.time.DateTime;
* @error {@link DomainFlowUtils.TooManyNameserversException}
* @error {@link DomainFlowUtils.UrgentAttributeNotSupportedException}
*/
-public final class DomainUpdateFlow extends LoggedInFlow implements TransactionalFlow {
+public final class DomainUpdateFlow extends Flow implements TransactionalFlow {
/**
* Note that CLIENT_UPDATE_PROHIBITED is intentionally not in this list. This is because it
@@ -128,6 +130,7 @@ public final class DomainUpdateFlow extends LoggedInFlow implements Transactiona
StatusValue.SERVER_UPDATE_PROHIBITED);
@Inject ResourceCommand resourceCommand;
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@@ -135,15 +138,15 @@ public final class DomainUpdateFlow extends LoggedInFlow implements Transactiona
@Inject DnsQueue dnsQueue;
@Inject DomainUpdateFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(FEE_UPDATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
- registerExtensions(
- MetadataExtension.class, SecDnsUpdateExtension.class, FlagsUpdateCommandExtension.class);
- }
-
@Override
public EppOutput run() throws EppException {
+ extensionManager.register(
+ FlagsUpdateCommandExtension.class,
+ MetadataExtension.class,
+ SecDnsUpdateExtension.class);
+ extensionManager.registerAsGroup(FEE_UPDATE_COMMAND_EXTENSIONS_IN_PREFERENCE_ORDER);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
Update command = cloneAndLinkReferences((Update) resourceCommand, now);
DomainResource existingDomain = loadAndVerifyExistence(DomainResource.class, targetId, now);
verifyUpdateAllowed(command, existingDomain);
@@ -184,7 +187,7 @@ public final class DomainUpdateFlow extends LoggedInFlow implements Transactiona
verifyStatusChangesAreClientSettable(command);
}
String tld = existingDomain.getTld();
- checkAllowedAccessToTld(getAllowedTlds(), tld);
+ checkAllowedAccessToTld(clientId, tld);
EppCommandOperations commandOperations = TldSpecificLogicProxy.getUpdatePrice(
Registry.get(tld), targetId, clientId, now, eppInput);
diff --git a/java/google/registry/flows/host/HostCheckFlow.java b/java/google/registry/flows/host/HostCheckFlow.java
index 09fc2f374..d26e0c6fc 100644
--- a/java/google/registry/flows/host/HostCheckFlow.java
+++ b/java/google/registry/flows/host/HostCheckFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.host;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyTargetIdCount;
import static google.registry.model.EppResourceUtils.checkResourcesExist;
import static google.registry.model.eppoutput.Result.Code.SUCCESS;
@@ -21,7 +22,9 @@ import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import com.google.common.collect.ImmutableList;
import google.registry.config.ConfigModule.Config;
import google.registry.flows.EppException;
-import google.registry.flows.LoggedInFlow;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
+import google.registry.flows.FlowModule.ClientId;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.CheckData.HostCheck;
import google.registry.model.eppoutput.CheckData.HostCheckData;
@@ -39,14 +42,18 @@ import javax.inject.Inject;
*
* @error {@link google.registry.flows.exceptions.TooManyResourceChecksException}
*/
-public final class HostCheckFlow extends LoggedInFlow {
+public final class HostCheckFlow extends Flow {
@Inject ResourceCommand resourceCommand;
+ @Inject @ClientId String clientId;
+ @Inject ExtensionManager extensionManager;
@Inject @Config("maxChecks") int maxChecks;
@Inject HostCheckFlow() {}
@Override
protected final EppOutput run() throws EppException {
+ extensionManager.validate(); // There are no legal extensions for this flow.
+ validateClientIsLoggedIn(clientId);
List targetIds = ((Check) resourceCommand).getTargetIds();
verifyTargetIdCount(targetIds, maxChecks);
Set existingIds = checkResourcesExist(HostResource.class, targetIds, now);
diff --git a/java/google/registry/flows/host/HostCreateFlow.java b/java/google/registry/flows/host/HostCreateFlow.java
index 95022cd3d..f8889e01e 100644
--- a/java/google/registry/flows/host/HostCreateFlow.java
+++ b/java/google/registry/flows/host/HostCreateFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.host;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyResourceDoesNotExist;
import static google.registry.flows.host.HostFlowUtils.lookupSuperordinateDomain;
import static google.registry.flows.host.HostFlowUtils.validateHostName;
@@ -31,9 +32,10 @@ import google.registry.dns.DnsQueue;
import google.registry.flows.EppException;
import google.registry.flows.EppException.ParameterValueRangeErrorException;
import google.registry.flows.EppException.RequiredParameterMissingException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.model.ImmutableObject;
import google.registry.model.domain.DomainResource;
@@ -68,23 +70,21 @@ import javax.inject.Inject;
* @error {@link SubordinateHostMustHaveIpException}
* @error {@link UnexpectedExternalHostIpException}
*/
-public final class HostCreateFlow extends LoggedInFlow implements TransactionalFlow {
+public final class HostCreateFlow extends Flow implements TransactionalFlow {
@Inject ResourceCommand resourceCommand;
+ @Inject ExtensionManager extensionManager;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
@Inject DnsQueue dnsQueue;
@Inject HostCreateFlow() {}
- @Override
- @SuppressWarnings("unchecked")
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(MetadataExtension.class);
- }
-
@Override
protected final EppOutput run() throws EppException {
+ extensionManager.register(MetadataExtension.class);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
Create command = (Create) resourceCommand;
verifyResourceDoesNotExist(HostResource.class, targetId, now);
// The superordinate domain of the host object if creating an in-bailiwick host, or null if
diff --git a/java/google/registry/flows/host/HostDeleteFlow.java b/java/google/registry/flows/host/HostDeleteFlow.java
index b8d4cbfe8..e6f1a21d3 100644
--- a/java/google/registry/flows/host/HostDeleteFlow.java
+++ b/java/google/registry/flows/host/HostDeleteFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.host;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.failfastForAsyncDelete;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
@@ -27,9 +28,10 @@ import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.async.AsyncFlowEnqueuer;
import google.registry.model.domain.DomainBase;
@@ -55,7 +57,7 @@ import javax.inject.Inject;
* @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException}
* @error {@link google.registry.flows.exceptions.ResourceToDeleteIsReferencedException}
*/
-public final class HostDeleteFlow extends LoggedInFlow implements TransactionalFlow {
+public final class HostDeleteFlow extends Flow implements TransactionalFlow {
private static final ImmutableSet DISALLOWED_STATUSES = ImmutableSet.of(
StatusValue.LINKED,
@@ -70,20 +72,19 @@ public final class HostDeleteFlow extends LoggedInFlow implements TransactionalF
return domain.getNameservers();
}};
- @Inject AsyncFlowEnqueuer asyncFlowEnqueuer;
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject HistoryEntry.Builder historyBuilder;
+ @Inject AsyncFlowEnqueuer asyncFlowEnqueuer;
@Inject HostDeleteFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(MetadataExtension.class);
- }
-
@Override
public final EppOutput run() throws EppException {
+ extensionManager.register(MetadataExtension.class);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
failfastForAsyncDelete(targetId, now, HostResource.class, GET_NAMESERVERS);
HostResource existingHost = loadAndVerifyExistence(HostResource.class, targetId, now);
verifyNoDisallowedStatuses(existingHost, DISALLOWED_STATUSES);
diff --git a/java/google/registry/flows/host/HostInfoFlow.java b/java/google/registry/flows/host/HostInfoFlow.java
index f27140496..aedc4c094 100644
--- a/java/google/registry/flows/host/HostInfoFlow.java
+++ b/java/google/registry/flows/host/HostInfoFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.host;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
import static google.registry.model.EppResourceUtils.cloneResourceWithLinkedStatus;
@@ -21,8 +22,10 @@ import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import com.google.common.base.Optional;
import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
+import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppoutput.EppOutput;
import google.registry.model.host.HostResource;
@@ -36,14 +39,18 @@ import javax.inject.Inject;
*
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
*/
-public final class HostInfoFlow extends LoggedInFlow {
+public final class HostInfoFlow extends Flow {
+ @Inject ExtensionManager extensionManager;
+ @Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@Inject Optional authInfo;
@Inject HostInfoFlow() {}
@Override
public EppOutput run() throws EppException {
+ extensionManager.validate(); // There are no legal extensions for this flow.
+ validateClientIsLoggedIn(clientId);
HostResource host = loadAndVerifyExistence(HostResource.class, targetId, now);
verifyOptionalAuthInfoForResource(authInfo, host);
return createOutput(SUCCESS, cloneResourceWithLinkedStatus(host, now));
diff --git a/java/google/registry/flows/host/HostUpdateFlow.java b/java/google/registry/flows/host/HostUpdateFlow.java
index 868e60fb6..2498f11ca 100644
--- a/java/google/registry/flows/host/HostUpdateFlow.java
+++ b/java/google/registry/flows/host/HostUpdateFlow.java
@@ -15,6 +15,7 @@
package google.registry.flows.host;
import static com.google.common.base.MoreObjects.firstNonNull;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfoForResource;
@@ -37,9 +38,10 @@ import google.registry.flows.EppException.ObjectAlreadyExistsException;
import google.registry.flows.EppException.ParameterValueRangeErrorException;
import google.registry.flows.EppException.RequiredParameterMissingException;
import google.registry.flows.EppException.StatusProhibitsOperationException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.flows.async.AsyncFlowEnqueuer;
import google.registry.flows.exceptions.AddRemoveSameValueEppException;
@@ -88,7 +90,7 @@ import javax.inject.Inject;
* @error {@link RenameHostToExternalRemoveIpException}
* @error {@link RenameHostToSubordinateRequiresIpException}
*/
-public final class HostUpdateFlow extends LoggedInFlow implements TransactionalFlow {
+public final class HostUpdateFlow extends Flow implements TransactionalFlow {
/**
* Note that CLIENT_UPDATE_PROHIBITED is intentionally not in this list. This is because it
@@ -100,6 +102,7 @@ public final class HostUpdateFlow extends LoggedInFlow implements TransactionalF
StatusValue.SERVER_UPDATE_PROHIBITED);
@Inject ResourceCommand resourceCommand;
+ @Inject ExtensionManager extensionManager;
@Inject Optional authInfo;
@Inject @ClientId String clientId;
@Inject @TargetId String targetId;
@@ -108,13 +111,11 @@ public final class HostUpdateFlow extends LoggedInFlow implements TransactionalF
@Inject DnsQueue dnsQueue;
@Inject HostUpdateFlow() {}
- @Override
- protected final void initLoggedInFlow() throws EppException {
- registerExtensions(MetadataExtension.class);
- }
-
@Override
public final EppOutput run() throws EppException {
+ extensionManager.register(MetadataExtension.class);
+ extensionManager.validate();
+ validateClientIsLoggedIn(clientId);
Update command = (Update) resourceCommand;
String suppliedNewHostName = command.getInnerChange().getFullyQualifiedHostName();
HostResource existingHost = loadAndVerifyExistence(HostResource.class, targetId, now);
diff --git a/java/google/registry/flows/poll/PollAckFlow.java b/java/google/registry/flows/poll/PollAckFlow.java
index 64bb0f091..22bd3e042 100644
--- a/java/google/registry/flows/poll/PollAckFlow.java
+++ b/java/google/registry/flows/poll/PollAckFlow.java
@@ -15,6 +15,7 @@
package google.registry.flows.poll;
import static com.google.common.base.Preconditions.checkState;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.poll.PollFlowUtils.getPollMessagesQuery;
import static google.registry.model.eppoutput.Result.Code.SUCCESS;
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_NO_MESSAGES;
@@ -28,9 +29,10 @@ import google.registry.flows.EppException.AuthorizationErrorException;
import google.registry.flows.EppException.ObjectDoesNotExistException;
import google.registry.flows.EppException.ParameterValueSyntaxErrorException;
import google.registry.flows.EppException.RequiredParameterMissingException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.PollMessageId;
-import google.registry.flows.LoggedInFlow;
import google.registry.flows.TransactionalFlow;
import google.registry.model.eppoutput.EppOutput;
import google.registry.model.poll.MessageQueueInfo;
@@ -53,14 +55,17 @@ import org.joda.time.DateTime;
* @error {@link PollAckFlow.MissingMessageIdException}
* @error {@link PollAckFlow.NotAuthorizedToAckMessageException}
*/
-public class PollAckFlow extends LoggedInFlow implements TransactionalFlow {
+public class PollAckFlow extends Flow implements TransactionalFlow {
+ @Inject ExtensionManager extensionManager;
@Inject @ClientId String clientId;
@Inject @PollMessageId String messageId;
@Inject PollAckFlow() {}
@Override
public final EppOutput run() throws EppException {
+ extensionManager.validate(); // There are no legal extensions for this flow.
+ validateClientIsLoggedIn(clientId);
if (messageId.isEmpty()) {
throw new MissingMessageIdException();
}
diff --git a/java/google/registry/flows/poll/PollRequestFlow.java b/java/google/registry/flows/poll/PollRequestFlow.java
index 64b3f8432..74d2e2699 100644
--- a/java/google/registry/flows/poll/PollRequestFlow.java
+++ b/java/google/registry/flows/poll/PollRequestFlow.java
@@ -14,6 +14,7 @@
package google.registry.flows.poll;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.poll.PollFlowUtils.getPollMessagesQuery;
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACK_MESSAGE;
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_NO_MESSAGES;
@@ -22,9 +23,10 @@ import static google.registry.util.CollectionUtils.forceEmptyToNull;
import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.flows.EppException.ParameterValueSyntaxErrorException;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.PollMessageId;
-import google.registry.flows.LoggedInFlow;
import google.registry.model.eppoutput.EppOutput;
import google.registry.model.poll.MessageQueueInfo;
import google.registry.model.poll.PollMessage;
@@ -42,14 +44,17 @@ import javax.inject.Inject;
*
* @error {@link PollRequestFlow.UnexpectedMessageIdException}
*/
-public class PollRequestFlow extends LoggedInFlow {
+public class PollRequestFlow extends Flow {
+ @Inject ExtensionManager extensionManager;
@Inject @ClientId String clientId;
@Inject @PollMessageId String messageId;
@Inject PollRequestFlow() {}
@Override
public final EppOutput run() throws EppException {
+ extensionManager.validate(); // There are no legal extensions for this flow.
+ validateClientIsLoggedIn(clientId);
if (!messageId.isEmpty()) {
throw new UnexpectedMessageIdException();
}
diff --git a/java/google/registry/flows/session/HelloFlow.java b/java/google/registry/flows/session/HelloFlow.java
index 6bfdd3bd7..e6ae67e01 100644
--- a/java/google/registry/flows/session/HelloFlow.java
+++ b/java/google/registry/flows/session/HelloFlow.java
@@ -14,6 +14,8 @@
package google.registry.flows.session;
+import google.registry.flows.EppException;
+import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow;
import google.registry.model.eppoutput.EppOutput;
import google.registry.model.eppoutput.Greeting;
@@ -22,10 +24,12 @@ import javax.inject.Inject;
/** A flow for an Epp "hello". */
public class HelloFlow extends Flow {
+ @Inject ExtensionManager extensionManager;
@Inject HelloFlow() {}
@Override
- public EppOutput run() {
+ public EppOutput run() throws EppException {
+ extensionManager.validate(); // There are no legal extensions for this flow.
return EppOutput.create(Greeting.create(now));
}
}
diff --git a/java/google/registry/flows/session/LoginFlow.java b/java/google/registry/flows/session/LoginFlow.java
index 5fe3cf085..6cdd17f4d 100644
--- a/java/google/registry/flows/session/LoginFlow.java
+++ b/java/google/registry/flows/session/LoginFlow.java
@@ -27,6 +27,7 @@ import google.registry.flows.EppException.ParameterValuePolicyErrorException;
import google.registry.flows.EppException.UnimplementedExtensionException;
import google.registry.flows.EppException.UnimplementedObjectServiceException;
import google.registry.flows.EppException.UnimplementedOptionException;
+import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId;
import google.registry.model.eppcommon.ProtocolDefinition;
@@ -68,6 +69,7 @@ public class LoginFlow extends Flow {
/** Maximum number of failed login attempts allowed per connection. */
private static final int MAX_FAILED_LOGIN_ATTEMPTS_PER_CONNECTION = 3;
+ @Inject ExtensionManager extensionManager;
@Inject @ClientId String clientId;
@Inject LoginFlow() {}
@@ -84,6 +86,7 @@ public class LoginFlow extends Flow {
/** Run the flow without bothering to log errors. The {@link #run} method will do that for us. */
public final EppOutput runWithoutLogging() throws EppException {
+ extensionManager.validate(); // There are no legal extensions for this flow.
Login login = (Login) eppInput.getCommandWrapper().getCommand();
if (!clientId.isEmpty()) {
throw new AlreadyLoggedInException();
diff --git a/java/google/registry/flows/session/LogoutFlow.java b/java/google/registry/flows/session/LogoutFlow.java
index 884376483..bb38188fb 100644
--- a/java/google/registry/flows/session/LogoutFlow.java
+++ b/java/google/registry/flows/session/LogoutFlow.java
@@ -14,24 +14,31 @@
package google.registry.flows.session;
+import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.model.eppoutput.Result.Code.SUCCESS_AND_CLOSE;
import google.registry.flows.EppException;
-import google.registry.flows.LoggedInFlow;
+import google.registry.flows.ExtensionManager;
+import google.registry.flows.Flow;
+import google.registry.flows.FlowModule.ClientId;
import google.registry.model.eppoutput.EppOutput;
import javax.inject.Inject;
/**
* An EPP flow for logout.
*
- * @error {@link google.registry.flows.LoggedInFlow.NotLoggedInException}
+ * @error {@link google.registry.flows.FlowUtils.NotLoggedInException}
*/
-public class LogoutFlow extends LoggedInFlow {
+public class LogoutFlow extends Flow {
+ @Inject ExtensionManager extensionManager;
+ @Inject @ClientId String clientId;
@Inject LogoutFlow() {}
@Override
public final EppOutput run() throws EppException {
+ extensionManager.validate(); // There are no legal extensions for this flow.
+ validateClientIsLoggedIn(clientId);
sessionMetadata.invalidate();
return createOutput(SUCCESS_AND_CLOSE);
}
diff --git a/javatests/google/registry/flows/ExtensionManagerTest.java b/javatests/google/registry/flows/ExtensionManagerTest.java
new file mode 100644
index 000000000..b11f9ec84
--- /dev/null
+++ b/javatests/google/registry/flows/ExtensionManagerTest.java
@@ -0,0 +1,218 @@
+// Copyright 2016 The Nomulus Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package google.registry.flows;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.testing.TestLogHandler;
+import google.registry.flows.EppException.UnimplementedExtensionException;
+import google.registry.flows.ExtensionManager.UndeclaredServiceExtensionException;
+import google.registry.flows.ExtensionManager.UnsupportedRepeatedExtensionException;
+import google.registry.flows.exceptions.OnlyToolCanPassMetadataException;
+import google.registry.flows.session.HelloFlow;
+import google.registry.model.domain.allocate.AllocateCreateExtension;
+import google.registry.model.domain.fee06.FeeInfoCommandExtensionV06;
+import google.registry.model.domain.launch.LaunchCreateExtension;
+import google.registry.model.domain.metadata.MetadataExtension;
+import google.registry.model.eppcommon.ProtocolDefinition.ServiceExtension;
+import google.registry.model.eppinput.EppInput;
+import google.registry.model.eppinput.EppInput.CommandExtension;
+import google.registry.testing.AppEngineRule;
+import google.registry.testing.ExceptionRule;
+import google.registry.util.TypeUtils;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link ExtensionManager}. */
+@RunWith(JUnit4.class)
+public class ExtensionManagerTest {
+
+ @Rule
+ public final AppEngineRule appEngine = AppEngineRule.builder()
+ .withDatastore()
+ .build();
+
+ @Rule
+ public final ExceptionRule thrown = new ExceptionRule();
+
+ @Test
+ public void testDuplicateExtensionsForbidden() throws Exception {
+ ExtensionManager manager = new TestInstanceBuilder()
+ .setEppRequestSource(EppRequestSource.TOOL)
+ .setDeclaredUris()
+ .setSuppliedExtensions(
+ MetadataExtension.class,
+ LaunchCreateExtension.class,
+ MetadataExtension.class)
+ .build();
+ manager.register(MetadataExtension.class, LaunchCreateExtension.class);
+ thrown.expect(UnsupportedRepeatedExtensionException.class);
+ manager.validate();
+ }
+
+ @Test
+ public void testMultipleExtensionsFromSameGroupForbidden() throws Exception {
+ ExtensionManager manager = new TestInstanceBuilder()
+ .setEppRequestSource(EppRequestSource.TOOL)
+ .setDeclaredUris(ServiceExtension.FEE_0_6.getUri())
+ .setSuppliedExtensions(
+ MetadataExtension.class,
+ LaunchCreateExtension.class,
+ AllocateCreateExtension.class)
+ .build();
+ manager.register(MetadataExtension.class);
+ manager.registerAsGroup(
+ ImmutableList.of(LaunchCreateExtension.class, AllocateCreateExtension.class));
+ thrown.expect(UnsupportedRepeatedExtensionException.class);
+ manager.validate();
+ }
+
+ @Test
+ public void testUndeclaredExtensionsLogged() throws Exception {
+ TestLogHandler handler = new TestLogHandler();
+ Logger.getLogger(ExtensionManager.class.getCanonicalName()).addHandler(handler);
+ ExtensionManager manager = new TestInstanceBuilder()
+ .setEppRequestSource(EppRequestSource.TOOL)
+ .setDeclaredUris()
+ .setSuppliedExtensions(MetadataExtension.class)
+ .build();
+ manager.register(MetadataExtension.class);
+ manager.validate();
+ ImmutableList.Builder logMessages = new ImmutableList.Builder<>();
+ for (LogRecord record : handler.getStoredLogRecords()) {
+ logMessages.add(record.getMessage());
+ }
+ assertThat(logMessages.build()).contains(
+ "Client clientId is attempting to run HelloFlow without declaring "
+ + "URIs [urn:google:params:xml:ns:metadata-1.0] on login");
+ }
+
+ @Test
+ public void testBlacklistedExtensions_forbiddenWhenUndeclared() throws Exception {
+ ExtensionManager manager = new TestInstanceBuilder()
+ .setEppRequestSource(EppRequestSource.TOOL)
+ .setDeclaredUris()
+ .setSuppliedExtensions(FeeInfoCommandExtensionV06.class)
+ .build();
+ manager.register(FeeInfoCommandExtensionV06.class);
+ thrown.expect(UndeclaredServiceExtensionException.class);
+ manager.validate();
+ }
+
+ @Test
+ public void testBlacklistedExtensions_allowedWhenDeclared() throws Exception {
+ ExtensionManager manager = new TestInstanceBuilder()
+ .setEppRequestSource(EppRequestSource.TOOL)
+ .setDeclaredUris(ServiceExtension.FEE_0_6.getUri())
+ .setSuppliedExtensions(FeeInfoCommandExtensionV06.class)
+ .build();
+ manager.register(FeeInfoCommandExtensionV06.class);
+ manager.validate();
+ }
+
+ @Test
+ public void testMetadataExtension_allowedForToolSource() throws Exception {
+ ExtensionManager manager = new TestInstanceBuilder()
+ .setEppRequestSource(EppRequestSource.TOOL)
+ .setDeclaredUris()
+ .setSuppliedExtensions(MetadataExtension.class)
+ .build();
+ manager.register(MetadataExtension.class);
+ manager.validate();
+ }
+
+ @Test
+ public void testMetadataExtension_forbiddenWhenNotToolSource() throws Exception {
+ ExtensionManager manager = new TestInstanceBuilder()
+ .setEppRequestSource(EppRequestSource.CONSOLE)
+ .setDeclaredUris()
+ .setSuppliedExtensions(MetadataExtension.class)
+ .build();
+ manager.register(MetadataExtension.class);
+ thrown.expect(OnlyToolCanPassMetadataException.class);
+ manager.validate();
+ }
+
+ @Test
+ public void testUnimplementedExtensionsForbidden() throws Exception {
+ ExtensionManager manager = new TestInstanceBuilder()
+ .setEppRequestSource(EppRequestSource.TOOL)
+ .setDeclaredUris()
+ .setSuppliedExtensions(LaunchCreateExtension.class)
+ .build();
+ thrown.expect(UnimplementedExtensionException.class);
+ manager.validate();
+ }
+
+ /** A builder for a test-ready {@link ExtensionManager} instance. */
+ private static class TestInstanceBuilder {
+
+ ExtensionManager manager = new ExtensionManager();
+
+ TestInstanceBuilder setEppRequestSource(EppRequestSource eppRequestSource) {
+ manager.eppRequestSource = eppRequestSource;
+ return this;
+ }
+
+ TestInstanceBuilder setDeclaredUris(String... declaredUris) {
+ manager.sessionMetadata =
+ new StatelessRequestSessionMetadata("clientId", ImmutableSet.copyOf(declaredUris));
+ return this;
+ }
+
+ @SafeVarargs
+ final TestInstanceBuilder setSuppliedExtensions(
+ Class extends CommandExtension>... suppliedExtensionClasses) {
+ manager.eppInput = new FakeEppInput(suppliedExtensionClasses);
+ return this;
+ }
+
+ ExtensionManager build() {
+ manager.flowClass = HelloFlow.class;
+ manager.clientId = manager.sessionMetadata.getClientId();
+ return manager;
+ }
+ }
+
+ /** A minimal fake {@link EppInput} that presents the given extensions. */
+ private static class FakeEppInput extends EppInput {
+
+ private final ImmutableList suppliedExtensions;
+
+ @SafeVarargs
+ FakeEppInput(Class extends CommandExtension>... suppliedExtensionClasses) {
+ ImmutableList.Builder instancesBuilder = new ImmutableList.Builder<>();
+ for (Class extends CommandExtension> clazz : suppliedExtensionClasses) {
+ instancesBuilder.add(TypeUtils.instantiate(clazz));
+ }
+ suppliedExtensions = instancesBuilder.build();
+ }
+
+ @Override
+ public CommandWrapper getCommandWrapper() {
+ return new CommandWrapper() {
+ @Override
+ public ImmutableList getExtensions() {
+ return suppliedExtensions;
+ }};
+ }
+ }
+}
diff --git a/javatests/google/registry/flows/ResourceFlowTestCase.java b/javatests/google/registry/flows/ResourceFlowTestCase.java
index 12b3bbedb..e3c33ccc0 100644
--- a/javatests/google/registry/flows/ResourceFlowTestCase.java
+++ b/javatests/google/registry/flows/ResourceFlowTestCase.java
@@ -25,7 +25,7 @@ import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.googlecode.objectify.Key;
-import google.registry.flows.EppException.CommandUseErrorException;
+import google.registry.flows.FlowUtils.NotLoggedInException;
import google.registry.model.EppResource;
import google.registry.model.EppResourceUtils;
import google.registry.model.domain.DomainApplication;
@@ -114,7 +114,7 @@ public abstract class ResourceFlowTestCase