/* * Copyright 2002-2017 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. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.web.cors.reactive; import org.junit.Before; import org.junit.Test; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.server.ServerWebExchange; 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.springframework.http.HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS; import static org.springframework.http.HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN; import static org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS; import static org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD; /** * {@link DefaultCorsProcessor} tests with simple or pre-flight CORS request. * * @author Sebastien Deleuze */ public class DefaultCorsProcessorTests { private DefaultCorsProcessor processor; private CorsConfiguration conf; @Before public void setup() { this.conf = new CorsConfiguration(); this.processor = new DefaultCorsProcessor(); } @Test public void actualRequestWithOriginHeader() throws Exception { ServerWebExchange exchange = actualRequest(); this.processor.processRequest(this.conf, exchange); ServerHttpResponse response = exchange.getResponse(); assertFalse(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode()); } @Test public void actualRequestWithOriginHeaderAndNullConfig() throws Exception { ServerWebExchange exchange = actualRequest(); this.processor.processRequest(null, exchange); ServerHttpResponse response = exchange.getResponse(); assertFalse(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)); assertNull(response.getStatusCode()); } @Test public void actualRequestWithOriginHeaderAndAllowedOrigin() throws Exception { ServerWebExchange exchange = actualRequest(); this.conf.addAllowedOrigin("*"); this.processor.processRequest(this.conf, exchange); ServerHttpResponse response = exchange.getResponse(); assertTrue(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals("*", response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN)); assertFalse(response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_MAX_AGE)); assertFalse(response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS)); assertNull(response.getStatusCode()); } @Test public void actualRequestCredentials() throws Exception { ServerWebExchange exchange = actualRequest(); this.conf.addAllowedOrigin("http://domain1.com"); this.conf.addAllowedOrigin("http://domain2.com"); this.conf.addAllowedOrigin("http://domain3.com"); this.conf.setAllowCredentials(true); this.processor.processRequest(this.conf, exchange); ServerHttpResponse response = exchange.getResponse(); assertTrue(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals("http://domain2.com", response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN)); assertTrue(response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)); assertEquals("true", response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)); assertNull(response.getStatusCode()); } @Test public void actualRequestCredentialsWithOriginWildcard() throws Exception { ServerWebExchange exchange = actualRequest(); this.conf.addAllowedOrigin("*"); this.conf.setAllowCredentials(true); this.processor.processRequest(this.conf, exchange); ServerHttpResponse response = exchange.getResponse(); assertTrue(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals("http://domain2.com", response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN)); assertTrue(response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)); assertEquals("true", response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)); assertNull(response.getStatusCode()); } @Test public void actualRequestCaseInsensitiveOriginMatch() throws Exception { ServerWebExchange exchange = actualRequest(); this.conf.addAllowedOrigin("http://DOMAIN2.com"); this.processor.processRequest(this.conf, exchange); ServerHttpResponse response = exchange.getResponse(); assertTrue(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)); assertNull(response.getStatusCode()); } @Test public void actualRequestExposedHeaders() throws Exception { ServerWebExchange exchange = actualRequest(); this.conf.addExposedHeader("header1"); this.conf.addExposedHeader("header2"); this.conf.addAllowedOrigin("http://domain2.com"); this.processor.processRequest(this.conf, exchange); ServerHttpResponse response = exchange.getResponse(); assertTrue(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals("http://domain2.com", response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN)); assertTrue(response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS)); assertTrue(response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS).contains("header1")); assertTrue(response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS).contains("header2")); assertNull(response.getStatusCode()); } @Test public void preflightRequestAllOriginsAllowed() throws Exception { ServerWebExchange exchange = preFlightRequest().header(ACCESS_CONTROL_REQUEST_METHOD, "GET").toExchange(); this.conf.addAllowedOrigin("*"); this.processor.processRequest(this.conf, exchange); assertNull(exchange.getResponse().getStatusCode()); } @Test public void preflightRequestWrongAllowedMethod() throws Exception { ServerWebExchange exchange = preFlightRequest().header(ACCESS_CONTROL_REQUEST_METHOD, "DELETE").toExchange(); this.conf.addAllowedOrigin("*"); this.processor.processRequest(this.conf, exchange); assertEquals(HttpStatus.FORBIDDEN, exchange.getResponse().getStatusCode()); } @Test public void preflightRequestMatchedAllowedMethod() throws Exception { ServerWebExchange exchange = preFlightRequest().header(ACCESS_CONTROL_REQUEST_METHOD, "GET").toExchange(); this.conf.addAllowedOrigin("*"); this.processor.processRequest(this.conf, exchange); ServerHttpResponse response = exchange.getResponse(); assertNull(response.getStatusCode()); assertEquals("GET,HEAD", response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS)); } @Test public void preflightRequestTestWithOriginButWithoutOtherHeaders() throws Exception { ServerWebExchange exchange = preFlightRequest().toExchange(); this.processor.processRequest(this.conf, exchange); ServerHttpResponse response = exchange.getResponse(); assertFalse(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode()); } @Test public void preflightRequestWithoutRequestMethod() throws Exception { ServerWebExchange exchange = preFlightRequest().header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1").toExchange(); this.processor.processRequest(this.conf, exchange); ServerHttpResponse response = exchange.getResponse(); assertFalse(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode()); } @Test public void preflightRequestWithRequestAndMethodHeaderButNoConfig() throws Exception { ServerWebExchange exchange = preFlightRequest() .header(ACCESS_CONTROL_REQUEST_METHOD, "GET") .header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1") .toExchange(); this.processor.processRequest(this.conf, exchange); ServerHttpResponse response = exchange.getResponse(); assertFalse(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode()); } @Test public void preflightRequestValidRequestAndConfig() throws Exception { ServerWebExchange exchange = preFlightRequest() .header(ACCESS_CONTROL_REQUEST_METHOD, "GET") .header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1") .toExchange(); this.conf.addAllowedOrigin("*"); this.conf.addAllowedMethod("GET"); this.conf.addAllowedMethod("PUT"); this.conf.addAllowedHeader("header1"); this.conf.addAllowedHeader("header2"); this.processor.processRequest(this.conf, exchange); ServerHttpResponse response = exchange.getResponse(); assertTrue(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals("*", response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN)); assertTrue(response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS)); assertEquals("GET,PUT", response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS)); assertFalse(response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_MAX_AGE)); assertNull(response.getStatusCode()); } @Test public void preflightRequestCredentials() throws Exception { ServerWebExchange exchange = preFlightRequest() .header(ACCESS_CONTROL_REQUEST_METHOD, "GET") .header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1") .toExchange(); this.conf.addAllowedOrigin("http://domain1.com"); this.conf.addAllowedOrigin("http://domain2.com"); this.conf.addAllowedOrigin("http://domain3.com"); this.conf.addAllowedHeader("Header1"); this.conf.setAllowCredentials(true); this.processor.processRequest(this.conf, exchange); ServerHttpResponse response = exchange.getResponse(); assertTrue(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals("http://domain2.com", response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN)); assertTrue(response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)); assertEquals("true", response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)); assertNull(response.getStatusCode()); } @Test public void preflightRequestCredentialsWithOriginWildcard() throws Exception { ServerWebExchange exchange = preFlightRequest() .header(ACCESS_CONTROL_REQUEST_METHOD, "GET") .header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1") .toExchange(); this.conf.addAllowedOrigin("http://domain1.com"); this.conf.addAllowedOrigin("*"); this.conf.addAllowedOrigin("http://domain3.com"); this.conf.addAllowedHeader("Header1"); this.conf.setAllowCredentials(true); this.processor.processRequest(this.conf, exchange); ServerHttpResponse response = exchange.getResponse(); assertTrue(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals("http://domain2.com", response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN)); assertNull(response.getStatusCode()); } @Test public void preflightRequestAllowedHeaders() throws Exception { ServerWebExchange exchange = preFlightRequest() .header(ACCESS_CONTROL_REQUEST_METHOD, "GET") .header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1, Header2") .toExchange(); this.conf.addAllowedHeader("Header1"); this.conf.addAllowedHeader("Header2"); this.conf.addAllowedHeader("Header3"); this.conf.addAllowedOrigin("http://domain2.com"); this.processor.processRequest(this.conf, exchange); ServerHttpResponse response = exchange.getResponse(); assertTrue(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)); assertTrue(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_HEADERS)); assertTrue(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS).contains("Header1")); assertTrue(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS).contains("Header2")); assertFalse(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS).contains("Header3")); assertNull(response.getStatusCode()); } @Test public void preflightRequestAllowsAllHeaders() throws Exception { ServerWebExchange exchange = preFlightRequest() .header(ACCESS_CONTROL_REQUEST_METHOD, "GET") .header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1, Header2") .toExchange(); this.conf.addAllowedHeader("*"); this.conf.addAllowedOrigin("http://domain2.com"); this.processor.processRequest(this.conf, exchange); ServerHttpResponse response = exchange.getResponse(); assertTrue(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)); assertTrue(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_HEADERS)); assertTrue(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS).contains("Header1")); assertTrue(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS).contains("Header2")); assertFalse(response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS).contains("*")); assertNull(response.getStatusCode()); } @Test public void preflightRequestWithEmptyHeaders() throws Exception { ServerWebExchange exchange = preFlightRequest() .header(ACCESS_CONTROL_REQUEST_METHOD, "GET") .header(ACCESS_CONTROL_REQUEST_HEADERS, "") .toExchange(); this.conf.addAllowedHeader("*"); this.conf.addAllowedOrigin("http://domain2.com"); this.processor.processRequest(this.conf, exchange); ServerHttpResponse response = exchange.getResponse(); assertTrue(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)); assertFalse(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_HEADERS)); assertNull(response.getStatusCode()); } @Test public void preflightRequestWithNullConfig() throws Exception { ServerWebExchange exchange = preFlightRequest().header(ACCESS_CONTROL_REQUEST_METHOD, "GET").toExchange(); this.conf.addAllowedOrigin("*"); this.processor.processRequest(null, exchange); ServerHttpResponse response = exchange.getResponse(); assertFalse(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode()); } private ServerWebExchange actualRequest() { return corsRequest(HttpMethod.GET).toExchange(); } private MockServerHttpRequest.BaseBuilder<?> preFlightRequest() { return corsRequest(HttpMethod.OPTIONS); } private MockServerHttpRequest.BaseBuilder<?> corsRequest(HttpMethod method) { return MockServerHttpRequest .method(method, "http://localhost/test.html") .header(HttpHeaders.ORIGIN, "http://domain2.com"); } }