feat: introduce ServerHttpHeaderValidator replacing ServerTransportSecurityValidator
Same feature set as ServerTransportSecurityValidator but uses a lazy "header accessor" function to read header values instead of extracting all headers into a map. Matches more closely what modern frameworks and JDK APIs do. Fixes #870 Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
This commit is contained in:
parent
2bb1481ec3
commit
5be2fa0688
1 changed files with 470 additions and 168 deletions
|
|
@ -43,50 +43,50 @@ class DefaultServerTransportSecurityValidatorTests {
|
|||
|
||||
@Test
|
||||
void originHeaderMissing() {
|
||||
assertThatCode(() -> validator.validateHeaders(new HashMap<>())).doesNotThrowAnyException();
|
||||
assertThatCode(() -> validator.validate(emptyAccessor())).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void originHeaderListEmpty() {
|
||||
assertThatThrownBy(() -> validator.validateHeaders(Map.of("Origin", List.of()))).isEqualTo(INVALID_ORIGIN);
|
||||
assertThatCode(() -> validator.validate(headerAccessor())).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void caseInsensitive() {
|
||||
var headers = Map.of("origin", List.of("http://localhost:8080"));
|
||||
var accessor = headerAccessor("Origin", "http://localhost:8080");
|
||||
|
||||
assertThatCode(() -> validator.validateHeaders(headers)).doesNotThrowAnyException();
|
||||
assertThatCode(() -> validator.validate(accessor)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void exactMatch() {
|
||||
var headers = originHeader("http://localhost:8080");
|
||||
var accessor = originAccessor("http://localhost:8080");
|
||||
|
||||
assertThatCode(() -> validator.validateHeaders(headers)).doesNotThrowAnyException();
|
||||
assertThatCode(() -> validator.validate(accessor)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void differentPort() {
|
||||
|
||||
var headers = originHeader("http://localhost:3000");
|
||||
var accessor = originAccessor("http://localhost:3000");
|
||||
|
||||
assertThatThrownBy(() -> validator.validateHeaders(headers)).isEqualTo(INVALID_ORIGIN);
|
||||
assertThatThrownBy(() -> validator.validate(accessor)).isEqualTo(INVALID_ORIGIN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void differentHost() {
|
||||
|
||||
var headers = originHeader("http://example.com:8080");
|
||||
var accessor = originAccessor("http://example.com:8080");
|
||||
|
||||
assertThatThrownBy(() -> validator.validateHeaders(headers)).isEqualTo(INVALID_ORIGIN);
|
||||
assertThatThrownBy(() -> validator.validate(accessor)).isEqualTo(INVALID_ORIGIN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void differentScheme() {
|
||||
|
||||
var headers = originHeader("https://localhost:8080");
|
||||
var accessor = originAccessor("https://localhost:8080");
|
||||
|
||||
assertThatThrownBy(() -> validator.validateHeaders(headers)).isEqualTo(INVALID_ORIGIN);
|
||||
assertThatThrownBy(() -> validator.validate(accessor)).isEqualTo(INVALID_ORIGIN);
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
|
@ -99,37 +99,37 @@ class DefaultServerTransportSecurityValidatorTests {
|
|||
|
||||
@Test
|
||||
void anyPortWithWildcard() {
|
||||
var headers = originHeader("http://localhost:3000");
|
||||
var accessor = originAccessor("http://localhost:3000");
|
||||
|
||||
assertThatCode(() -> wildcardValidator.validateHeaders(headers)).doesNotThrowAnyException();
|
||||
assertThatCode(() -> wildcardValidator.validate(accessor)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void noPortWithWildcard() {
|
||||
var headers = originHeader("http://localhost");
|
||||
var accessor = originAccessor("http://localhost");
|
||||
|
||||
assertThatCode(() -> wildcardValidator.validateHeaders(headers)).doesNotThrowAnyException();
|
||||
assertThatCode(() -> wildcardValidator.validate(accessor)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void differentPortWithWildcard() {
|
||||
var headers = originHeader("http://localhost:8080");
|
||||
var accessor = originAccessor("http://localhost:8080");
|
||||
|
||||
assertThatCode(() -> wildcardValidator.validateHeaders(headers)).doesNotThrowAnyException();
|
||||
assertThatCode(() -> wildcardValidator.validate(accessor)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void differentHostWithWildcard() {
|
||||
var headers = originHeader("http://example.com:3000");
|
||||
var accessor = originAccessor("http://example.com:3000");
|
||||
|
||||
assertThatThrownBy(() -> wildcardValidator.validateHeaders(headers)).isEqualTo(INVALID_ORIGIN);
|
||||
assertThatThrownBy(() -> wildcardValidator.validate(accessor)).isEqualTo(INVALID_ORIGIN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void differentSchemeWithWildcard() {
|
||||
var headers = originHeader("https://localhost:3000");
|
||||
var accessor = originAccessor("https://localhost:3000");
|
||||
|
||||
assertThatThrownBy(() -> wildcardValidator.validateHeaders(headers)).isEqualTo(INVALID_ORIGIN);
|
||||
assertThatThrownBy(() -> wildcardValidator.validate(accessor)).isEqualTo(INVALID_ORIGIN);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -146,23 +146,23 @@ class DefaultServerTransportSecurityValidatorTests {
|
|||
|
||||
@Test
|
||||
void matchingOneOfMultiple() {
|
||||
var headers = originHeader("http://example.com:3000");
|
||||
var accessor = originAccessor("http://example.com:3000");
|
||||
|
||||
assertThatCode(() -> multipleOriginsValidator.validateHeaders(headers)).doesNotThrowAnyException();
|
||||
assertThatCode(() -> multipleOriginsValidator.validate(accessor)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchingWildcardInMultiple() {
|
||||
var headers = originHeader("http://myapp.example.com:9999");
|
||||
var accessor = originAccessor("http://myapp.example.com:9999");
|
||||
|
||||
assertThatCode(() -> multipleOriginsValidator.validateHeaders(headers)).doesNotThrowAnyException();
|
||||
assertThatCode(() -> multipleOriginsValidator.validate(accessor)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void notMatchingAny() {
|
||||
var headers = originHeader("http://malicious.example.com:1234");
|
||||
var accessor = originAccessor("http://malicious.example.com:1234");
|
||||
|
||||
assertThatThrownBy(() -> multipleOriginsValidator.validateHeaders(headers)).isEqualTo(INVALID_ORIGIN);
|
||||
assertThatThrownBy(() -> multipleOriginsValidator.validate(accessor)).isEqualTo(INVALID_ORIGIN);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -176,9 +176,9 @@ class DefaultServerTransportSecurityValidatorTests {
|
|||
.allowedOrigins(List.of("http://localhost:8080", "http://example.com:*"))
|
||||
.build();
|
||||
|
||||
var headers = originHeader("http://example.com:3000");
|
||||
var accessor = originAccessor("http://example.com:3000");
|
||||
|
||||
assertThatCode(() -> validator.validateHeaders(headers)).doesNotThrowAnyException();
|
||||
assertThatCode(() -> validator.validate(accessor)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -188,11 +188,11 @@ class DefaultServerTransportSecurityValidatorTests {
|
|||
.allowedOrigins(List.of("http://example.com:*", "http://test.com:3000"))
|
||||
.build();
|
||||
|
||||
assertThatCode(() -> validator.validateHeaders(originHeader("http://localhost:8080")))
|
||||
assertThatCode(() -> validator.validate(originAccessor("http://localhost:8080")))
|
||||
.doesNotThrowAnyException();
|
||||
assertThatCode(() -> validator.validateHeaders(originHeader("http://example.com:9999")))
|
||||
assertThatCode(() -> validator.validate(originAccessor("http://example.com:9999")))
|
||||
.doesNotThrowAnyException();
|
||||
assertThatCode(() -> validator.validateHeaders(originHeader("http://test.com:3000")))
|
||||
assertThatCode(() -> validator.validate(originAccessor("http://test.com:3000")))
|
||||
.doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
|
|
@ -210,45 +210,45 @@ class DefaultServerTransportSecurityValidatorTests {
|
|||
|
||||
@Test
|
||||
void notConfigured() {
|
||||
assertThatCode(() -> validator.validateHeaders(new HashMap<>())).doesNotThrowAnyException();
|
||||
assertThatCode(() -> validator.validate(emptyAccessor())).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void missing() {
|
||||
assertThatThrownBy(() -> hostValidator.validateHeaders(new HashMap<>())).isEqualTo(INVALID_HOST);
|
||||
assertThatThrownBy(() -> hostValidator.validate(emptyAccessor())).isEqualTo(INVALID_HOST);
|
||||
}
|
||||
|
||||
@Test
|
||||
void listEmpty() {
|
||||
assertThatThrownBy(() -> hostValidator.validateHeaders(Map.of("Host", List.of()))).isEqualTo(INVALID_HOST);
|
||||
assertThatThrownBy(() -> hostValidator.validate(headerAccessor())).isEqualTo(INVALID_HOST);
|
||||
}
|
||||
|
||||
@Test
|
||||
void caseInsensitive() {
|
||||
var headers = Map.of("host", List.of("localhost:8080"));
|
||||
var accessor = headerAccessor("Host", "localhost:8080");
|
||||
|
||||
assertThatCode(() -> hostValidator.validateHeaders(headers)).doesNotThrowAnyException();
|
||||
assertThatCode(() -> hostValidator.validate(accessor)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void exactMatch() {
|
||||
var headers = hostHeader("localhost:8080");
|
||||
var accessor = hostAccessor("localhost:8080");
|
||||
|
||||
assertThatCode(() -> hostValidator.validateHeaders(headers)).doesNotThrowAnyException();
|
||||
assertThatCode(() -> hostValidator.validate(accessor)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void differentPort() {
|
||||
var headers = hostHeader("localhost:3000");
|
||||
var accessor = hostAccessor("localhost:3000");
|
||||
|
||||
assertThatThrownBy(() -> hostValidator.validateHeaders(headers)).isEqualTo(INVALID_HOST);
|
||||
assertThatThrownBy(() -> hostValidator.validate(accessor)).isEqualTo(INVALID_HOST);
|
||||
}
|
||||
|
||||
@Test
|
||||
void differentHost() {
|
||||
var headers = hostHeader("example.com:8080");
|
||||
var accessor = hostAccessor("example.com:8080");
|
||||
|
||||
assertThatThrownBy(() -> hostValidator.validateHeaders(headers)).isEqualTo(INVALID_HOST);
|
||||
assertThatThrownBy(() -> hostValidator.validate(accessor)).isEqualTo(INVALID_HOST);
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
|
@ -261,23 +261,23 @@ class DefaultServerTransportSecurityValidatorTests {
|
|||
|
||||
@Test
|
||||
void anyPort() {
|
||||
var headers = hostHeader("localhost:3000");
|
||||
var accessor = hostAccessor("localhost:3000");
|
||||
|
||||
assertThatCode(() -> wildcardHostValidator.validateHeaders(headers)).doesNotThrowAnyException();
|
||||
assertThatCode(() -> wildcardHostValidator.validate(accessor)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void noPort() {
|
||||
var headers = hostHeader("localhost");
|
||||
var accessor = hostAccessor("localhost");
|
||||
|
||||
assertThatCode(() -> wildcardHostValidator.validateHeaders(headers)).doesNotThrowAnyException();
|
||||
assertThatCode(() -> wildcardHostValidator.validate(accessor)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void differentHost() {
|
||||
var headers = hostHeader("example.com:3000");
|
||||
var accessor = hostAccessor("example.com:3000");
|
||||
|
||||
assertThatThrownBy(() -> wildcardHostValidator.validateHeaders(headers)).isEqualTo(INVALID_HOST);
|
||||
assertThatThrownBy(() -> wildcardHostValidator.validate(accessor)).isEqualTo(INVALID_HOST);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -293,30 +293,30 @@ class DefaultServerTransportSecurityValidatorTests {
|
|||
|
||||
@Test
|
||||
void exactMatch() {
|
||||
var headers = hostHeader("example.com:3000");
|
||||
var accessor = hostAccessor("example.com:3000");
|
||||
|
||||
assertThatCode(() -> multipleHostsValidator.validateHeaders(headers)).doesNotThrowAnyException();
|
||||
assertThatCode(() -> multipleHostsValidator.validate(accessor)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void wildcard() {
|
||||
var headers = hostHeader("myapp.example.com:9999");
|
||||
var accessor = hostAccessor("myapp.example.com:9999");
|
||||
|
||||
assertThatCode(() -> multipleHostsValidator.validateHeaders(headers)).doesNotThrowAnyException();
|
||||
assertThatCode(() -> multipleHostsValidator.validate(accessor)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void differentHost() {
|
||||
var headers = hostHeader("malicious.example.com:3000");
|
||||
var accessor = hostAccessor("malicious.example.com:3000");
|
||||
|
||||
assertThatThrownBy(() -> multipleHostsValidator.validateHeaders(headers)).isEqualTo(INVALID_HOST);
|
||||
assertThatThrownBy(() -> multipleHostsValidator.validate(accessor)).isEqualTo(INVALID_HOST);
|
||||
}
|
||||
|
||||
@Test
|
||||
void differentPort() {
|
||||
var headers = hostHeader("localhost:8080");
|
||||
var accessor = hostAccessor("localhost:8080");
|
||||
|
||||
assertThatThrownBy(() -> multipleHostsValidator.validateHeaders(headers)).isEqualTo(INVALID_HOST);
|
||||
assertThatThrownBy(() -> multipleHostsValidator.validate(accessor)).isEqualTo(INVALID_HOST);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -330,10 +330,8 @@ class DefaultServerTransportSecurityValidatorTests {
|
|||
.allowedHosts(List.of("localhost:8080", "example.com:*"))
|
||||
.build();
|
||||
|
||||
assertThatCode(() -> validator.validateHeaders(hostHeader("example.com:3000")))
|
||||
.doesNotThrowAnyException();
|
||||
assertThatCode(() -> validator.validateHeaders(hostHeader("localhost:8080")))
|
||||
.doesNotThrowAnyException();
|
||||
assertThatCode(() -> validator.validate(hostAccessor("example.com:3000"))).doesNotThrowAnyException();
|
||||
assertThatCode(() -> validator.validate(hostAccessor("localhost:8080"))).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -343,11 +341,9 @@ class DefaultServerTransportSecurityValidatorTests {
|
|||
.allowedHosts(List.of("example.com:*", "test.com:3000"))
|
||||
.build();
|
||||
|
||||
assertThatCode(() -> validator.validateHeaders(hostHeader("localhost:8080")))
|
||||
.doesNotThrowAnyException();
|
||||
assertThatCode(() -> validator.validateHeaders(hostHeader("example.com:9999")))
|
||||
.doesNotThrowAnyException();
|
||||
assertThatCode(() -> validator.validateHeaders(hostHeader("test.com:3000"))).doesNotThrowAnyException();
|
||||
assertThatCode(() -> validator.validate(hostAccessor("localhost:8080"))).doesNotThrowAnyException();
|
||||
assertThatCode(() -> validator.validate(hostAccessor("example.com:9999"))).doesNotThrowAnyException();
|
||||
assertThatCode(() -> validator.validate(hostAccessor("test.com:3000"))).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -365,60 +361,195 @@ class DefaultServerTransportSecurityValidatorTests {
|
|||
|
||||
@Test
|
||||
void bothValid() {
|
||||
var header = headers("http://localhost:8080", "localhost:8080");
|
||||
var accessor = combinedAccessor("http://localhost:8080", "localhost:8080");
|
||||
|
||||
assertThatCode(() -> combinedValidator.validateHeaders(header)).doesNotThrowAnyException();
|
||||
assertThatCode(() -> combinedValidator.validate(accessor)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void originValidHostInvalid() {
|
||||
var header = headers("http://localhost:8080", "malicious.example.com:8080");
|
||||
var accessor = combinedAccessor("http://localhost:8080", "malicious.example.com:8080");
|
||||
|
||||
assertThatThrownBy(() -> combinedValidator.validateHeaders(header)).isEqualTo(INVALID_HOST);
|
||||
assertThatThrownBy(() -> combinedValidator.validate(accessor)).isEqualTo(INVALID_HOST);
|
||||
}
|
||||
|
||||
@Test
|
||||
void originInvalidHostValid() {
|
||||
var header = headers("http://malicious.example.com:8080", "localhost:8080");
|
||||
var accessor = combinedAccessor("http://malicious.example.com:8080", "localhost:8080");
|
||||
|
||||
assertThatThrownBy(() -> combinedValidator.validateHeaders(header)).isEqualTo(INVALID_ORIGIN);
|
||||
assertThatThrownBy(() -> combinedValidator.validate(accessor)).isEqualTo(INVALID_ORIGIN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void originMissingHostValid() {
|
||||
// Origin missing is OK (same-origin request)
|
||||
var header = headers(null, "localhost:8080");
|
||||
var accessor = combinedAccessor(null, "localhost:8080");
|
||||
|
||||
assertThatCode(() -> combinedValidator.validateHeaders(header)).doesNotThrowAnyException();
|
||||
assertThatCode(() -> combinedValidator.validate(accessor)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void originValidHostMissing() {
|
||||
// Host missing is NOT OK when allowedHosts is configured
|
||||
var header = headers("http://localhost:8080", null);
|
||||
var accessor = combinedAccessor("http://localhost:8080", null);
|
||||
|
||||
assertThatThrownBy(() -> combinedValidator.validateHeaders(header)).isEqualTo(INVALID_HOST);
|
||||
assertThatThrownBy(() -> combinedValidator.validate(accessor)).isEqualTo(INVALID_HOST);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Map<String, List<String>> originHeader(String origin) {
|
||||
return Map.of("Origin", List.of(origin));
|
||||
@Nested
|
||||
class DeprecatedMapBasedApi {
|
||||
|
||||
@Test
|
||||
void originValidation() {
|
||||
Map<String, List<String>> headers = new HashMap<>();
|
||||
headers.put("Origin", List.of("http://localhost:8080"));
|
||||
|
||||
assertThatCode(() -> validator.validateHeaders(headers)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void originRejected() {
|
||||
Map<String, List<String>> headers = new HashMap<>();
|
||||
headers.put("Origin", List.of("http://malicious.example.com"));
|
||||
|
||||
assertThatThrownBy(() -> validator.validateHeaders(headers)).isEqualTo(INVALID_ORIGIN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void caseInsensitiveHeaderLookup() {
|
||||
Map<String, List<String>> headers = new HashMap<>();
|
||||
headers.put("origin", List.of("http://localhost:8080"));
|
||||
|
||||
assertThatCode(() -> validator.validateHeaders(headers)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void hostValidation() {
|
||||
DefaultServerTransportSecurityValidator hostValidator = DefaultServerTransportSecurityValidator.builder()
|
||||
.allowedHost("localhost:8080")
|
||||
.build();
|
||||
|
||||
Map<String, List<String>> headers = new HashMap<>();
|
||||
headers.put("Host", List.of("localhost:8080"));
|
||||
|
||||
assertThatCode(() -> hostValidator.validateHeaders(headers)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void hostRejected() {
|
||||
DefaultServerTransportSecurityValidator hostValidator = DefaultServerTransportSecurityValidator.builder()
|
||||
.allowedHost("localhost:8080")
|
||||
.build();
|
||||
|
||||
Map<String, List<String>> headers = new HashMap<>();
|
||||
headers.put("Host", List.of("malicious.com:8080"));
|
||||
|
||||
assertThatThrownBy(() -> hostValidator.validateHeaders(headers)).isEqualTo(INVALID_HOST);
|
||||
}
|
||||
|
||||
@Test
|
||||
void emptyHeaders() {
|
||||
assertThatCode(() -> validator.validateHeaders(new HashMap<>())).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void combinedOriginAndHost() {
|
||||
DefaultServerTransportSecurityValidator combinedValidator = DefaultServerTransportSecurityValidator
|
||||
.builder()
|
||||
.allowedOrigin("http://localhost:*")
|
||||
.allowedHost("localhost:*")
|
||||
.build();
|
||||
|
||||
Map<String, List<String>> headers = new HashMap<>();
|
||||
headers.put("Origin", List.of("http://localhost:8080"));
|
||||
headers.put("Host", List.of("localhost:8080"));
|
||||
|
||||
assertThatCode(() -> combinedValidator.validateHeaders(headers)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Map<String, List<String>> hostHeader(String host) {
|
||||
return Map.of("Host", List.of(host));
|
||||
@Nested
|
||||
class ValidatorCompatibility {
|
||||
|
||||
@Test
|
||||
void noopAcceptsAll() {
|
||||
assertThatCode(() -> ServerHttpHeaderValidator.NOOP.validate(emptyAccessor())).doesNotThrowAnyException();
|
||||
assertThatCode(() -> ServerTransportSecurityValidator.NOOP.validateHeaders(new HashMap<>()))
|
||||
.doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void legacyValidatorAdaptsToHeaderAccessor() {
|
||||
ServerTransportSecurityValidator legacyValidator = headers -> {
|
||||
List<String> origins = headers.getOrDefault("Origin", List.of());
|
||||
if (!origins.isEmpty() && origins.get(0).contains("evil")) {
|
||||
throw new ServerTransportSecurityException(403, "Invalid Origin header");
|
||||
}
|
||||
};
|
||||
ServerHttpHeaderValidator headerValidator = ServerTransportSecurityValidator
|
||||
.toHttpHeaderValidator(legacyValidator);
|
||||
|
||||
assertThatCode(() -> headerValidator.validate(originAccessor("http://good.example.com")))
|
||||
.doesNotThrowAnyException();
|
||||
|
||||
assertThatThrownBy(() -> headerValidator.validate(originAccessor("http://evil.example.com")))
|
||||
.isEqualTo(INVALID_ORIGIN);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Map<String, List<String>> headers(String origin, String host) {
|
||||
var map = new HashMap<String, List<String>>();
|
||||
private static HeaderAccessor emptyAccessor() {
|
||||
return headerAccessor();
|
||||
}
|
||||
|
||||
private static HeaderAccessor headerAccessor(String... namesAndValues) {
|
||||
Map<String, List<String>> headers = new HashMap<>();
|
||||
for (int i = 0; i < namesAndValues.length; i += 2) {
|
||||
headers.put(namesAndValues[i], List.of(namesAndValues[i + 1]));
|
||||
}
|
||||
return new HeaderAccessor() {
|
||||
@Override
|
||||
public List<String> getHeader(String name) {
|
||||
return headers.getOrDefault(name, List.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getHeaderNames() {
|
||||
return List.copyOf(headers.keySet());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static HeaderAccessor originAccessor(String origin) {
|
||||
return headerAccessor("Origin", origin);
|
||||
}
|
||||
|
||||
private static HeaderAccessor hostAccessor(String host) {
|
||||
return headerAccessor("Host", host);
|
||||
}
|
||||
|
||||
private static HeaderAccessor combinedAccessor(String origin, String host) {
|
||||
Map<String, List<String>> headers = new HashMap<>();
|
||||
if (origin != null) {
|
||||
map.put("Origin", List.of(origin));
|
||||
headers.put("Origin", List.of(origin));
|
||||
}
|
||||
if (host != null) {
|
||||
map.put("Host", List.of(host));
|
||||
headers.put("Host", List.of(host));
|
||||
}
|
||||
return map;
|
||||
return new HeaderAccessor() {
|
||||
@Override
|
||||
public List<String> getHeader(String name) {
|
||||
return headers.getOrDefault(name, List.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getHeaderNames() {
|
||||
return List.copyOf(headers.keySet());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue