Repository: quarkusio/quarkus
Issue: Unexpected behavior of path matching for configuration-based security policies

If I have a permission for a path like
`quarkus.http.auth.permission.mypermission.paths=/a/*`
Then requests to `/a/anything` should be matched to it, but they are not.

If I change it to 
`quarkus.http.auth.permission.mypermission.paths=/a*`
Only then requests to `/a/anything` will start getting authorization checks.

This is contradictory to what is described in the documentation https://quarkus.io/guides/security#matching-on-paths-methods

Changed files:
extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/security/RolesAllowedTestCase.java
extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/PathMatchingHttpSecurityPolicy.java

diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/security/RolesAllowedTestCase.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/security/RolesAllowedTestCase.java
index 7278e611a42..614fe67f4c8 100644
--- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/security/RolesAllowedTestCase.java
+++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/security/RolesAllowedTestCase.java
@@ -20,9 +20,9 @@ public class RolesAllowedTestCase {
             "quarkus.http.auth.basic=true\\n" +
             "quarkus.http.auth.policy.r1.roles-allowed=test\\n" +
             "quarkus.http.auth.policy.r2.roles-allowed=admin\\n" +
-            "quarkus.http.auth.permission.roles1.paths=/roles1,/deny,/permit,/combined\\n" +
+            "quarkus.http.auth.permission.roles1.paths=/roles1,/deny,/permit,/combined,/wildcard1/*,/wildcard2*\\n" +
             "quarkus.http.auth.permission.roles1.policy=r1\\n" +
-            "quarkus.http.auth.permission.roles2.paths=/roles2,/deny,/permit/combined\\n" +
+            "quarkus.http.auth.permission.roles2.paths=/roles2,/deny,/permit/combined,/wildcard3/*\\n" +
             "quarkus.http.auth.permission.roles2.policy=r2\\n" +
             "quarkus.http.auth.permission.permit1.paths=/permit\\n" +
             "quarkus.http.auth.permission.permit1.policy=permit\\n" +
@@ -178,4 +178,94 @@ public void testRolesAllowedCombinedWithDenyAll() {
                 .assertThat()
                 .statusCode(403);
     }
+
+    @Test
+    public void testWildcardMatchingWithSlash() {
+        RestAssured
+                .given()
+                .auth()
+                .preemptive()
+                .basic("test", "test")
+                .when()
+                .get("/wildcard1/a")
+                .then()
+                .assertThat()
+                .statusCode(200);
+
+        RestAssured
+                .given()
+                .auth()
+                .preemptive()
+                .basic("test", "test")
+                .when()
+                .get("/wildcard1/a/")
+                .then()
+                .assertThat()
+                .statusCode(200);
+
+        RestAssured
+                .given()
+                .when()
+                .get("/wildcard1/a")
+                .then()
+                .assertThat()
+                .statusCode(401);
+
+        RestAssured
+                .given()
+                .when()
+                .get("/wildcard1/a/")
+                .then()
+                .assertThat()
+                .statusCode(401);
+
+        RestAssured
+                .given()
+                .when()
+                .get("/wildcard3XXX")
+                .then()
+                .assertThat()
+                .statusCode(200);
+    }
+
+    @Test
+    public void testWildcardMatchingWithoutSlash() {
+        RestAssured
+                .given()
+                .auth()
+                .preemptive()
+                .basic("test", "test")
+                .when()
+                .get("/wildcard2/a")
+                .then()
+                .assertThat()
+                .statusCode(200);
+
+        RestAssured
+                .given()
+                .auth()
+                .preemptive()
+                .basic("test", "test")
+                .when()
+                .get("/wildcard2")
+                .then()
+                .assertThat()
+                .statusCode(200);
+
+        RestAssured
+                .given()
+                .when()
+                .get("/wildcard2")
+                .then()
+                .assertThat()
+                .statusCode(401);
+
+        RestAssured
+                .given()
+                .when()
+                .get("/wildcard2/a")
+                .then()
+                .assertThat()
+                .statusCode(401);
+    }
 }
diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/PathMatchingHttpSecurityPolicy.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/PathMatchingHttpSecurityPolicy.java
index 1d1b754453a..24badd42743 100644
--- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/PathMatchingHttpSecurityPolicy.java
+++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/PathMatchingHttpSecurityPolicy.java
@@ -93,7 +93,10 @@ void init(HttpBuildTimeConfig config, Map<String, Supplier<HttpSecurityPolicy>>
                     List<HttpMatcher> perms = new ArrayList<>();
                     tempMap.put(path, perms);
                     perms.add(m);
-                    if (path.endsWith("*")) {
+                    if (path.endsWith("/*")) {
+                        String stripped = path.substring(0, path.length() - 2);
+                        pathMatcher.addPrefixPath(stripped.isEmpty() ? "/" : stripped, perms);
+                    } else if (path.endsWith("*")) {
                         pathMatcher.addPrefixPath(path.substring(0, path.length() - 1), perms);
                     } else {
                         pathMatcher.addExactPath(path, perms);