diff --git a/spring-web/src/main/java/org/springframework/web/cors/CorsConfiguration.java b/spring-web/src/main/java/org/springframework/web/cors/CorsConfiguration.java index f3864c6a2df6..aa7cdf710e64 100644 --- a/spring-web/src/main/java/org/springframework/web/cors/CorsConfiguration.java +++ b/spring-web/src/main/java/org/springframework/web/cors/CorsConfiguration.java @@ -603,8 +603,23 @@ public CorsConfiguration combine(@Nullable CorsConfiguration other) { List patterns = combinePatterns(this.allowedOriginPatterns, other.allowedOriginPatterns); config.allowedOrigins = (origins == DEFAULT_PERMIT_ALL && !CollectionUtils.isEmpty(patterns) ? null : origins); config.allowedOriginPatterns = patterns; - config.setAllowedMethods(combine(getAllowedMethods(), other.getAllowedMethods())); - config.setAllowedHeaders(combine(getAllowedHeaders(), other.getAllowedHeaders())); + // Bypass setAllowedMethods and setAllowedHeaders to retain default permit values + List methods = combine(getAllowedMethods(), other.getAllowedMethods()); + if (methods == DEFAULT_PERMIT_METHODS) { + config.allowedMethods = methods; + config.resolvedMethods = (this.allowedMethods == methods ? + this.resolvedMethods : other.resolvedMethods); + } + else { + config.setAllowedMethods(methods); + } + List headers = combine(getAllowedHeaders(), other.getAllowedHeaders()); + if (headers == DEFAULT_PERMIT_ALL) { + config.allowedHeaders = headers; + } + else { + config.setAllowedHeaders(headers); + } config.setExposedHeaders(combine(getExposedHeaders(), other.getExposedHeaders())); Boolean allowCredentials = other.getAllowCredentials(); if (allowCredentials != null) { diff --git a/spring-web/src/test/java/org/springframework/web/cors/CorsConfigurationTests.java b/spring-web/src/test/java/org/springframework/web/cors/CorsConfigurationTests.java index 6bc920185474..1111d49bb58f 100644 --- a/spring-web/src/test/java/org/springframework/web/cors/CorsConfigurationTests.java +++ b/spring-web/src/test/java/org/springframework/web/cors/CorsConfigurationTests.java @@ -152,6 +152,41 @@ void combineWithDefaultPermitValues() { assertThat(combinedConfig.getExposedHeaders()).isEmpty(); } + @Test + void combineWithDefaultPermitValuesOfCombinedConfig() { + CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues(); + CorsConfiguration other = new CorsConfiguration(); + other.addAllowedOrigin("https://domain.com"); + other.addAllowedHeader("header1"); + other.addAllowedMethod(HttpMethod.PUT.name()); + + CorsConfiguration combinedConfig = config.combine(new CorsConfiguration()).combine(other); + assertThat(combinedConfig.getAllowedOrigins()).containsExactly("https://domain.com"); + assertThat(combinedConfig.getAllowedHeaders()).containsExactly("header1"); + assertThat(combinedConfig.getAllowedMethods()).containsExactly(HttpMethod.PUT.name()); + assertThat(combinedConfig.checkHttpMethod(HttpMethod.POST)).isNull(); + + combinedConfig = other.combine(config.combine(new CorsConfiguration())); + assertThat(combinedConfig.getAllowedOrigins()).containsExactly("https://domain.com"); + assertThat(combinedConfig.getAllowedHeaders()).containsExactly("header1"); + assertThat(combinedConfig.getAllowedMethods()).containsExactly(HttpMethod.PUT.name()); + assertThat(combinedConfig.checkHttpMethod(HttpMethod.POST)).isNull(); + + combinedConfig = new CorsConfiguration().combine(config).combine(other); + assertThat(combinedConfig.getAllowedOrigins()).containsExactly("https://domain.com"); + assertThat(combinedConfig.getAllowedHeaders()).containsExactly("header1"); + assertThat(combinedConfig.getAllowedMethods()).containsExactly(HttpMethod.PUT.name()); + assertThat(combinedConfig.checkHttpMethod(HttpMethod.POST)).isNull(); + + combinedConfig = new CorsConfiguration().combine(config); + assertThat(combinedConfig.checkHttpMethod(HttpMethod.POST)) + .containsExactly(HttpMethod.GET, HttpMethod.HEAD, HttpMethod.POST); + combinedConfig.addAllowedHeader("header1"); + combinedConfig.addAllowedMethod("PATCH"); + assertThat(combinedConfig.getAllowedHeaders()).containsExactly("*", "header1"); + assertThat(combinedConfig.getAllowedMethods()).containsExactly("GET", "HEAD", "POST", "PATCH"); + } + @Test void combinePatternWithDefaultPermitValues() { CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues();