diff --git a/.github/badges/jacoco.svg b/.github/badges/jacoco.svg
index de06873..65ea9eb 100644
--- a/.github/badges/jacoco.svg
+++ b/.github/badges/jacoco.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/main/java/io/github/pixee/security/HostValidator.java b/src/main/java/io/github/pixee/security/HostValidator.java
index dc5e764..80eb132 100644
--- a/src/main/java/io/github/pixee/security/HostValidator.java
+++ b/src/main/java/io/github/pixee/security/HostValidator.java
@@ -47,4 +47,16 @@ public boolean isAllowed(final String host) {
static HostValidator fromAllowedHostPattern(final Pattern allowPattern) {
return new PatternBasedHostValidator(allowPattern);
}
+
+ /**
+ * Return a {@link HostValidator} that will assure a given domain is within the allowed domain. For example, given
+ * a domain of "good.com", this validator will allow "good.com", "www.good.com", "internal.good.com", etc.
+ *
+ * @param domainName the domain to allow, e.g., "good.com", or "internal-host"
+ * @return a validator that will only allow hosts within the given domain space
+ */
+ static HostValidator fromAllowedHostDomain(final String domainName) {
+ Pattern p = Pattern.compile("(.*\\." + Pattern.quote(domainName) + "|" + Pattern.quote(domainName) +")");
+ return new PatternBasedHostValidator(p);
+ }
}
diff --git a/src/test/java/io/github/pixee/security/UrlsTest.java b/src/test/java/io/github/pixee/security/UrlsTest.java
index 39a1fa0..c96972e 100644
--- a/src/test/java/io/github/pixee/security/UrlsTest.java
+++ b/src/test/java/io/github/pixee/security/UrlsTest.java
@@ -1,18 +1,19 @@
package io.github.pixee.security;
-import static io.github.pixee.security.J8ApiBridge.setOf;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.*;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.regex.Pattern;
import java.util.stream.Stream;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
+
+import static io.github.pixee.security.J8ApiBridge.setOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.junit.jupiter.api.Assertions.assertThrows;
final class UrlsTest {
@@ -138,6 +139,21 @@ void it_disallows_bad_domains() throws MalformedURLException {
() -> {
Urls.create("https://evil.com/", setOf(UrlProtocol.HTTPS), allowsOnlyGoodDotCom);
});
+
+ HostValidator allowsOnlyGoodDotComByDomainString = HostValidator.fromAllowedHostDomain("good.com");
+ Urls.create("https://good.com/", setOf(UrlProtocol.HTTPS), allowsOnlyGoodDotComByDomainString);
+ Urls.create("https://sub.good.com/", setOf(UrlProtocol.HTTPS), allowsOnlyGoodDotComByDomainString);
+ Urls.create("https://different-sub-123.good.com/", setOf(UrlProtocol.HTTPS), allowsOnlyGoodDotComByDomainString);
+ Urls.create("https://.good.com/", setOf(UrlProtocol.HTTPS), allowsOnlyGoodDotComByDomainString);
+
+ Stream.of("https://goodAcom/", "https://evil.com", "https://good.com.evil", "https://good.com.").forEach(badDomain -> {
+ assertThrows(
+ SecurityException.class,
+ () -> {
+ Urls.create(badDomain, setOf(UrlProtocol.HTTPS), allowsOnlyGoodDotComByDomainString);
+ });
+ });
+
}
@Test