mirror of
https://github.com/google/nomulus.git
synced 2025-05-13 16:07:15 +02:00
Check the host is under registry suffix instead of public suffix
Guava now has support to distinguish a registry suffix from a public suffix. Since we are only interested in registrable domains, registry suffix is the proper thing to check.
See:
692446a303/guava/src/com/google/common/net/InternetDomainName.java
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=176126916
This commit is contained in:
parent
9ab68613a0
commit
0796a0ff1c
4 changed files with 50 additions and 59 deletions
|
@ -1032,7 +1032,7 @@ allows creating a host name, and if necessary enqueues tasks to update DNS.
|
||||||
* 2304
|
* 2304
|
||||||
* Superordinate domain for this hostname is in pending delete.
|
* Superordinate domain for this hostname is in pending delete.
|
||||||
* 2306
|
* 2306
|
||||||
* Host names must be at least two levels below the public suffix.
|
* Host names must be at least two levels below the registry suffix.
|
||||||
|
|
||||||
## HostDeleteFlow
|
## HostDeleteFlow
|
||||||
|
|
||||||
|
@ -1131,7 +1131,7 @@ are enqueued to update DNS accordingly.
|
||||||
* Cannot rename an external host.
|
* Cannot rename an external host.
|
||||||
* 2306
|
* 2306
|
||||||
* Cannot add and remove the same value.
|
* Cannot add and remove the same value.
|
||||||
* Host names must be at least two levels below the public suffix.
|
* Host names must be at least two levels below the registry suffix.
|
||||||
|
|
||||||
## LoginFlow
|
## LoginFlow
|
||||||
|
|
||||||
|
|
|
@ -57,32 +57,21 @@ public class HostFlowUtils {
|
||||||
if (!name.equals(hostName.toString())) {
|
if (!name.equals(hostName.toString())) {
|
||||||
throw new HostNameNotNormalizedException(hostName.toString());
|
throw new HostNameNotNormalizedException(hostName.toString());
|
||||||
}
|
}
|
||||||
// Checks whether a hostname is deep enough. Technically a host can be just one under a
|
// The effective TLD is, in order of preference, the registry suffix, if the TLD is a real TLD
|
||||||
// public suffix (e.g. example.com) but we require by policy that it has to be at least one
|
// published in the public suffix list (https://publicsuffix.org/, note that a registry suffix
|
||||||
// part beyond that (e.g. ns1.example.com). The public suffix list includes all current
|
// is in the "ICANN DOMAINS" in that list); or a TLD managed by Nomulus (in-bailiwick), found
|
||||||
// ccTlds, so this check requires 4+ parts if it's a ccTld that doesn't delegate second
|
// by #findTldForName; or just the last part of a domain name.
|
||||||
// level domains, such as .co.uk. But the list does not include new tlds, so in that case
|
InternetDomainName effectiveTld =
|
||||||
// we just ensure 3+ parts. In the particular case where our own tld has a '.' in it, we know
|
hostName.isUnderRegistrySuffix()
|
||||||
// that there need to be 4 parts as well.
|
? hostName.registrySuffix()
|
||||||
// TODO(b/63128999): Use better method (once implemented) that determines if it's a public
|
: findTldForName(hostName).orElse(InternetDomainName.from("invalid"));
|
||||||
// suffix that domain names can be registered under.
|
// Checks whether a hostname is deep enough. Technically a host can be just one level beneath
|
||||||
if (hostName.isUnderPublicSuffix()) {
|
// the effective TLD (e.g. example.com) but we require by policy that it has to be at least
|
||||||
if (hostName.parent().isUnderPublicSuffix()) {
|
// one part beyond that (e.g. ns1.example.com).
|
||||||
return hostName;
|
if (hostName.parts().size() < effectiveTld.parts().size() + 2) {
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We need to know how many parts the hostname has beyond the public suffix, but we don't
|
|
||||||
// know what the public suffix is. If the host is in bailiwick and we are hosting a
|
|
||||||
// multipart "tld" like .co.uk the public suffix might be 2 parts. Otherwise it's an
|
|
||||||
// unrecognized tld that's not on the public suffix list, so assume the tld alone is the
|
|
||||||
// public suffix.
|
|
||||||
Optional<InternetDomainName> tldParsed = findTldForName(hostName);
|
|
||||||
int suffixSize = tldParsed.isPresent() ? tldParsed.get().parts().size() : 1;
|
|
||||||
if (hostName.parts().size() >= suffixSize + 2) {
|
|
||||||
return hostName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new HostNameTooShallowException();
|
throw new HostNameTooShallowException();
|
||||||
|
}
|
||||||
|
return hostName;
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new InvalidHostNameException();
|
throw new InvalidHostNameException();
|
||||||
}
|
}
|
||||||
|
@ -119,8 +108,7 @@ public class HostFlowUtils {
|
||||||
|
|
||||||
/** Ensure that the superordinate domain is sponsored by the provided clientId. */
|
/** Ensure that the superordinate domain is sponsored by the provided clientId. */
|
||||||
static void verifySuperordinateDomainOwnership(
|
static void verifySuperordinateDomainOwnership(
|
||||||
String clientId,
|
String clientId, DomainResource superordinateDomain) throws EppException {
|
||||||
DomainResource superordinateDomain) throws EppException {
|
|
||||||
if (superordinateDomain != null
|
if (superordinateDomain != null
|
||||||
&& !clientId.equals(superordinateDomain.getCurrentSponsorClientId())) {
|
&& !clientId.equals(superordinateDomain.getCurrentSponsorClientId())) {
|
||||||
throw new HostDomainNotOwnedException();
|
throw new HostDomainNotOwnedException();
|
||||||
|
@ -135,8 +123,8 @@ public class HostFlowUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Ensure that the superordinate domain is not in pending delete. */
|
/** Ensure that the superordinate domain is not in pending delete. */
|
||||||
static void verifySuperordinateDomainNotInPendingDelete(
|
static void verifySuperordinateDomainNotInPendingDelete(DomainResource superordinateDomain)
|
||||||
DomainResource superordinateDomain) throws EppException {
|
throws EppException {
|
||||||
if ((superordinateDomain != null)
|
if ((superordinateDomain != null)
|
||||||
&& superordinateDomain.getStatusValues().contains(StatusValue.PENDING_DELETE)) {
|
&& superordinateDomain.getStatusValues().contains(StatusValue.PENDING_DELETE)) {
|
||||||
throw new SuperordinateDomainInPendingDeleteException();
|
throw new SuperordinateDomainInPendingDeleteException();
|
||||||
|
@ -158,10 +146,10 @@ public class HostFlowUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Host names must be at least two levels below the public suffix. */
|
/** Host names must be at least two levels below the registry suffix. */
|
||||||
static class HostNameTooShallowException extends ParameterValuePolicyErrorException {
|
static class HostNameTooShallowException extends ParameterValuePolicyErrorException {
|
||||||
public HostNameTooShallowException() {
|
public HostNameTooShallowException() {
|
||||||
super("Host names must be at least two levels below the public suffix");
|
super("Host names must be at least two levels below the registry suffix");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1006,10 +1006,10 @@ def com_google_gdata_core():
|
||||||
def com_google_guava():
|
def com_google_guava():
|
||||||
java_import_external(
|
java_import_external(
|
||||||
name = "com_google_guava",
|
name = "com_google_guava",
|
||||||
jar_sha256 = "7baa80df284117e5b945b19b98d367a85ea7b7801bd358ff657946c3bd1b6596",
|
jar_sha256 = "4a87d5b1ca996e5e46a99594cf3566ae16885d0cf00b381b5e9f816a0e0125b3",
|
||||||
jar_urls = [
|
jar_urls = [
|
||||||
"http://repo1.maven.org/maven2/com/google/guava/guava/23.0/guava-23.0.jar",
|
"http://repo1.maven.org/maven2/com/google/guava/guava/23.3-jre/guava-23.3-jre.jar",
|
||||||
"http://domain-registry-maven.storage.googleapis.com/repo1.maven.org/maven2/com/google/guava/guava/23.0/guava-23.0.jar",
|
"http://maven.ibiblio.org/maven2/com/google/guava/guava/23.3-jre/guava-23.3-jre.jar",
|
||||||
],
|
],
|
||||||
licenses = ["notice"], # The Apache Software License, Version 2.0
|
licenses = ["notice"], # The Apache Software License, Version 2.0
|
||||||
exports = [
|
exports = [
|
||||||
|
@ -1021,10 +1021,10 @@ def com_google_guava():
|
||||||
def com_google_guava_testlib():
|
def com_google_guava_testlib():
|
||||||
java_import_external(
|
java_import_external(
|
||||||
name = "com_google_guava_testlib",
|
name = "com_google_guava_testlib",
|
||||||
jar_sha256 = "7e328d0f89a5ea103de4f9b689130eb555ff277e83bf86294bc14c2c40a59a80",
|
jar_sha256 = "377c60720828a655ffd0f64d8b64643962b2957635323ddc9c5223827f6e5482",
|
||||||
jar_urls = [
|
jar_urls = [
|
||||||
"http://repo1.maven.org/maven2/com/google/guava/guava-testlib/23.0/guava-testlib-23.0.jar",
|
"http://maven.ibiblio.org/maven2/com/google/guava/guava-testlib/23.3-jre/guava-testlib-23.3-jre.jar",
|
||||||
"http://domain-registry-maven.storage.googleapis.com/repo1.maven.org/maven2/com/google/guava/guava-testlib/23.0/guava-testlib-23.0.jar",
|
"http://repo1.maven.org/maven2/com/google/guava/guava-testlib/23.3-jre/guava-testlib-23.3-jre.jar",
|
||||||
],
|
],
|
||||||
licenses = ["notice"], # The Apache Software License, Version 2.0
|
licenses = ["notice"], # The Apache Software License, Version 2.0
|
||||||
testonly_ = True,
|
testonly_ = True,
|
||||||
|
|
|
@ -16,6 +16,7 @@ package google.registry.flows.host;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static google.registry.flows.host.HostFlowUtils.validateHostName;
|
import static google.registry.flows.host.HostFlowUtils.validateHostName;
|
||||||
|
import static google.registry.testing.JUnitBackports.assertThrows;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import google.registry.flows.host.HostFlowUtils.HostNameNotLowerCaseException;
|
import google.registry.flows.host.HostFlowUtils.HostNameNotLowerCaseException;
|
||||||
|
@ -25,8 +26,6 @@ import google.registry.flows.host.HostFlowUtils.HostNameTooLongException;
|
||||||
import google.registry.flows.host.HostFlowUtils.HostNameTooShallowException;
|
import google.registry.flows.host.HostFlowUtils.HostNameTooShallowException;
|
||||||
import google.registry.flows.host.HostFlowUtils.InvalidHostNameException;
|
import google.registry.flows.host.HostFlowUtils.InvalidHostNameException;
|
||||||
import google.registry.testing.AppEngineRule;
|
import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.ExceptionRule;
|
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
@ -36,8 +35,6 @@ import org.junit.runners.JUnit4;
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
public class HostFlowUtilsTest {
|
public class HostFlowUtilsTest {
|
||||||
|
|
||||||
@Rule public final ExceptionRule thrown = new ExceptionRule();
|
|
||||||
|
|
||||||
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -46,47 +43,53 @@ public class HostFlowUtilsTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
public void test_validExternalHostNameOnRegistrySuffixList_validates() throws Exception {
|
||||||
// TODO(b/63128999): Fix handling of public suffix lists so that hostnames that aren't on
|
|
||||||
// effective TLDs validate.
|
|
||||||
public void test_validExternalHostNameOnPublicSuffixList_validates() throws Exception {
|
|
||||||
assertThat(validateHostName("host.blogspot.com").toString()).isEqualTo("host.blogspot.com");
|
assertThat(validateHostName("host.blogspot.com").toString()).isEqualTo("host.blogspot.com");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_validExternalHostNameOnRegistrySuffixList_multipartTLD_validates()
|
||||||
|
throws Exception {
|
||||||
|
assertThat(validateHostName("ns1.host.co.uk").toString()).isEqualTo("ns1.host.co.uk");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_validExternalHostNameOnRegistrySuffixList_multipartTLD_tooShallow()
|
||||||
|
throws Exception {
|
||||||
|
assertThrows(
|
||||||
|
HostNameTooShallowException.class, () -> validateHostName("host.co.uk").toString());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_validateHostName_hostNameTooLong() throws Exception {
|
public void test_validateHostName_hostNameTooLong() throws Exception {
|
||||||
thrown.expect(HostNameTooLongException.class);
|
assertThrows(
|
||||||
validateHostName(Strings.repeat("na", 200) + ".wat.man");
|
HostNameTooLongException.class,
|
||||||
|
() -> validateHostName(Strings.repeat("na", 200) + ".wat.man"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_validateHostName_hostNameNotLowerCase() throws Exception {
|
public void test_validateHostName_hostNameNotLowerCase() throws Exception {
|
||||||
thrown.expect(HostNameNotLowerCaseException.class);
|
assertThrows(HostNameNotLowerCaseException.class, () -> validateHostName("NA.CAPS.TLD"));
|
||||||
validateHostName("NA.CAPS.TLD");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_validateHostName_hostNameNotPunyCoded() throws Exception {
|
public void test_validateHostName_hostNameNotPunyCoded() throws Exception {
|
||||||
thrown.expect(HostNameNotPunyCodedException.class);
|
assertThrows(
|
||||||
validateHostName("motörhead.death.metal");
|
HostNameNotPunyCodedException.class, () -> validateHostName("motörhead.death.metal"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_validateHostName_hostNameNotNormalized() throws Exception {
|
public void test_validateHostName_hostNameNotNormalized() throws Exception {
|
||||||
thrown.expect(HostNameNotNormalizedException.class);
|
assertThrows(HostNameNotNormalizedException.class, () -> validateHostName("root.node.yeah."));
|
||||||
validateHostName("root.node.yeah.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_validateHostName_hostNameHasLeadingHyphen() throws Exception {
|
public void test_validateHostName_hostNameHasLeadingHyphen() throws Exception {
|
||||||
thrown.expect(InvalidHostNameException.class);
|
assertThrows(InvalidHostNameException.class, () -> validateHostName("-giga.mega.tld"));
|
||||||
validateHostName("-giga.mega.tld");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_validateHostName_hostNameTooShallow() throws Exception {
|
public void test_validateHostName_hostNameTooShallow() throws Exception {
|
||||||
thrown.expect(HostNameTooShallowException.class);
|
assertThrows(HostNameTooShallowException.class, () -> validateHostName("domain.tld"));
|
||||||
validateHostName("domain.tld");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue