DefaultCorsProcessorTests.java 15.3 KB
Newer Older
S
Sebastien Deleuze 已提交
1
/*
2
 * Copyright 2002-2017 the original author or authors.
S
Sebastien Deleuze 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * 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;
25
import org.springframework.http.server.reactive.ServerHttpResponse;
S
Sebastien Deleuze 已提交
26
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
27
import org.springframework.mock.web.test.server.MockServerWebExchange;
S
Sebastien Deleuze 已提交
28
import org.springframework.web.cors.CorsConfiguration;
29
import org.springframework.web.server.ServerWebExchange;
S
Sebastien Deleuze 已提交
30

31 32 33 34 35 36 37 38
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;
R
Rossen Stoyanchev 已提交
39

S
Sebastien Deleuze 已提交
40
/**
R
Rossen Stoyanchev 已提交
41
 * {@link DefaultCorsProcessor} tests with simple or pre-flight CORS request.
S
Sebastien Deleuze 已提交
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
 *
 * @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 {
61
		ServerWebExchange exchange = actualRequest();
62
		this.processor.process(this.conf, exchange);
63 64 65 66

		ServerHttpResponse response = exchange.getResponse();
		assertFalse(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
		assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode());
S
Sebastien Deleuze 已提交
67 68 69 70
	}

	@Test
	public void actualRequestWithOriginHeaderAndNullConfig() throws Exception {
71
		ServerWebExchange exchange = actualRequest();
72
		this.processor.process(null, exchange);
73 74 75 76

		ServerHttpResponse response = exchange.getResponse();
		assertFalse(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
		assertNull(response.getStatusCode());
S
Sebastien Deleuze 已提交
77 78 79 80
	}

	@Test
	public void actualRequestWithOriginHeaderAndAllowedOrigin() throws Exception {
81
		ServerWebExchange exchange = actualRequest();
S
Sebastien Deleuze 已提交
82
		this.conf.addAllowedOrigin("*");
83
		this.processor.process(this.conf, exchange);
84 85 86 87 88 89 90

		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());
S
Sebastien Deleuze 已提交
91 92 93 94
	}

	@Test
	public void actualRequestCredentials() throws Exception {
95
		ServerWebExchange exchange = actualRequest();
S
Sebastien Deleuze 已提交
96 97 98 99
		this.conf.addAllowedOrigin("http://domain1.com");
		this.conf.addAllowedOrigin("http://domain2.com");
		this.conf.addAllowedOrigin("http://domain3.com");
		this.conf.setAllowCredentials(true);
100
		this.processor.process(this.conf, exchange);
101 102 103 104 105 106 107

		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());
S
Sebastien Deleuze 已提交
108 109 110 111
	}

	@Test
	public void actualRequestCredentialsWithOriginWildcard() throws Exception {
112
		ServerWebExchange exchange = actualRequest();
S
Sebastien Deleuze 已提交
113 114
		this.conf.addAllowedOrigin("*");
		this.conf.setAllowCredentials(true);
115
		this.processor.process(this.conf, exchange);
116 117 118 119 120 121 122

		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());
S
Sebastien Deleuze 已提交
123 124 125 126
	}

	@Test
	public void actualRequestCaseInsensitiveOriginMatch() throws Exception {
127
		ServerWebExchange exchange = actualRequest();
S
Sebastien Deleuze 已提交
128
		this.conf.addAllowedOrigin("http://DOMAIN2.com");
129
		this.processor.process(this.conf, exchange);
S
Sebastien Deleuze 已提交
130

131 132 133
		ServerHttpResponse response = exchange.getResponse();
		assertTrue(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
		assertNull(response.getStatusCode());
S
Sebastien Deleuze 已提交
134 135 136 137
	}

	@Test
	public void actualRequestExposedHeaders() throws Exception {
138
		ServerWebExchange exchange = actualRequest();
S
Sebastien Deleuze 已提交
139 140 141
		this.conf.addExposedHeader("header1");
		this.conf.addExposedHeader("header2");
		this.conf.addAllowedOrigin("http://domain2.com");
142
		this.processor.process(this.conf, exchange);
143 144 145 146 147 148 149 150

		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());
S
Sebastien Deleuze 已提交
151 152 153 154
	}

	@Test
	public void preflightRequestAllOriginsAllowed() throws Exception {
155 156
		MockServerHttpRequest request = preFlightRequest().header(ACCESS_CONTROL_REQUEST_METHOD, "GET").build();
		ServerWebExchange exchange = MockServerWebExchange.from(request);
S
Sebastien Deleuze 已提交
157
		this.conf.addAllowedOrigin("*");
158
		this.processor.process(this.conf, exchange);
S
Sebastien Deleuze 已提交
159

160
		assertNull(exchange.getResponse().getStatusCode());
S
Sebastien Deleuze 已提交
161 162
	}

163

S
Sebastien Deleuze 已提交
164 165
	@Test
	public void preflightRequestWrongAllowedMethod() throws Exception {
166 167
		MockServerHttpRequest request = preFlightRequest().header(ACCESS_CONTROL_REQUEST_METHOD, "DELETE").build();
		ServerWebExchange exchange = MockServerWebExchange.from(request);
S
Sebastien Deleuze 已提交
168
		this.conf.addAllowedOrigin("*");
169
		this.processor.process(this.conf, exchange);
S
Sebastien Deleuze 已提交
170

171
		assertEquals(HttpStatus.FORBIDDEN, exchange.getResponse().getStatusCode());
S
Sebastien Deleuze 已提交
172 173 174 175
	}

	@Test
	public void preflightRequestMatchedAllowedMethod() throws Exception {
176 177
		MockServerHttpRequest request = preFlightRequest().header(ACCESS_CONTROL_REQUEST_METHOD, "GET").build();
		ServerWebExchange exchange = MockServerWebExchange.from(request);
S
Sebastien Deleuze 已提交
178
		this.conf.addAllowedOrigin("*");
179
		this.processor.process(this.conf, exchange);
S
Sebastien Deleuze 已提交
180

181 182 183
		ServerHttpResponse response = exchange.getResponse();
		assertNull(response.getStatusCode());
		assertEquals("GET,HEAD", response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS));
S
Sebastien Deleuze 已提交
184 185 186 187
	}

	@Test
	public void preflightRequestTestWithOriginButWithoutOtherHeaders() throws Exception {
188
		ServerWebExchange exchange = MockServerWebExchange.from(preFlightRequest().build());
189
		this.processor.process(this.conf, exchange);
S
Sebastien Deleuze 已提交
190

191 192 193
		ServerHttpResponse response = exchange.getResponse();
		assertFalse(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
		assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode());
S
Sebastien Deleuze 已提交
194 195 196 197
	}

	@Test
	public void preflightRequestWithoutRequestMethod() throws Exception {
198 199
		MockServerHttpRequest request = preFlightRequest().header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1").build();
		ServerWebExchange exchange = MockServerWebExchange.from(request);
200
		this.processor.process(this.conf, exchange);
S
Sebastien Deleuze 已提交
201

202 203 204
		ServerHttpResponse response = exchange.getResponse();
		assertFalse(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
		assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode());
S
Sebastien Deleuze 已提交
205 206 207 208
	}

	@Test
	public void preflightRequestWithRequestAndMethodHeaderButNoConfig() throws Exception {
209
		ServerWebExchange exchange = MockServerWebExchange.from(preFlightRequest()
210 211
				.header(ACCESS_CONTROL_REQUEST_METHOD, "GET")
				.header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1")
212
				.build());
213

214
		this.processor.process(this.conf, exchange);
S
Sebastien Deleuze 已提交
215

216 217 218
		ServerHttpResponse response = exchange.getResponse();
		assertFalse(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
		assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode());
S
Sebastien Deleuze 已提交
219 220 221 222
	}

	@Test
	public void preflightRequestValidRequestAndConfig() throws Exception {
223
		ServerWebExchange exchange = MockServerWebExchange.from(preFlightRequest()
224 225
				.header(ACCESS_CONTROL_REQUEST_METHOD, "GET")
				.header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1")
226
				.build());
227

S
Sebastien Deleuze 已提交
228 229 230 231 232 233
		this.conf.addAllowedOrigin("*");
		this.conf.addAllowedMethod("GET");
		this.conf.addAllowedMethod("PUT");
		this.conf.addAllowedHeader("header1");
		this.conf.addAllowedHeader("header2");

234
		this.processor.process(this.conf, exchange);
235 236 237 238 239 240 241 242

		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());
S
Sebastien Deleuze 已提交
243 244 245 246
	}

	@Test
	public void preflightRequestCredentials() throws Exception {
247
		ServerWebExchange exchange = MockServerWebExchange.from(preFlightRequest()
248 249
				.header(ACCESS_CONTROL_REQUEST_METHOD, "GET")
				.header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1")
250
				.build());
251

S
Sebastien Deleuze 已提交
252 253 254 255 256 257
		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);

258
		this.processor.process(this.conf, exchange);
259 260 261 262 263 264 265

		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());
S
Sebastien Deleuze 已提交
266 267 268 269
	}

	@Test
	public void preflightRequestCredentialsWithOriginWildcard() throws Exception {
270
		ServerWebExchange exchange = MockServerWebExchange.from(preFlightRequest()
271 272
				.header(ACCESS_CONTROL_REQUEST_METHOD, "GET")
				.header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1")
273
				.build());
274

S
Sebastien Deleuze 已提交
275 276 277 278 279 280
		this.conf.addAllowedOrigin("http://domain1.com");
		this.conf.addAllowedOrigin("*");
		this.conf.addAllowedOrigin("http://domain3.com");
		this.conf.addAllowedHeader("Header1");
		this.conf.setAllowCredentials(true);

281
		this.processor.process(this.conf, exchange);
282 283 284 285 286

		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());
S
Sebastien Deleuze 已提交
287 288 289 290
	}

	@Test
	public void preflightRequestAllowedHeaders() throws Exception {
291
		ServerWebExchange exchange = MockServerWebExchange.from(preFlightRequest()
292 293
				.header(ACCESS_CONTROL_REQUEST_METHOD, "GET")
				.header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1, Header2")
294
				.build());
295

S
Sebastien Deleuze 已提交
296 297 298 299 300
		this.conf.addAllowedHeader("Header1");
		this.conf.addAllowedHeader("Header2");
		this.conf.addAllowedHeader("Header3");
		this.conf.addAllowedOrigin("http://domain2.com");

301
		this.processor.process(this.conf, exchange);
302 303 304 305 306 307 308 309

		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());
S
Sebastien Deleuze 已提交
310 311 312 313
	}

	@Test
	public void preflightRequestAllowsAllHeaders() throws Exception {
314
		ServerWebExchange exchange = MockServerWebExchange.from(preFlightRequest()
315 316
				.header(ACCESS_CONTROL_REQUEST_METHOD, "GET")
				.header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1, Header2")
317
				.build());
318

S
Sebastien Deleuze 已提交
319 320 321
		this.conf.addAllowedHeader("*");
		this.conf.addAllowedOrigin("http://domain2.com");

322
		this.processor.process(this.conf, exchange);
323 324 325 326 327 328 329 330

		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());
S
Sebastien Deleuze 已提交
331 332 333 334
	}

	@Test
	public void preflightRequestWithEmptyHeaders() throws Exception {
335
		ServerWebExchange exchange = MockServerWebExchange.from(preFlightRequest()
336 337
				.header(ACCESS_CONTROL_REQUEST_METHOD, "GET")
				.header(ACCESS_CONTROL_REQUEST_HEADERS, "")
338
				.build());
339

S
Sebastien Deleuze 已提交
340 341 342
		this.conf.addAllowedHeader("*");
		this.conf.addAllowedOrigin("http://domain2.com");

343
		this.processor.process(this.conf, exchange);
344 345 346 347 348

		ServerHttpResponse response = exchange.getResponse();
		assertTrue(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
		assertFalse(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_HEADERS));
		assertNull(response.getStatusCode());
S
Sebastien Deleuze 已提交
349 350 351 352
	}

	@Test
	public void preflightRequestWithNullConfig() throws Exception {
353 354
		MockServerHttpRequest request = preFlightRequest().header(ACCESS_CONTROL_REQUEST_METHOD, "GET").build();
		ServerWebExchange exchange = MockServerWebExchange.from(request);
S
Sebastien Deleuze 已提交
355
		this.conf.addAllowedOrigin("*");
356
		this.processor.process(null, exchange);
S
Sebastien Deleuze 已提交
357

358 359 360
		ServerHttpResponse response = exchange.getResponse();
		assertFalse(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
		assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode());
S
Sebastien Deleuze 已提交
361 362
	}

363

364
	private ServerWebExchange actualRequest() {
365
		return MockServerWebExchange.from(corsRequest(HttpMethod.GET).build());
366 367 368 369 370 371
	}

	private MockServerHttpRequest.BaseBuilder<?> preFlightRequest() {
		return corsRequest(HttpMethod.OPTIONS);
	}

372
	private MockServerHttpRequest.BaseBuilder<?> corsRequest(HttpMethod method) {
373
		return MockServerHttpRequest
374
				.method(method, "http://localhost/test.html")
375 376 377
				.header(HttpHeaders.ORIGIN, "http://domain2.com");
	}

S
Sebastien Deleuze 已提交
378
}