Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ protected void validateOrigin(String origin) throws ServerTransportSecurityExcep
else if (allowed.endsWith(":*")) {
// Wildcard port pattern: "http://example.com:*"
String baseOrigin = allowed.substring(0, allowed.length() - 2);
if (origin.equals(baseOrigin) || origin.startsWith(baseOrigin + ":")) {
if (origin.equals(baseOrigin) || matchesWithPort(origin, baseOrigin)) {
return;
}
}
Expand Down Expand Up @@ -121,7 +121,7 @@ private void validateHost(String host) throws ServerTransportSecurityException {
else if (allowed.endsWith(":*")) {
// Wildcard port pattern: "example.com:*"
String baseHost = allowed.substring(0, allowed.length() - 2);
if (host.equals(baseHost) || host.startsWith(baseHost + ":")) {
if (host.equals(baseHost) || matchesWithPort(host, baseHost)) {
return;
}
}
Expand All @@ -130,6 +130,28 @@ else if (allowed.endsWith(":*")) {
throw new ServerTransportSecurityException(421, "Invalid Host header");
}

/**
* Checks that {@code actual} is {@code allowed} followed by {@code ":"} and a valid
* port: 1 to 5 ASCII digits, in the range 1-65535.
*/
private static boolean matchesWithPort(String actual, String allowed) {
if (!actual.startsWith(allowed + ":")) {
return false;
}
String port = actual.substring(allowed.length() + 1);
if (port.isEmpty() || port.length() > 5) {
return false;
}
for (int i = 0; i < port.length(); i++) {
char c = port.charAt(i);
if (c < '0' || c > '9') {
return false;
}
}
int portNumber = Integer.parseInt(port);
return portNumber >= 1 && portNumber <= 65535;
}

/**
* Creates a new builder for constructing a DefaultServerTransportSecurityValidator.
* @return A new builder instance
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
Expand Down Expand Up @@ -118,6 +120,25 @@ void differentPortWithWildcard() {
assertThatCode(() -> wildcardValidator.validate(accessor)).doesNotThrowAnyException();
}

@ParameterizedTest
@ValueSource(strings = { "http://localhost:1", "http://localhost:65535" })
void boundaryPortsWithWildcard(String origin) {
var accessor = originAccessor(origin);

assertThatCode(() -> wildcardValidator.validate(accessor)).doesNotThrowAnyException();
}

@ParameterizedTest
@ValueSource(strings = { "http://localhost:", "http://localhost:evil.com", "http://localhost:3000.evil.com",
"http://localhost:@evil.com", "http://localhost:80a", "http://localhost: 80",
"http://localhost:3000/path", "http://localhost:0", "http://localhost:65536",
"http://localhost:123456", "http://localhost:-1", "http://localhost:+80" })
void invalidPortWithWildcard(String origin) {
var accessor = originAccessor(origin);

assertThatThrownBy(() -> wildcardValidator.validate(accessor)).isEqualTo(INVALID_ORIGIN);
}

@Test
void differentHostWithWildcard() {
var accessor = originAccessor("http://example.com:3000");
Expand Down Expand Up @@ -273,6 +294,33 @@ void noPort() {
assertThatCode(() -> wildcardHostValidator.validate(accessor)).doesNotThrowAnyException();
}

@ParameterizedTest
@ValueSource(strings = { "localhost:1", "localhost:65535" })
void boundaryPorts(String host) {
var accessor = hostAccessor(host);

assertThatCode(() -> wildcardHostValidator.validate(accessor)).doesNotThrowAnyException();
}

@ParameterizedTest
@ValueSource(strings = { "localhost:", "localhost:evil.com", "localhost:3000.evil.com",
"localhost:@evil.com", "localhost:80a", "localhost: 80", "localhost:3000/path", "localhost:0",
"localhost:65536", "localhost:123456", "localhost:-1", "localhost:+80" })
void invalidPort(String host) {
var accessor = hostAccessor(host);

assertThatThrownBy(() -> wildcardHostValidator.validate(accessor)).isEqualTo(INVALID_HOST);
}

@ParameterizedTest
@ValueSource(strings = { "127.0.0.1:evil.com", "127.0.0.1:80.evil.com", "127.0.0.1:@evil.com" })
void nonNumericPortIpv4(String host) {
var ipValidator = DefaultServerTransportSecurityValidator.builder().allowedHost("127.0.0.1:*").build();

assertThatThrownBy(() -> ipValidator.validate(hostAccessor(host))).isEqualTo(INVALID_HOST);
assertThatCode(() -> ipValidator.validate(hostAccessor("127.0.0.1:8080"))).doesNotThrowAnyException();
}

@Test
void differentHost() {
var accessor = hostAccessor("example.com:3000");
Expand Down
Loading