DefaultCorsProcessorTests.java 14.6 KB
Newer Older
S
Sebastien Deleuze 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * Copyright 2002-2016 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;

19
import org.jetbrains.annotations.NotNull;
S
Sebastien Deleuze 已提交
20 21 22 23 24 25 26 27 28 29 30
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.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.server.adapter.DefaultServerWebExchange;

R
Rossen Stoyanchev 已提交
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.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;

S
Sebastien Deleuze 已提交
39
/**
R
Rossen Stoyanchev 已提交
40
 * {@link DefaultCorsProcessor} tests with simple or pre-flight CORS request.
S
Sebastien Deleuze 已提交
41 42 43 44 45 46
 *
 * @author Sebastien Deleuze
 */
public class DefaultCorsProcessorTests {

	private MockServerHttpRequest request;
47
	
S
Sebastien Deleuze 已提交
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
	private MockServerHttpResponse response;

	private DefaultCorsProcessor processor;

	private CorsConfiguration conf;


	@Before
	public void setup() {
		this.conf = new CorsConfiguration();
		this.response = new MockServerHttpResponse();
		this.response.setStatusCode(HttpStatus.OK);
		this.processor = new DefaultCorsProcessor();
	}


	@Test
	public void actualRequestWithOriginHeader() throws Exception {
66 67
		this.request = actualRequest().build();
		this.processor.processRequest(this.conf, createExchange());
R
Rossen Stoyanchev 已提交
68
		assertFalse(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
S
Sebastien Deleuze 已提交
69 70 71 72 73
		assertEquals(HttpStatus.FORBIDDEN, this.response.getStatusCode());
	}

	@Test
	public void actualRequestWithOriginHeaderAndNullConfig() throws Exception {
74 75
		this.request = actualRequest().build();
		this.processor.processRequest(null, createExchange());
R
Rossen Stoyanchev 已提交
76
		assertFalse(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
S
Sebastien Deleuze 已提交
77 78 79 80 81
		assertEquals(HttpStatus.OK, this.response.getStatusCode());
	}

	@Test
	public void actualRequestWithOriginHeaderAndAllowedOrigin() throws Exception {
82
		this.request = actualRequest().build();
S
Sebastien Deleuze 已提交
83 84
		this.conf.addAllowedOrigin("*");

85
		this.processor.processRequest(this.conf, createExchange());
R
Rossen Stoyanchev 已提交
86 87
		assertTrue(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
		assertEquals("*", this.response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN));
S
Sebastien Deleuze 已提交
88 89 90 91 92 93 94
		assertFalse(this.response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_MAX_AGE));
		assertFalse(this.response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS));
		assertEquals(HttpStatus.OK, this.response.getStatusCode());
	}

	@Test
	public void actualRequestCredentials() throws Exception {
95
		this.request = actualRequest().build();
S
Sebastien Deleuze 已提交
96 97 98 99 100
		this.conf.addAllowedOrigin("http://domain1.com");
		this.conf.addAllowedOrigin("http://domain2.com");
		this.conf.addAllowedOrigin("http://domain3.com");
		this.conf.setAllowCredentials(true);

101
		this.processor.processRequest(this.conf, createExchange());
R
Rossen Stoyanchev 已提交
102 103
		assertTrue(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
		assertEquals("http://domain2.com", this.response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN));
S
Sebastien Deleuze 已提交
104 105 106 107 108 109 110
		assertTrue(this.response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS));
		assertEquals("true", this.response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS));
		assertEquals(HttpStatus.OK, this.response.getStatusCode());
	}

	@Test
	public void actualRequestCredentialsWithOriginWildcard() throws Exception {
111
		this.request = actualRequest().build();
S
Sebastien Deleuze 已提交
112 113 114
		this.conf.addAllowedOrigin("*");
		this.conf.setAllowCredentials(true);

115
		this.processor.processRequest(this.conf, createExchange());
R
Rossen Stoyanchev 已提交
116 117
		assertTrue(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
		assertEquals("http://domain2.com", this.response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN));
S
Sebastien Deleuze 已提交
118 119 120 121 122 123 124
		assertTrue(this.response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS));
		assertEquals("true", this.response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS));
		assertEquals(HttpStatus.OK, this.response.getStatusCode());
	}

	@Test
	public void actualRequestCaseInsensitiveOriginMatch() throws Exception {
125
		this.request = actualRequest().build();
S
Sebastien Deleuze 已提交
126 127
		this.conf.addAllowedOrigin("http://DOMAIN2.com");

128
		this.processor.processRequest(this.conf, createExchange());
R
Rossen Stoyanchev 已提交
129
		assertTrue(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
S
Sebastien Deleuze 已提交
130 131 132 133 134
		assertEquals(HttpStatus.OK, this.response.getStatusCode());
	}

	@Test
	public void actualRequestExposedHeaders() throws Exception {
135
		this.request = actualRequest().build();
S
Sebastien Deleuze 已提交
136 137 138 139
		this.conf.addExposedHeader("header1");
		this.conf.addExposedHeader("header2");
		this.conf.addAllowedOrigin("http://domain2.com");

140
		this.processor.processRequest(this.conf, createExchange());
R
Rossen Stoyanchev 已提交
141 142
		assertTrue(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
		assertEquals("http://domain2.com", this.response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN));
S
Sebastien Deleuze 已提交
143 144 145 146 147 148 149 150
		assertTrue(this.response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS));
		assertTrue(this.response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS).contains("header1"));
		assertTrue(this.response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS).contains("header2"));
		assertEquals(HttpStatus.OK, this.response.getStatusCode());
	}

	@Test
	public void preflightRequestAllOriginsAllowed() throws Exception {
151
		this.request = preFlightRequest().header(ACCESS_CONTROL_REQUEST_METHOD, "GET").build();
S
Sebastien Deleuze 已提交
152 153
		this.conf.addAllowedOrigin("*");

154
		this.processor.processRequest(this.conf, createExchange());
S
Sebastien Deleuze 已提交
155 156 157
		assertEquals(HttpStatus.OK, this.response.getStatusCode());
	}

158

S
Sebastien Deleuze 已提交
159 160
	@Test
	public void preflightRequestWrongAllowedMethod() throws Exception {
161
		this.request = preFlightRequest().header(ACCESS_CONTROL_REQUEST_METHOD, "DELETE").build();
S
Sebastien Deleuze 已提交
162 163
		this.conf.addAllowedOrigin("*");

164
		this.processor.processRequest(this.conf, createExchange());
S
Sebastien Deleuze 已提交
165 166 167 168 169
		assertEquals(HttpStatus.FORBIDDEN, this.response.getStatusCode());
	}

	@Test
	public void preflightRequestMatchedAllowedMethod() throws Exception {
170
		this.request = preFlightRequest().header(ACCESS_CONTROL_REQUEST_METHOD, "GET").build();
S
Sebastien Deleuze 已提交
171 172
		this.conf.addAllowedOrigin("*");

173
		this.processor.processRequest(this.conf, createExchange());
S
Sebastien Deleuze 已提交
174 175 176 177 178 179
		assertEquals(HttpStatus.OK, this.response.getStatusCode());
		assertEquals("GET,HEAD", this.response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS));
	}

	@Test
	public void preflightRequestTestWithOriginButWithoutOtherHeaders() throws Exception {
180
		this.request = preFlightRequest().build();
S
Sebastien Deleuze 已提交
181

182
		this.processor.processRequest(this.conf, createExchange());
R
Rossen Stoyanchev 已提交
183
		assertFalse(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
S
Sebastien Deleuze 已提交
184 185 186 187 188
		assertEquals(HttpStatus.FORBIDDEN, this.response.getStatusCode());
	}

	@Test
	public void preflightRequestWithoutRequestMethod() throws Exception {
189
		this.request = preFlightRequest().header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1").build();
S
Sebastien Deleuze 已提交
190

191
		this.processor.processRequest(this.conf, createExchange());
R
Rossen Stoyanchev 已提交
192
		assertFalse(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
S
Sebastien Deleuze 已提交
193 194 195 196 197
		assertEquals(HttpStatus.FORBIDDEN, this.response.getStatusCode());
	}

	@Test
	public void preflightRequestWithRequestAndMethodHeaderButNoConfig() throws Exception {
198 199 200 201
		this.request = preFlightRequest()
				.header(ACCESS_CONTROL_REQUEST_METHOD, "GET")
				.header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1")
				.build();
S
Sebastien Deleuze 已提交
202

203
		this.processor.processRequest(this.conf, createExchange());
R
Rossen Stoyanchev 已提交
204
		assertFalse(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
S
Sebastien Deleuze 已提交
205 206 207 208 209
		assertEquals(HttpStatus.FORBIDDEN, this.response.getStatusCode());
	}

	@Test
	public void preflightRequestValidRequestAndConfig() throws Exception {
210 211 212 213
		this.request = preFlightRequest()
				.header(ACCESS_CONTROL_REQUEST_METHOD, "GET")
				.header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1")
				.build();
S
Sebastien Deleuze 已提交
214 215 216 217 218 219
		this.conf.addAllowedOrigin("*");
		this.conf.addAllowedMethod("GET");
		this.conf.addAllowedMethod("PUT");
		this.conf.addAllowedHeader("header1");
		this.conf.addAllowedHeader("header2");

220
		this.processor.processRequest(this.conf, createExchange());
R
Rossen Stoyanchev 已提交
221 222
		assertTrue(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
		assertEquals("*", this.response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN));
S
Sebastien Deleuze 已提交
223 224 225 226 227 228 229 230
		assertTrue(this.response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS));
		assertEquals("GET,PUT", this.response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS));
		assertFalse(this.response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_MAX_AGE));
		assertEquals(HttpStatus.OK, this.response.getStatusCode());
	}

	@Test
	public void preflightRequestCredentials() throws Exception {
231 232 233 234
		this.request = preFlightRequest()
				.header(ACCESS_CONTROL_REQUEST_METHOD, "GET")
				.header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1")
				.build();
S
Sebastien Deleuze 已提交
235 236 237 238 239 240
		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);

241
		this.processor.processRequest(this.conf, createExchange());
R
Rossen Stoyanchev 已提交
242 243
		assertTrue(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
		assertEquals("http://domain2.com", this.response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN));
S
Sebastien Deleuze 已提交
244 245 246 247 248 249 250
		assertTrue(this.response.getHeaders().containsKey(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS));
		assertEquals("true", this.response.getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS));
		assertEquals(HttpStatus.OK, this.response.getStatusCode());
	}

	@Test
	public void preflightRequestCredentialsWithOriginWildcard() throws Exception {
251 252 253 254
		this.request = preFlightRequest()
				.header(ACCESS_CONTROL_REQUEST_METHOD, "GET")
				.header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1")
				.build();
S
Sebastien Deleuze 已提交
255 256 257 258 259 260
		this.conf.addAllowedOrigin("http://domain1.com");
		this.conf.addAllowedOrigin("*");
		this.conf.addAllowedOrigin("http://domain3.com");
		this.conf.addAllowedHeader("Header1");
		this.conf.setAllowCredentials(true);

261
		this.processor.processRequest(this.conf, createExchange());
R
Rossen Stoyanchev 已提交
262 263
		assertTrue(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
		assertEquals("http://domain2.com", this.response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_ORIGIN));
S
Sebastien Deleuze 已提交
264 265 266 267 268
		assertEquals(HttpStatus.OK, this.response.getStatusCode());
	}

	@Test
	public void preflightRequestAllowedHeaders() throws Exception {
269 270 271 272
		this.request = preFlightRequest()
				.header(ACCESS_CONTROL_REQUEST_METHOD, "GET")
				.header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1, Header2")
				.build();
S
Sebastien Deleuze 已提交
273 274 275 276 277
		this.conf.addAllowedHeader("Header1");
		this.conf.addAllowedHeader("Header2");
		this.conf.addAllowedHeader("Header3");
		this.conf.addAllowedOrigin("http://domain2.com");

278
		this.processor.processRequest(this.conf, createExchange());
R
Rossen Stoyanchev 已提交
279 280 281 282 283
		assertTrue(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
		assertTrue(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_HEADERS));
		assertTrue(this.response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS).contains("Header1"));
		assertTrue(this.response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS).contains("Header2"));
		assertFalse(this.response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS).contains("Header3"));
S
Sebastien Deleuze 已提交
284 285 286 287 288
		assertEquals(HttpStatus.OK, this.response.getStatusCode());
	}

	@Test
	public void preflightRequestAllowsAllHeaders() throws Exception {
289 290 291 292
		this.request = preFlightRequest()
				.header(ACCESS_CONTROL_REQUEST_METHOD, "GET")
				.header(ACCESS_CONTROL_REQUEST_HEADERS, "Header1, Header2")
				.build();
S
Sebastien Deleuze 已提交
293 294 295
		this.conf.addAllowedHeader("*");
		this.conf.addAllowedOrigin("http://domain2.com");

296
		this.processor.processRequest(this.conf, createExchange());
R
Rossen Stoyanchev 已提交
297 298 299 300 301
		assertTrue(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
		assertTrue(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_HEADERS));
		assertTrue(this.response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS).contains("Header1"));
		assertTrue(this.response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS).contains("Header2"));
		assertFalse(this.response.getHeaders().getFirst(ACCESS_CONTROL_ALLOW_HEADERS).contains("*"));
S
Sebastien Deleuze 已提交
302 303 304 305 306
		assertEquals(HttpStatus.OK, this.response.getStatusCode());
	}

	@Test
	public void preflightRequestWithEmptyHeaders() throws Exception {
307 308 309 310
		this.request = preFlightRequest()
				.header(ACCESS_CONTROL_REQUEST_METHOD, "GET")
				.header(ACCESS_CONTROL_REQUEST_HEADERS, "")
				.build();
S
Sebastien Deleuze 已提交
311 312 313
		this.conf.addAllowedHeader("*");
		this.conf.addAllowedOrigin("http://domain2.com");

314
		this.processor.processRequest(this.conf, createExchange());
R
Rossen Stoyanchev 已提交
315 316
		assertTrue(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
		assertFalse(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_HEADERS));
S
Sebastien Deleuze 已提交
317 318 319 320 321
		assertEquals(HttpStatus.OK, this.response.getStatusCode());
	}

	@Test
	public void preflightRequestWithNullConfig() throws Exception {
322 323 324
		this.request = preFlightRequest()
				.header(ACCESS_CONTROL_REQUEST_METHOD, "GET")
				.build();
S
Sebastien Deleuze 已提交
325 326
		this.conf.addAllowedOrigin("*");

327
		this.processor.processRequest(null, createExchange());
R
Rossen Stoyanchev 已提交
328
		assertFalse(this.response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN));
S
Sebastien Deleuze 已提交
329 330 331
		assertEquals(HttpStatus.FORBIDDEN, this.response.getStatusCode());
	}

332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
	private MockServerHttpRequest.BaseBuilder<?> actualRequest() {
		return corsRequest(HttpMethod.GET);
	}

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

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

	@NotNull
	private DefaultServerWebExchange createExchange() {
		return new DefaultServerWebExchange(this.request, this.response);
	}

S
Sebastien Deleuze 已提交
351
}