Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2.13: Do not support any Origin by default if CORS is enabled #33439

Merged
merged 2 commits into from
May 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class UriTagCorsTest {
.overrideConfigKey("quarkus.micrometer.binder.http-server.enabled", "true")
.overrideConfigKey("quarkus.micrometer.binder.vertx.enabled", "true")
.overrideConfigKey("quarkus.http.cors", "true")
.overrideConfigKey("quarkus.http.cors.origins", "*")
.withApplicationRoot((jar) -> jar
.addClasses(Util.class,
VertxWebEndpoint.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
quarkus.http.cors=true
quarkus.http.cors.origins=*
# whitespaces added to test that they are not taken into account config is parsed
quarkus.http.cors.methods=GET, OPTIONS, POST
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
quarkus.http.cors=true
quarkus.http.cors=true
quarkus.http.cors.origins=*
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ public class OpenApiHttpRootDefaultPathTestCase {
static QuarkusUnitTest runner = new QuarkusUnitTest()
.withApplicationRoot((jar) -> jar
.addClasses(OpenApiRoute.class)
.addAsResource(new StringAsset("quarkus.http.root-path=/foo"), "application.properties"));
.addAsResource(new StringAsset("quarkus.http.root-path=/foo\n" +
"quarkus.http.cors=true\n"
+ "quarkus.http.cors.origins=*"), "application.properties"));

@Test
public void testOpenApiPathAccessResource() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.quarkus.vertx.http.cors;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.nullValue;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.test.QuarkusUnitTest;

class CORSSameOriginWithoutOriginConfigTestCase {

@RegisterExtension
static QuarkusUnitTest runner = new QuarkusUnitTest()
.withApplicationRoot((jar) -> jar
.addClasses(BeanRegisteringRoute.class)
.addAsResource("conf/cors-same-origin-only.properties", "application.properties"));

@Test
void corsSameOriginRequest() {
String origin = "http://localhost:8081";
given().header("Origin", origin)
.get("/test").then()
.statusCode(200)
.header("Access-Control-Allow-Origin", origin);
}

@Test
void corsInvalidSameOriginRequest() {
String origin = "http://externalhost:8081";
given().header("Origin", origin)
.get("/test").then()
.statusCode(403)
.header("Access-Control-Allow-Origin", nullValue());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class CORSSecurityTestCase {

private static final String APP_PROPS = "" +
"quarkus.http.cors=true\n" +
"quarkus.http.cors.origins=*\n" +
"quarkus.http.cors.methods=GET, OPTIONS, POST\n" +
"quarkus.http.auth.basic=true\n" +
"quarkus.http.auth.policy.r1.roles-allowed=test\n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class CORSWildcardSecurityTestCase {

private static final String APP_PROPS = "" +
"quarkus.http.cors=true\n" +
"quarkus.http.cors.origins=*\n" +
"quarkus.http.auth.basic=true\n" +
"quarkus.http.auth.policy.r1.roles-allowed=test\n" +
"quarkus.http.auth.permission.roles1.paths=/test\n" +
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
quarkus.http.cors=true
quarkus.http.cors.origins=*
# whitespaces added to test that they are not taken into account config is parsed
quarkus.http.cors.methods=GET, OPTIONS, POST
quarkus.http.cors.access-control-allow-credentials=true
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
quarkus.http.cors=true
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ public class CORSConfig {
* Comma separated list of valid URLs, e.g.: http://www.quarkus.io,http://localhost:3000
* In case an entry of the list is surrounded by forward slashes,
* it is interpreted as a regular expression.
* The filter allows any origin if this is not set.
*
* default: returns any requested origin as valid
*/
@ConfigItem
@ConvertWith(TrimmedStringConverter.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,20 @@ public class CORSFilter implements Handler<RoutingContext> {
// Must be static because the filter is created(deployed) at build time and runtime config is still not available
final CORSConfig corsConfig;

final List<Pattern> allowedOriginsRegex;
private final boolean wildcardOrigin;
private final List<Pattern> allowedOriginsRegex;
private final List<HttpMethod> configuredHttpMethods;

public CORSFilter(CORSConfig corsConfig) {
this.corsConfig = corsConfig;
this.allowedOriginsRegex = parseAllowedOriginsRegex(this.corsConfig.origins);
configuredHttpMethods = createConfiguredHttpMethods(this.corsConfig.methods);
this.wildcardOrigin = isOriginConfiguredWithWildcard(this.corsConfig.origins);
this.allowedOriginsRegex = this.wildcardOrigin ? List.of() : parseAllowedOriginsRegex(this.corsConfig.origins);
this.configuredHttpMethods = createConfiguredHttpMethods(this.corsConfig.methods);
}

private List<HttpMethod> createConfiguredHttpMethods(Optional<List<String>> methods) {
if (methods.isEmpty()) {
return Collections.emptyList();
return List.of();
}
List<String> corsConfigMethods = methods.get();
List<HttpMethod> result = new ArrayList<>(corsConfigMethods.size());
Expand All @@ -53,6 +55,10 @@ public static boolean isConfiguredWithWildcard(Optional<List<String>> optionalLi
return list.isEmpty() || (list.size() == 1 && "*".equals(list.get(0)));
}

private static boolean isOriginConfiguredWithWildcard(Optional<List<String>> origins) {
return !origins.isEmpty() && origins.get().size() == 1 && "*".equals(origins.get().get(0));
}

/**
* Parse the provided allowed origins for any regexes
*
Expand All @@ -61,7 +67,7 @@ public static boolean isConfiguredWithWildcard(Optional<List<String>> optionalLi
*/
public static List<Pattern> parseAllowedOriginsRegex(Optional<List<String>> allowedOrigins) {
if (allowedOrigins == null || !allowedOrigins.isPresent()) {
return Collections.emptyList();
return List.of();
}

// extract configured origins and find any Regular Expressions
Expand Down Expand Up @@ -176,8 +182,16 @@ public void handle(RoutingContext event) {
processRequestedHeaders(response, requestedHeaders);
}

boolean allowsOrigin = isConfiguredWithWildcard(corsConfig.origins) || corsConfig.origins.get().contains(origin)
|| isOriginAllowedByRegex(allowedOriginsRegex, origin) || isSameOrigin(request, origin);
boolean allowsOrigin = wildcardOrigin;
if (!allowsOrigin) {
if (!corsConfig.origins.isEmpty()) {
allowsOrigin = corsConfig.origins.get().contains(origin)
|| isOriginAllowedByRegex(allowedOriginsRegex, origin)
|| isSameOrigin(request, origin);
} else {
allowsOrigin = isSameOrigin(request, origin);
}
}

if (allowsOrigin) {
response.headers().set(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, origin);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ quarkus.http.auth.permission.post-logout.paths=/tenant-logout/post-logout
quarkus.http.auth.permission.post-logout.policy=permit

quarkus.http.cors=true
quarkus.http.cors.origins=*
quarkus.http.auth.proactive=false
quarkus.http.proxy.enable-forwarded-prefix=true
quarkus.http.proxy.allow-forwarded=true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
quarkus.http.cors=true
quarkus.http.cors.origins=*

quarkus.oidc.token-cache.max-size=3

Expand Down Expand Up @@ -115,4 +116,4 @@ quarkus.native.additional-build-args=-H:IncludeResources=.*\\.pem


quarkus.log.category."io.quarkus.oidc.runtime.CodeAuthenticationMechanism".min-level=TRACE
quarkus.log.category."io.quarkus.oidc.runtime.CodeAuthenticationMechanism".level=TRACE
quarkus.log.category."io.quarkus.oidc.runtime.CodeAuthenticationMechanism".level=TRACE
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ quarkus.oidc.tls.key-store-password=password
quarkus.native.additional-build-args=-H:IncludeResources=.*\\.jks

quarkus.http.cors=true
quarkus.http.cors.origins=*

quarkus.http.auth.basic=true
quarkus.security.users.embedded.enabled=true
Expand Down