Skip to content

Commit

Permalink
Support '*' in CORS filter configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
xumk authored and gsmet committed Sep 19, 2020
1 parent 5613ea6 commit 8f9302b
Show file tree
Hide file tree
Showing 7 changed files with 354 additions and 16 deletions.
14 changes: 7 additions & 7 deletions docs/src/main/asciidoc/http-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,13 @@ following properties will be applied before passing the request on to its actual
[cols="<m,<m,<2",options="header"]
|===
|Property Name|Default|Description
|quarkus.http.cors.origins||The comma-separated list of origins allowed for CORS. The filter allows any origin if this is not
set.
|quarkus.http.cors.methods||The comma-separated list of HTTP methods allowed for CORS. The filter allows any method if this is
not set.
|quarkus.http.cors.headers||The comma-separated list of HTTP headers allowed for CORS. The filter allows any header if this is
not set.
|quarkus.http.cors.exposed-headers||The comma-separated list of HTTP headers exposed in CORS.
|quarkus.http.cors.origins|*|The comma-separated list of origins allowed for CORS. The filter allows any origin if this is not set or set to '*'.
|quarkus.http.cors.methods|*|The comma-separated list of HTTP methods allowed for CORS. The filter allows any method if this is
not set or set to '*'.
|quarkus.http.cors.headers|*|The comma-separated list of HTTP headers allowed for CORS. The filter allows any header if this is
not set or set to '*'.
|quarkus.http.cors.exposed-headers|*|The comma-separated list of HTTP headers exposed in CORS. The filter allows any headers to be exposed if this is
not set or set to '*'.
|quarkus.http.cors.access-control-max-age||The duration (see note below) indicating how long the results of a pre-flight request can be cached.
This value will be returned in a `Access-Control-Max-Age` response header.
|quarkus.http.cors.access-control-allow-credentials||Boolean value to tell the browsers to expose the response to front-end JavaScript code
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import io.quarkus.test.QuarkusUnitTest;
import io.quarkus.vertx.http.security.PathHandler;

public class CoresSecurityTestCase {
public class CORSSecurityTestCase {

private static final String APP_PROPS = "" +
"quarkus.http.cors=true\n" +
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package io.quarkus.vertx.http.cors;

import static io.restassured.RestAssured.given;

import java.util.function.Supplier;

import org.hamcrest.Matchers;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.security.test.utils.TestIdentityController;
import io.quarkus.security.test.utils.TestIdentityProvider;
import io.quarkus.test.QuarkusUnitTest;
import io.quarkus.vertx.http.security.PathHandler;

public class CORSWildcardSecurityTestCase {

private static final String APP_PROPS = "" +
"quarkus.http.cors=true\n" +
"quarkus.http.auth.basic=true\n" +
"quarkus.http.auth.policy.r1.roles-allowed=test\n" +
"quarkus.http.auth.permission.roles1.paths=/test\n" +
"quarkus.http.auth.permission.roles1.policy=r1\n";

@RegisterExtension
static QuarkusUnitTest test = new QuarkusUnitTest().setArchiveProducer(new Supplier<JavaArchive>() {
@Override
public JavaArchive get() {
return ShrinkWrap.create(JavaArchive.class)
.addClasses(TestIdentityProvider.class, TestIdentityController.class, PathHandler.class)
.addAsResource(new StringAsset(APP_PROPS), "application.properties");
}
});

@BeforeAll
public static void setup() {
TestIdentityController.resetRoles().add("test", "test", "test").add("user", "user", "user");
}

@Test
@DisplayName("Handles a preflight CORS request correctly")
public void corsPreflightTest() {
String origin = "http://custom.origin.quarkus";
String methods = "GET,POST";
String headers = "X-Custom";
given().header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when()
.options("/test").then()
.statusCode(200)
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers);

given().header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when()
.auth().basic("test", "test")
.options("/test").then()
.statusCode(200)
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers);

given().header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when()
.auth().basic("test", "wrongpassword")
.options("/test").then()
.statusCode(200)
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers);

given().header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when()
.auth().basic("user", "user")
.options("/test").then()
.statusCode(200)
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers);
}

@Test
@DisplayName("Handles a direct CORS request correctly")
public void corsNoPreflightTest() {
String origin = "http://custom.origin.quarkus";
String methods = "GET,POST";
String headers = "X-Custom";
given().header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when()
.log().headers()
.get("/test").then()
.statusCode(401)
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers);

given().header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when()
.auth().basic("test", "test")
.log().headers()
.get("/test").then()
.statusCode(200)
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers)
.body(Matchers.equalTo("test:/test"));

given().header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when()
.auth().basic("test", "wrongpassword")
.log().headers()
.get("/test").then()
.statusCode(401)
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers);

given().header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when()
.auth().basic("user", "user")
.log().headers()
.get("/test").then()
.statusCode(403)
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package io.quarkus.vertx.http.cors;

import static io.restassured.RestAssured.given;

import java.util.function.Supplier;

import org.hamcrest.Matchers;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.security.test.utils.TestIdentityController;
import io.quarkus.security.test.utils.TestIdentityProvider;
import io.quarkus.test.QuarkusUnitTest;
import io.quarkus.vertx.http.security.PathHandler;

public class CORSWildcardStarSecurityTestCase {

private static final String APP_PROPS = "" +
"quarkus.http.cors=true\n" +
"quarkus.http.cors.methods=*\n" +
"quarkus.http.cors.origins=*\n" +
"quarkus.http.cors.headers=*\n" +
"quarkus.http.auth.basic=true\n" +
"quarkus.http.auth.policy.r1.roles-allowed=test\n" +
"quarkus.http.auth.permission.roles1.paths=/test\n" +
"quarkus.http.auth.permission.roles1.policy=r1\n";

@RegisterExtension
static QuarkusUnitTest test = new QuarkusUnitTest().setArchiveProducer(new Supplier<JavaArchive>() {
@Override
public JavaArchive get() {
return ShrinkWrap.create(JavaArchive.class)
.addClasses(TestIdentityProvider.class, TestIdentityController.class, PathHandler.class)
.addAsResource(new StringAsset(APP_PROPS), "application.properties");
}
});

@BeforeAll
public static void setup() {
TestIdentityController.resetRoles().add("test", "test", "test").add("user", "user", "user");
}

@Test
@DisplayName("Handles a preflight CORS request correctly")
public void corsPreflightTest() {
String origin = "http://custom.origin.quarkus";
String methods = "GET,POST,OPTIONS,DELETE";
String headers = "X-Custom,B-Custom,Test-Headers";
given().header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when()
.options("/test").then()
.statusCode(200)
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers);

given().header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when()
.auth().basic("test", "test")
.options("/test").then()
.statusCode(200)
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers);

given().header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when()
.auth().basic("test", "wrongpassword")
.options("/test").then()
.statusCode(200)
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers);

given().header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when()
.auth().basic("user", "user")
.options("/test").then()
.statusCode(200)
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers);
}

@Test
@DisplayName("Handles a direct CORS request correctly")
public void corsNoPreflightTest() {
String origin = "http://custom.origin.quarkus";
String methods = "GET,POST,OPTIONS,DELETE";
String headers = "X-Custom,B-Custom,Test-Headers";
given().header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when()
.log().headers()
.get("/test").then()
.statusCode(401)
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers);

given().header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when()
.auth().basic("test", "test")
.log().headers()
.get("/test").then()
.statusCode(200)
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers)
.body(Matchers.equalTo("test:/test"));

given().header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when()
.auth().basic("test", "wrongpassword")
.log().headers()
.get("/test").then()
.statusCode(401)
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers);

given().header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when()
.auth().basic("user", "user")
.log().headers()
.get("/test").then()
.statusCode(403)
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConvertWith;
import io.quarkus.runtime.configuration.TrimmedStringConverter;
import io.vertx.core.http.HttpMethod;

@ConfigGroup
public class CORSConfig {
Expand All @@ -34,7 +33,7 @@ public class CORSConfig {
* default: returns any requested method as valid
*/
@ConfigItem
public Optional<List<HttpMethod>> methods;
public Optional<List<String>> methods;

/**
* HTTP headers allowed for CORS
Expand Down
Loading

0 comments on commit 8f9302b

Please sign in to comment.