diff --git a/docs/flows.md b/docs/flows.md
index 80e5ed56c..5ed134696 100644
--- a/docs/flows.md
+++ b/docs/flows.md
@@ -602,6 +602,8 @@ An EPP flow that deletes a domain.
* 2002
* Command is not allowed in the current registry phase.
+* 2103
+ * Specified extension is not implemented.
* 2201
* The specified resource belongs to another client.
* Only a tool can pass a metadata extension.
diff --git a/java/google/registry/flows/EppXmlTransformer.java b/java/google/registry/flows/EppXmlTransformer.java
index 969e88c34..7ce6a31c3 100644
--- a/java/google/registry/flows/EppXmlTransformer.java
+++ b/java/google/registry/flows/EppXmlTransformer.java
@@ -64,7 +64,8 @@ public class EppXmlTransformer {
"smd.xsd",
"launch.xsd",
"allocate.xsd",
- "superuser.xsd");
+ "superuser.xsd",
+ "allocationToken-1.0.xsd");
private static final XmlTransformer INPUT_TRANSFORMER =
new XmlTransformer(SCHEMAS, EppInput.class);
diff --git a/java/google/registry/flows/domain/DomainCheckFlow.java b/java/google/registry/flows/domain/DomainCheckFlow.java
index 5fc13c6f5..975e9d95a 100644
--- a/java/google/registry/flows/domain/DomainCheckFlow.java
+++ b/java/google/registry/flows/domain/DomainCheckFlow.java
@@ -49,6 +49,7 @@ import google.registry.model.domain.fee.FeeCheckCommandExtension;
import google.registry.model.domain.fee.FeeCheckCommandExtensionItem;
import google.registry.model.domain.fee.FeeCheckResponseExtensionItem;
import google.registry.model.domain.launch.LaunchCheckExtension;
+import google.registry.model.domain.token.AllocationTokenExtension;
import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.ResourceCommand;
import google.registry.model.eppoutput.CheckData.DomainCheck;
@@ -118,7 +119,8 @@ public final class DomainCheckFlow implements Flow {
@Override
public EppResponse run() throws EppException {
- extensionManager.register(FeeCheckCommandExtension.class, LaunchCheckExtension.class);
+ extensionManager.register(
+ FeeCheckCommandExtension.class, LaunchCheckExtension.class, AllocationTokenExtension.class);
customLogic.beforeValidation();
extensionManager.validate();
validateClientIsLoggedIn(clientId);
diff --git a/java/google/registry/flows/domain/DomainCreateFlow.java b/java/google/registry/flows/domain/DomainCreateFlow.java
index 724f94ec1..35654f0d9 100644
--- a/java/google/registry/flows/domain/DomainCreateFlow.java
+++ b/java/google/registry/flows/domain/DomainCreateFlow.java
@@ -85,6 +85,7 @@ import google.registry.model.domain.launch.LaunchCreateExtension;
import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.secdns.SecDnsCreateExtension;
+import google.registry.model.domain.token.AllocationTokenExtension;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.ResourceCommand;
@@ -194,7 +195,8 @@ public class DomainCreateFlow implements TransactionalFlow {
FeeCreateCommandExtension.class,
SecDnsCreateExtension.class,
MetadataExtension.class,
- LaunchCreateExtension.class);
+ LaunchCreateExtension.class,
+ AllocationTokenExtension.class);
customLogic.beforeValidation();
extensionManager.validate();
validateClientIsLoggedIn(clientId);
diff --git a/java/google/registry/flows/domain/DomainDeleteFlow.java b/java/google/registry/flows/domain/DomainDeleteFlow.java
index 26eee582f..659989aa7 100644
--- a/java/google/registry/flows/domain/DomainDeleteFlow.java
+++ b/java/google/registry/flows/domain/DomainDeleteFlow.java
@@ -100,6 +100,7 @@ import org.joda.time.Duration;
/**
* An EPP flow that deletes a domain.
*
+ * @error {@link google.registry.flows.EppException.UnimplementedExtensionException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException}
* @error {@link google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException}
* @error {@link google.registry.flows.exceptions.OnlyToolCanPassMetadataException}
diff --git a/java/google/registry/model/domain/token/AllocationTokenExtension.java b/java/google/registry/model/domain/token/AllocationTokenExtension.java
new file mode 100644
index 000000000..d6fa72949
--- /dev/null
+++ b/java/google/registry/model/domain/token/AllocationTokenExtension.java
@@ -0,0 +1,38 @@
+// Copyright 2017 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.model.domain.token;
+
+import google.registry.model.ImmutableObject;
+import google.registry.model.eppinput.EppInput.CommandExtension;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlValue;
+
+/**
+ * An allocation token extension that may be present on EPP domain commands.
+ *
+ * @see the IETF
+ * draft for full details.
+ */
+@XmlRootElement(name = "allocationToken")
+public class AllocationTokenExtension extends ImmutableObject implements CommandExtension {
+
+ /** The allocation token for the command. */
+ @XmlValue
+ String allocationToken;
+
+ public String getAllocationToken() {
+ return allocationToken;
+ }
+}
diff --git a/java/google/registry/model/domain/token/package-info.java b/java/google/registry/model/domain/token/package-info.java
new file mode 100644
index 000000000..2a2c4cf40
--- /dev/null
+++ b/java/google/registry/model/domain/token/package-info.java
@@ -0,0 +1,31 @@
+// Copyright 2017 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.
+
+@XmlSchema(
+ namespace = "urn:ietf:params:xml:ns:allocationToken-1.0",
+ xmlns =
+ @XmlNs(
+ prefix = "allocationToken",
+ namespaceURI = "urn:ietf:params:xml:ns:allocationToken-1.0"
+ ),
+ elementFormDefault = XmlNsForm.QUALIFIED
+)
+@XmlAccessorType(XmlAccessType.FIELD)
+package google.registry.model.domain.token;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlNsForm;
+import javax.xml.bind.annotation.XmlSchema;
diff --git a/java/google/registry/model/eppinput/EppInput.java b/java/google/registry/model/eppinput/EppInput.java
index 65bdeb033..db7fcf504 100644
--- a/java/google/registry/model/eppinput/EppInput.java
+++ b/java/google/registry/model/eppinput/EppInput.java
@@ -51,6 +51,7 @@ import google.registry.model.domain.secdns.SecDnsCreateExtension;
import google.registry.model.domain.secdns.SecDnsUpdateExtension;
import google.registry.model.domain.superuser.DomainDeleteSuperuserExtension;
import google.registry.model.domain.superuser.DomainTransferRequestSuperuserExtension;
+import google.registry.model.domain.token.AllocationTokenExtension;
import google.registry.model.eppinput.ResourceCommand.ResourceCheck;
import google.registry.model.eppinput.ResourceCommand.SingleResourceCommand;
import google.registry.model.host.HostCommand;
@@ -329,6 +330,8 @@ public class EppInput extends ImmutableObject {
@XmlElementRefs({
// allocate create extension
@XmlElementRef(type = AllocateCreateExtension.class),
+ // allocation token extension
+ @XmlElementRef(type = AllocationTokenExtension.class),
// fee extension version 0.6
@XmlElementRef(type = FeeCheckCommandExtensionV06.class),
@XmlElementRef(type = FeeInfoCommandExtensionV06.class),
diff --git a/javatests/google/registry/flows/domain/DomainCheckFlowTest.java b/javatests/google/registry/flows/domain/DomainCheckFlowTest.java
index 908f87336..0b9deb378 100644
--- a/javatests/google/registry/flows/domain/DomainCheckFlowTest.java
+++ b/javatests/google/registry/flows/domain/DomainCheckFlowTest.java
@@ -111,6 +111,17 @@ public class DomainCheckFlowTest
create(true, "example3.tld", null));
}
+ @Test
+ public void testSuccess_oneExists_allocationTokenDoesNothing() throws Exception {
+ // TODO(b/70628322): Change this test to fail on invalid allocationToken.
+ setEppInput("domain_check_allocationtoken.xml");
+ persistActiveDomain("example1.tld");
+ doCheckTest(
+ create(false, "example1.tld", "In use"),
+ create(true, "example2.tld", null),
+ create(true, "example3.tld", null));
+ }
+
@Test
public void testSuccess_oneReserved() throws Exception {
setEppInput("domain_check_one_tld_reserved.xml");
diff --git a/javatests/google/registry/flows/domain/DomainCreateFlowTest.java b/javatests/google/registry/flows/domain/DomainCreateFlowTest.java
index c37722528..c0182def5 100644
--- a/javatests/google/registry/flows/domain/DomainCreateFlowTest.java
+++ b/javatests/google/registry/flows/domain/DomainCreateFlowTest.java
@@ -380,6 +380,14 @@ public class DomainCreateFlowTest extends ResourceFlowTestCase
+
+
+
+ example1.tld
+ example2.tld
+ example3.tld
+
+
+
+
+ abc123
+
+
+ ABC-12345
+
+
diff --git a/javatests/google/registry/flows/domain/testdata/domain_create_allocationtoken.xml b/javatests/google/registry/flows/domain/testdata/domain_create_allocationtoken.xml
new file mode 100644
index 000000000..b3941b033
--- /dev/null
+++ b/javatests/google/registry/flows/domain/testdata/domain_create_allocationtoken.xml
@@ -0,0 +1,29 @@
+
+
+
+
+ example.tld
+ 2
+
+ ns1.example.net
+ ns2.example.net
+
+ jd1234
+ sh8013
+ sh8013
+
+ 2fooBAR
+
+
+
+
+
+ abc123
+
+
+ ABC-12345
+
+
diff --git a/javatests/google/registry/flows/domain/testdata/domain_delete_allocationtoken.xml b/javatests/google/registry/flows/domain/testdata/domain_delete_allocationtoken.xml
new file mode 100644
index 000000000..e004d56a5
--- /dev/null
+++ b/javatests/google/registry/flows/domain/testdata/domain_delete_allocationtoken.xml
@@ -0,0 +1,18 @@
+
+
+
+
+ example.tld
+
+
+
+
+ abc123
+
+
+ ABC-12345
+
+