mirror of
https://github.com/google/nomulus
synced 2026-01-05 04:56:03 +00:00
Allow anchor tenant creation via allocation token behavior (#1735)
* Allow anchor tenant creation via allocation token behavior This also enforces that non-superusers cannot create registrations on trademarked names prior to the sunrise period, even if they have an allocation token with ANCHOR_TENANT behavior.
This commit is contained in:
@@ -153,6 +153,7 @@ import org.joda.time.Duration;
|
||||
* @error {@link DomainCreateFlow.AnchorTenantCreatePeriodException}
|
||||
* @error {@link DomainCreateFlow.MustHaveSignedMarksInCurrentPhaseException}
|
||||
* @error {@link DomainCreateFlow.NoGeneralRegistrationsInCurrentPhaseException}
|
||||
* @error {@link DomainCreateFlow.NoTrademarkedRegistrationsBeforeSunriseException}
|
||||
* @error {@link DomainCreateFlow.SignedMarksOnlyDuringSunriseException}
|
||||
* @error {@link DomainFlowTmchUtils.NoMarksFoundMatchingDomainException}
|
||||
* @error {@link DomainFlowTmchUtils.FoundMarkNotYetValidException}
|
||||
@@ -481,7 +482,8 @@ public final class DomainCreateFlow implements TransactionalFlow {
|
||||
boolean isValidReservedCreate,
|
||||
boolean hasSignedMarks)
|
||||
throws NoGeneralRegistrationsInCurrentPhaseException,
|
||||
MustHaveSignedMarksInCurrentPhaseException {
|
||||
MustHaveSignedMarksInCurrentPhaseException,
|
||||
NoTrademarkedRegistrationsBeforeSunriseException {
|
||||
// We allow general registration during GA.
|
||||
TldState currentState = registry.getTldState(now);
|
||||
if (currentState.equals(GENERAL_AVAILABILITY)) {
|
||||
@@ -496,16 +498,23 @@ public final class DomainCreateFlow implements TransactionalFlow {
|
||||
// Bypass most TLD state checks if that behavior is specified by the token
|
||||
if (behavior.equals(RegistrationBehavior.BYPASS_TLD_STATE)
|
||||
|| behavior.equals(RegistrationBehavior.ANCHOR_TENANT)) {
|
||||
// If bypassing TLD state checks, a post-sunrise state is always fine
|
||||
if (!currentState.equals(START_DATE_SUNRISE)
|
||||
&& registry.getTldStateTransitions().headMap(now).containsValue(START_DATE_SUNRISE)) {
|
||||
return;
|
||||
}
|
||||
// Non-trademarked names with the state check bypassed are always available
|
||||
if (!claimsList.getClaimKey(domainLabel).isPresent()) {
|
||||
return;
|
||||
}
|
||||
if (!currentState.equals(START_DATE_SUNRISE)) {
|
||||
// Trademarked domains cannot be registered until after the sunrise period has ended, unless
|
||||
// a valid signed mark is provided. Signed marks can only be provided during sunrise.
|
||||
// Thus, when bypassing TLD state checks, a post-sunrise state is always fine.
|
||||
if (registry.getTldStateTransitions().headMap(now).containsValue(START_DATE_SUNRISE)) {
|
||||
return;
|
||||
} else {
|
||||
// If sunrise hasn't happened yet, trademarked domains are unavailable
|
||||
throw new NoTrademarkedRegistrationsBeforeSunriseException(domainLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, signed marks are necessary and sufficient in the sunrise period
|
||||
if (currentState.equals(START_DATE_SUNRISE)) {
|
||||
if (!hasSignedMarks) {
|
||||
@@ -724,6 +733,17 @@ public final class DomainCreateFlow implements TransactionalFlow {
|
||||
}
|
||||
}
|
||||
|
||||
/** Trademarked domains cannot be registered before the sunrise period. */
|
||||
static class NoTrademarkedRegistrationsBeforeSunriseException
|
||||
extends ParameterValuePolicyErrorException {
|
||||
public NoTrademarkedRegistrationsBeforeSunriseException(String domainLabel) {
|
||||
super(
|
||||
String.format(
|
||||
"The trademarked label %s cannot be registered before the sunrise period.",
|
||||
domainLabel));
|
||||
}
|
||||
}
|
||||
|
||||
/** Anchor tenant domain create is for the wrong number of years. */
|
||||
static class AnchorTenantCreatePeriodException extends ParameterValuePolicyErrorException {
|
||||
public AnchorTenantCreatePeriodException(int invalidYears) {
|
||||
|
||||
@@ -112,6 +112,7 @@ import google.registry.model.domain.secdns.SecDnsUpdateExtension;
|
||||
import google.registry.model.domain.secdns.SecDnsUpdateExtension.Add;
|
||||
import google.registry.model.domain.secdns.SecDnsUpdateExtension.Remove;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.domain.token.AllocationToken.RegistrationBehavior;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
|
||||
import google.registry.model.host.Host;
|
||||
@@ -270,7 +271,13 @@ public class DomainFlowUtils {
|
||||
&& token.get().getDomainName().get().equals(domainName.toString())) {
|
||||
return true;
|
||||
}
|
||||
// Otherwise check whether the metadata extension is being used by a superuser to specify that
|
||||
// Otherwise, check to see if we're using the specialized anchor tenant registration behavior on
|
||||
// the allocation token
|
||||
if (token.isPresent()
|
||||
&& token.get().getRegistrationBehavior().equals(RegistrationBehavior.ANCHOR_TENANT)) {
|
||||
return true;
|
||||
}
|
||||
// Otherwise, check whether the metadata extension is being used by a superuser to specify that
|
||||
// it's an anchor tenant creation.
|
||||
return metadataExtension.isPresent() && metadataExtension.get().getIsAnchorTenant();
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ import google.registry.flows.ResourceFlowTestCase;
|
||||
import google.registry.flows.domain.DomainCreateFlow.AnchorTenantCreatePeriodException;
|
||||
import google.registry.flows.domain.DomainCreateFlow.MustHaveSignedMarksInCurrentPhaseException;
|
||||
import google.registry.flows.domain.DomainCreateFlow.NoGeneralRegistrationsInCurrentPhaseException;
|
||||
import google.registry.flows.domain.DomainCreateFlow.NoTrademarkedRegistrationsBeforeSunriseException;
|
||||
import google.registry.flows.domain.DomainCreateFlow.RenewalPriceInfo;
|
||||
import google.registry.flows.domain.DomainCreateFlow.SignedMarksOnlyDuringSunriseException;
|
||||
import google.registry.flows.domain.DomainFlowTmchUtils.FoundMarkExpiredException;
|
||||
@@ -2734,7 +2735,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_quietPeriod_skipTldCheckWithToken() throws Exception {
|
||||
void testSuccess_quietPeriod_skipTldStateCheckWithToken() throws Exception {
|
||||
AllocationToken token =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
@@ -2813,7 +2814,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
.build());
|
||||
persistContactsAndHosts();
|
||||
setEppInput("domain_create_allocationtoken_claims.xml");
|
||||
assertThrows(NoGeneralRegistrationsInCurrentPhaseException.class, this::runFlow);
|
||||
assertThrows(NoTrademarkedRegistrationsBeforeSunriseException.class, this::runFlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2844,4 +2845,285 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
runFlow();
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(), allocationToken);
|
||||
}
|
||||
|
||||
// ________________________________
|
||||
// Anchor tenant in quiet period before sunrise:
|
||||
// Only non-trademarked domains are allowed.
|
||||
// ________________________________
|
||||
@Test
|
||||
void testSuccess_anchorTenant_quietPeriodBeforeSunrise_nonTrademarked_viaToken()
|
||||
throws Exception {
|
||||
createTld("tld", QUIET_PERIOD);
|
||||
AllocationToken token =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("example.tld")
|
||||
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
|
||||
.build());
|
||||
setEppInput(
|
||||
"domain_create_allocationtoken.xml",
|
||||
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
|
||||
persistContactsAndHosts();
|
||||
runFlow();
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT), token);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_anchorTenant_quietPeriodBeforeSunrise_trademarked_withoutClaims_viaToken() {
|
||||
createTld("tld", QUIET_PERIOD);
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("test-validate.tld")
|
||||
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
|
||||
.build());
|
||||
setEppInput(
|
||||
"domain_create_allocationtoken.xml",
|
||||
ImmutableMap.of("DOMAIN", "test-validate.tld", "YEARS", "2"));
|
||||
persistContactsAndHosts();
|
||||
assertThrows(NoTrademarkedRegistrationsBeforeSunriseException.class, this::runFlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_anchorTenant_quietPeriodBeforeSunrise_trademarked_withClaims_viaToken() {
|
||||
createTld("tld", QUIET_PERIOD);
|
||||
persistResource(
|
||||
allocationToken
|
||||
.asBuilder()
|
||||
.setDomainName("example-one.tld")
|
||||
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
|
||||
.build());
|
||||
setEppInput("domain_create_allocationtoken_claims.xml");
|
||||
persistContactsAndHosts();
|
||||
assertThrows(NoTrademarkedRegistrationsBeforeSunriseException.class, this::runFlow);
|
||||
}
|
||||
|
||||
// ________________________________
|
||||
// Anchor tenant in sunrise:
|
||||
// Non-trademarked domains and trademarked domains with signed marks are allowed
|
||||
// ________________________________
|
||||
@Test
|
||||
void testSuccess_anchorTenant_inSunrise_nonTrademarked_viaToken() throws Exception {
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
AllocationToken token =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("example.tld")
|
||||
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
|
||||
.build());
|
||||
persistContactsAndHosts();
|
||||
setEppInput(
|
||||
"domain_create_allocationtoken.xml",
|
||||
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
|
||||
runFlow();
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT), token);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_anchorTenant_inSunrise_trademarked_withSignedMark_viaToken() throws Exception {
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
clock.setTo(DateTime.parse("2014-09-09T09:09:09Z"));
|
||||
setEppInput(
|
||||
"domain_create_registration_encoded_signed_mark_allocationtoken.xml",
|
||||
ImmutableMap.of("DOMAIN", "test-validate.tld"));
|
||||
persistResource(
|
||||
allocationToken
|
||||
.asBuilder()
|
||||
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
|
||||
.setDomainName("test-validate.tld")
|
||||
.build());
|
||||
persistContactsAndHosts();
|
||||
runFlow();
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(SUNRISE, ANCHOR_TENANT), allocationToken);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_anchorTenant_inSunrise_trademarked_withoutSignedMark_viaToken() {
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setToken("abc123")
|
||||
.setDomainName("example-one.tld")
|
||||
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
|
||||
.build());
|
||||
persistContactsAndHosts();
|
||||
assertThrows(MustHaveSignedMarksInCurrentPhaseException.class, this::runFlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_anchorTenant_inSunrise_trademarked_withoutSignedMark_withClaims_viaToken() {
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
persistResource(
|
||||
allocationToken
|
||||
.asBuilder()
|
||||
.setDomainName("example-one.tld")
|
||||
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
|
||||
.build());
|
||||
setEppInput("domain_create_allocationtoken_claims.xml");
|
||||
persistContactsAndHosts();
|
||||
assertThrows(MustHaveSignedMarksInCurrentPhaseException.class, this::runFlow);
|
||||
}
|
||||
|
||||
// ________________________________
|
||||
// Anchor tenant in a post-sunrise quiet period:
|
||||
// Non-trademarked domains and trademarked domains with claims are allowed.
|
||||
// ________________________________
|
||||
@Test
|
||||
void testSuccess_anchorTenant_quietPeriodAfterSunrise_nonTrademarked_viaToken() throws Exception {
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setTldStateTransitions(
|
||||
ImmutableSortedMap.of(
|
||||
START_OF_TIME,
|
||||
QUIET_PERIOD,
|
||||
clock.nowUtc().minusYears(1),
|
||||
START_DATE_SUNRISE,
|
||||
clock.nowUtc().minusMonths(1),
|
||||
QUIET_PERIOD))
|
||||
.build());
|
||||
AllocationToken token =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
|
||||
.setDomainName("example.tld")
|
||||
.build());
|
||||
persistContactsAndHosts();
|
||||
setEppInput(
|
||||
"domain_create_allocationtoken.xml",
|
||||
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
|
||||
runFlow();
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT), token);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_anchorTenant_quietPeriodAfterSunrise_trademarked_withClaims_viaToken()
|
||||
throws Exception {
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setTldStateTransitions(
|
||||
ImmutableSortedMap.of(
|
||||
START_OF_TIME,
|
||||
QUIET_PERIOD,
|
||||
clock.nowUtc().minusYears(1),
|
||||
START_DATE_SUNRISE,
|
||||
clock.nowUtc().minusMonths(1),
|
||||
QUIET_PERIOD))
|
||||
.build());
|
||||
persistResource(
|
||||
allocationToken
|
||||
.asBuilder()
|
||||
.setDomainName("example-one.tld")
|
||||
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
|
||||
.build());
|
||||
setEppInput("domain_create_allocationtoken_claims.xml");
|
||||
persistContactsAndHosts();
|
||||
runFlow();
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT), allocationToken);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_anchorTenant_quietPeriodAfterSunrise_trademarked_withoutClaims_viaToken() {
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
.setTldStateTransitions(
|
||||
ImmutableSortedMap.of(
|
||||
START_OF_TIME,
|
||||
QUIET_PERIOD,
|
||||
clock.nowUtc().minusYears(1),
|
||||
START_DATE_SUNRISE,
|
||||
clock.nowUtc().minusMonths(1),
|
||||
QUIET_PERIOD))
|
||||
.build());
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("example-one.tld")
|
||||
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
|
||||
.build());
|
||||
persistContactsAndHosts();
|
||||
setEppInput(
|
||||
"domain_create_allocationtoken.xml",
|
||||
ImmutableMap.of("DOMAIN", "example-one.tld", "YEARS", "2"));
|
||||
assertThrows(MissingClaimsNoticeException.class, this::runFlow);
|
||||
}
|
||||
|
||||
// ________________________________
|
||||
// Anchor tenant in GA:
|
||||
// Non-trademarked domains and trademarked domains with claims are allowed.
|
||||
// ________________________________
|
||||
@Test
|
||||
void testSuccess_anchorTenant_ga_nonTrademarked_viaToken() throws Exception {
|
||||
AllocationToken token =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
|
||||
.setDomainName("example.tld")
|
||||
.build());
|
||||
persistContactsAndHosts();
|
||||
setEppInput(
|
||||
"domain_create_allocationtoken.xml",
|
||||
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
|
||||
runFlow();
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT), token);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_anchorTenant_ga_trademarked_withClaims_viaToken() throws Exception {
|
||||
persistResource(
|
||||
allocationToken
|
||||
.asBuilder()
|
||||
.setDomainName("example-one.tld")
|
||||
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
|
||||
.build());
|
||||
setEppInput("domain_create_allocationtoken_claims.xml");
|
||||
persistContactsAndHosts();
|
||||
runFlow();
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT), allocationToken);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_anchorTenant_ga_trademarked_withoutClaims_viaToken() {
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("example-one.tld")
|
||||
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
|
||||
.build());
|
||||
persistContactsAndHosts();
|
||||
setEppInput(
|
||||
"domain_create_allocationtoken.xml",
|
||||
ImmutableMap.of("DOMAIN", "example-one.tld", "YEARS", "2"));
|
||||
assertThrows(MissingClaimsNoticeException.class, this::runFlow);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_anchorTenant_mismatchedName_viaToken() throws Exception {
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
|
||||
.setDomainName("example.tld")
|
||||
.build());
|
||||
persistContactsAndHosts();
|
||||
setEppInput(
|
||||
"domain_create_allocationtoken.xml",
|
||||
ImmutableMap.of("DOMAIN", "example-one.tld", "YEARS", "2"));
|
||||
assertThrows(AllocationTokenNotValidForDomainException.class, this::runFlow);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -374,6 +374,7 @@ An EPP flow that creates a new domain resource.
|
||||
* The allocation token was already redeemed.
|
||||
* 2306
|
||||
* Anchor tenant domain create is for the wrong number of years.
|
||||
* Trademarked domains cannot be registered before the sunrise period.
|
||||
* The provided mark is not yet valid.
|
||||
* The provided mark has expired.
|
||||
* Domain names can only contain a-z, 0-9, '.' and '-'.
|
||||
|
||||
Reference in New Issue
Block a user