Remove individual detection of forwarded headers

This commit removes all places where forwarded headers are checked
implicitly, on an ad-hoc basis.

ForwardedHeaderFilter is expected to be used instead providing
centralized control over using or discarding such headers.

Issue: SPR-16668
This commit is contained in:
Rossen Stoyanchev
2018-05-11 09:31:39 -04:00
parent 82a8e42ff9
commit 4da43de7e1
14 changed files with 251 additions and 299 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,15 +16,19 @@
package org.springframework.web.cors.reactive;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Test;
import reactor.core.publisher.Mono;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.web.test.server.MockServerWebExchange;
import org.springframework.web.filter.reactive.ForwardedHeaderFilter;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.get;
import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.options;
import static org.junit.Assert.*;
import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.*;
/**
* Test case for reactive {@link CorsUtils}.
@@ -35,19 +39,19 @@ public class CorsUtilsTests {
@Test
public void isCorsRequest() {
MockServerHttpRequest request = get("/").header(HttpHeaders.ORIGIN, "http://domain.com").build();
ServerHttpRequest request = get("/").header(HttpHeaders.ORIGIN, "http://domain.com").build();
assertTrue(CorsUtils.isCorsRequest(request));
}
@Test
public void isNotCorsRequest() {
MockServerHttpRequest request = get("/").build();
ServerHttpRequest request = get("/").build();
assertFalse(CorsUtils.isCorsRequest(request));
}
@Test
public void isPreFlightRequest() {
MockServerHttpRequest request = options("/")
ServerHttpRequest request = options("/")
.header(HttpHeaders.ORIGIN, "http://domain.com")
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET")
.build();
@@ -56,7 +60,7 @@ public class CorsUtilsTests {
@Test
public void isNotPreFlightRequest() {
MockServerHttpRequest request = get("/").build();
ServerHttpRequest request = get("/").build();
assertFalse(CorsUtils.isPreFlightRequest(request));
request = options("/").header(HttpHeaders.ORIGIN, "http://domain.com").build();
@@ -68,31 +72,35 @@ public class CorsUtilsTests {
@Test // SPR-16262
public void isSameOriginWithXForwardedHeaders() {
assertTrue(checkSameOriginWithXForwardedHeaders("mydomain1.com", -1, "https", null, -1, "https://mydomain1.com"));
assertTrue(checkSameOriginWithXForwardedHeaders("mydomain1.com", 123, "https", null, -1, "https://mydomain1.com"));
assertTrue(checkSameOriginWithXForwardedHeaders("mydomain1.com", -1, "https", "mydomain2.com", -1, "https://mydomain2.com"));
assertTrue(checkSameOriginWithXForwardedHeaders("mydomain1.com", 123, "https", "mydomain2.com", -1, "https://mydomain2.com"));
assertTrue(checkSameOriginWithXForwardedHeaders("mydomain1.com", -1, "https", "mydomain2.com", 456, "https://mydomain2.com:456"));
assertTrue(checkSameOriginWithXForwardedHeaders("mydomain1.com", 123, "https", "mydomain2.com", 456, "https://mydomain2.com:456"));
String server = "mydomain1.com";
testWithXForwardedHeaders(server, -1, "https", null, -1, "https://mydomain1.com");
testWithXForwardedHeaders(server, 123, "https", null, -1, "https://mydomain1.com");
testWithXForwardedHeaders(server, -1, "https", "mydomain2.com", -1, "https://mydomain2.com");
testWithXForwardedHeaders(server, 123, "https", "mydomain2.com", -1, "https://mydomain2.com");
testWithXForwardedHeaders(server, -1, "https", "mydomain2.com", 456, "https://mydomain2.com:456");
testWithXForwardedHeaders(server, 123, "https", "mydomain2.com", 456, "https://mydomain2.com:456");
}
@Test // SPR-16262
public void isSameOriginWithForwardedHeader() {
assertTrue(checkSameOriginWithForwardedHeader("mydomain1.com", -1, "proto=https", "https://mydomain1.com"));
assertTrue(checkSameOriginWithForwardedHeader("mydomain1.com", 123, "proto=https", "https://mydomain1.com"));
assertTrue(checkSameOriginWithForwardedHeader("mydomain1.com", -1, "proto=https; host=mydomain2.com", "https://mydomain2.com"));
assertTrue(checkSameOriginWithForwardedHeader("mydomain1.com", 123, "proto=https; host=mydomain2.com", "https://mydomain2.com"));
assertTrue(checkSameOriginWithForwardedHeader("mydomain1.com", -1, "proto=https; host=mydomain2.com:456", "https://mydomain2.com:456"));
assertTrue(checkSameOriginWithForwardedHeader("mydomain1.com", 123, "proto=https; host=mydomain2.com:456", "https://mydomain2.com:456"));
String server = "mydomain1.com";
testWithForwardedHeader(server, -1, "proto=https", "https://mydomain1.com");
testWithForwardedHeader(server, 123, "proto=https", "https://mydomain1.com");
testWithForwardedHeader(server, -1, "proto=https; host=mydomain2.com", "https://mydomain2.com");
testWithForwardedHeader(server, 123, "proto=https; host=mydomain2.com", "https://mydomain2.com");
testWithForwardedHeader(server, -1, "proto=https; host=mydomain2.com:456", "https://mydomain2.com:456");
testWithForwardedHeader(server, 123, "proto=https; host=mydomain2.com:456", "https://mydomain2.com:456");
}
private boolean checkSameOriginWithXForwardedHeaders(String serverName, int port, String forwardedProto, String forwardedHost, int forwardedPort, String originHeader) {
private void testWithXForwardedHeaders(String serverName, int port,
String forwardedProto, String forwardedHost, int forwardedPort, String originHeader) {
String url = "http://" + serverName;
if (port != -1) {
url = url + ":" + port;
}
MockServerHttpRequest.BaseBuilder<?> builder = get(url)
.header(HttpHeaders.ORIGIN, originHeader);
MockServerHttpRequest.BaseBuilder<?> builder = get(url).header(HttpHeaders.ORIGIN, originHeader);
if (forwardedProto != null) {
builder.header("X-Forwarded-Proto", forwardedProto);
}
@@ -102,18 +110,36 @@ public class CorsUtilsTests {
if (forwardedPort != -1) {
builder.header("X-Forwarded-Port", String.valueOf(forwardedPort));
}
return CorsUtils.isSameOrigin(builder.build());
ServerHttpRequest request = adaptFromForwardedHeaders(builder);
assertTrue(CorsUtils.isSameOrigin(request));
}
private boolean checkSameOriginWithForwardedHeader(String serverName, int port, String forwardedHeader, String originHeader) {
private void testWithForwardedHeader(String serverName, int port,
String forwardedHeader, String originHeader) {
String url = "http://" + serverName;
if (port != -1) {
url = url + ":" + port;
}
MockServerHttpRequest.BaseBuilder<?> builder = get(url)
.header("Forwarded", forwardedHeader)
.header(HttpHeaders.ORIGIN, originHeader);
return CorsUtils.isSameOrigin(builder.build());
ServerHttpRequest request = adaptFromForwardedHeaders(builder);
assertTrue(CorsUtils.isSameOrigin(request));
}
// SPR-16668
private ServerHttpRequest adaptFromForwardedHeaders(MockServerHttpRequest.BaseBuilder<?> builder) {
AtomicReference<ServerHttpRequest> requestRef = new AtomicReference<>();
MockServerWebExchange exchange = MockServerWebExchange.from(builder);
new ForwardedHeaderFilter().filter(exchange, exchange2 -> {
requestRef.set(exchange2.getRequest());
return Mono.empty();
}).block();
return requestRef.get();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,19 +21,20 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.junit.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.mock.web.test.MockFilterChain;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse;
import org.springframework.util.MultiValueMap;
import org.springframework.web.filter.ForwardedHeaderFilter;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
/**
* @author Juergen Hoeller
@@ -141,23 +142,25 @@ public class WebUtilsTests {
}
@Test // SPR-16262
public void isSameOriginWithXForwardedHeaders() {
assertTrue(checkSameOriginWithXForwardedHeaders("mydomain1.com", -1, "https", null, -1, "https://mydomain1.com"));
assertTrue(checkSameOriginWithXForwardedHeaders("mydomain1.com", 123, "https", null, -1, "https://mydomain1.com"));
assertTrue(checkSameOriginWithXForwardedHeaders("mydomain1.com", -1, "https", "mydomain2.com", -1, "https://mydomain2.com"));
assertTrue(checkSameOriginWithXForwardedHeaders("mydomain1.com", 123, "https", "mydomain2.com", -1, "https://mydomain2.com"));
assertTrue(checkSameOriginWithXForwardedHeaders("mydomain1.com", -1, "https", "mydomain2.com", 456, "https://mydomain2.com:456"));
assertTrue(checkSameOriginWithXForwardedHeaders("mydomain1.com", 123, "https", "mydomain2.com", 456, "https://mydomain2.com:456"));
public void isSameOriginWithXForwardedHeaders() throws Exception {
String server = "mydomain1.com";
testWithXForwardedHeaders(server, -1, "https", null, -1, "https://mydomain1.com");
testWithXForwardedHeaders(server, 123, "https", null, -1, "https://mydomain1.com");
testWithXForwardedHeaders(server, -1, "https", "mydomain2.com", -1, "https://mydomain2.com");
testWithXForwardedHeaders(server, 123, "https", "mydomain2.com", -1, "https://mydomain2.com");
testWithXForwardedHeaders(server, -1, "https", "mydomain2.com", 456, "https://mydomain2.com:456");
testWithXForwardedHeaders(server, 123, "https", "mydomain2.com", 456, "https://mydomain2.com:456");
}
@Test // SPR-16262
public void isSameOriginWithForwardedHeader() {
assertTrue(checkSameOriginWithForwardedHeader("mydomain1.com", -1, "proto=https", "https://mydomain1.com"));
assertTrue(checkSameOriginWithForwardedHeader("mydomain1.com", 123, "proto=https", "https://mydomain1.com"));
assertTrue(checkSameOriginWithForwardedHeader("mydomain1.com", -1, "proto=https; host=mydomain2.com", "https://mydomain2.com"));
assertTrue(checkSameOriginWithForwardedHeader("mydomain1.com", 123, "proto=https; host=mydomain2.com", "https://mydomain2.com"));
assertTrue(checkSameOriginWithForwardedHeader("mydomain1.com", -1, "proto=https; host=mydomain2.com:456", "https://mydomain2.com:456"));
assertTrue(checkSameOriginWithForwardedHeader("mydomain1.com", 123, "proto=https; host=mydomain2.com:456", "https://mydomain2.com:456"));
public void isSameOriginWithForwardedHeader() throws Exception {
String server = "mydomain1.com";
testWithForwardedHeader(server, -1, "proto=https", "https://mydomain1.com");
testWithForwardedHeader(server, 123, "proto=https", "https://mydomain1.com");
testWithForwardedHeader(server, -1, "proto=https; host=mydomain2.com", "https://mydomain2.com");
testWithForwardedHeader(server, 123, "proto=https; host=mydomain2.com", "https://mydomain2.com");
testWithForwardedHeader(server, -1, "proto=https; host=mydomain2.com:456", "https://mydomain2.com:456");
testWithForwardedHeader(server, 123, "proto=https; host=mydomain2.com:456", "https://mydomain2.com:456");
}
@@ -183,36 +186,53 @@ public class WebUtilsTests {
return WebUtils.isSameOrigin(request);
}
private boolean checkSameOriginWithXForwardedHeaders(String serverName, int port, String forwardedProto, String forwardedHost, int forwardedPort, String originHeader) {
MockHttpServletRequest servletRequest = new MockHttpServletRequest();
ServerHttpRequest request = new ServletServerHttpRequest(servletRequest);
servletRequest.setServerName(serverName);
private void testWithXForwardedHeaders(String serverName, int port, String forwardedProto,
String forwardedHost, int forwardedPort, String originHeader) throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setServerName(serverName);
if (port != -1) {
servletRequest.setServerPort(port);
request.setServerPort(port);
}
if (forwardedProto != null) {
servletRequest.addHeader("X-Forwarded-Proto", forwardedProto);
request.addHeader("X-Forwarded-Proto", forwardedProto);
}
if (forwardedHost != null) {
servletRequest.addHeader("X-Forwarded-Host", forwardedHost);
request.addHeader("X-Forwarded-Host", forwardedHost);
}
if (forwardedPort != -1) {
servletRequest.addHeader("X-Forwarded-Port", String.valueOf(forwardedPort));
request.addHeader("X-Forwarded-Port", String.valueOf(forwardedPort));
}
servletRequest.addHeader(HttpHeaders.ORIGIN, originHeader);
return WebUtils.isSameOrigin(request);
request.addHeader(HttpHeaders.ORIGIN, originHeader);
HttpServletRequest requestToUse = adaptFromForwardedHeaders(request);
ServerHttpRequest httpRequest = new ServletServerHttpRequest(requestToUse);
assertTrue(WebUtils.isSameOrigin(httpRequest));
}
private boolean checkSameOriginWithForwardedHeader(String serverName, int port, String forwardedHeader, String originHeader) {
MockHttpServletRequest servletRequest = new MockHttpServletRequest();
ServerHttpRequest request = new ServletServerHttpRequest(servletRequest);
servletRequest.setServerName(serverName);
private void testWithForwardedHeader(String serverName, int port, String forwardedHeader,
String originHeader) throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setServerName(serverName);
if (port != -1) {
servletRequest.setServerPort(port);
request.setServerPort(port);
}
servletRequest.addHeader("Forwarded", forwardedHeader);
servletRequest.addHeader(HttpHeaders.ORIGIN, originHeader);
return WebUtils.isSameOrigin(request);
request.addHeader("Forwarded", forwardedHeader);
request.addHeader(HttpHeaders.ORIGIN, originHeader);
HttpServletRequest requestToUse = adaptFromForwardedHeaders(request);
ServerHttpRequest httpRequest = new ServletServerHttpRequest(requestToUse);
assertTrue(WebUtils.isSameOrigin(httpRequest));
}
// SPR-16668
private HttpServletRequest adaptFromForwardedHeaders(HttpServletRequest request) throws Exception {
MockFilterChain chain = new MockFilterChain();
new ForwardedHeaderFilter().doFilter(request, new MockHttpServletResponse(), chain);
return (HttpServletRequest) chain.getRequest();
}
}