diff --git a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java index 26216c377b495..fab22abc2fc80 100644 --- a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java +++ b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/SmallRyeOpenApiProcessor.java @@ -89,6 +89,7 @@ import io.quarkus.runtime.LaunchMode; import io.quarkus.runtime.util.ClassPathUtils; import io.quarkus.security.Authenticated; +import io.quarkus.security.PermissionsAllowed; import io.quarkus.smallrye.openapi.OpenApiFilter; import io.quarkus.smallrye.openapi.common.deployment.SmallRyeOpenApiConfig; import io.quarkus.smallrye.openapi.deployment.filter.AutoRolesAllowedFilter; @@ -565,6 +566,9 @@ private OASFilter getAutoRolesAllowedFilter( Map> rolesAllowedMethodReferences = getRolesAllowedMethodReferences( apiFilteredIndexViewBuildItem); + getPermissionsAllowedMethodReferences(apiFilteredIndexViewBuildItem) + .forEach(k -> rolesAllowedMethodReferences.putIfAbsent(k, List.of())); + List authenticatedMethodReferences = getAuthenticatedMethodReferences( apiFilteredIndexViewBuildItem); @@ -630,6 +634,17 @@ private Map> getRolesAllowedMethodReferences(OpenApiFiltere })); } + private List getPermissionsAllowedMethodReferences( + OpenApiFilteredIndexViewBuildItem indexViewBuildItem) { + return indexViewBuildItem.getIndex() + .getAnnotations(DotName.createSimple(PermissionsAllowed.class)) + .stream() + .flatMap(SmallRyeOpenApiProcessor::getMethods) + .map(e -> JandexUtil.createUniqueMethodReference(e.getKey().declaringClass(), e.getKey())) + .distinct() + .toList(); + } + private List getAuthenticatedMethodReferences(OpenApiFilteredIndexViewBuildItem indexViewBuildItem) { return indexViewBuildItem.getIndex() .getAnnotations(DotName.createSimple(Authenticated.class.getName())) diff --git a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/AutoSecurityRolesAllowedTestCase.java b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/AutoSecurityRolesAllowedTestCase.java index 7a8ee7f8df6f9..7a95fe1aaf5f3 100644 --- a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/AutoSecurityRolesAllowedTestCase.java +++ b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/AutoSecurityRolesAllowedTestCase.java @@ -26,7 +26,8 @@ class AutoSecurityRolesAllowedTestCase { static QuarkusUnitTest runner = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar .addClasses(ResourceBean.class, OpenApiResourceSecuredAtClassLevel.class, - OpenApiResourceSecuredAtMethodLevel.class, OpenApiResourceSecuredAtMethodLevel2.class) + OpenApiResourceSecuredAtClassLevel2.class, OpenApiResourceSecuredAtMethodLevel.class, + OpenApiResourceSecuredAtMethodLevel2.class) .addAsResource( new StringAsset("quarkus.smallrye-openapi.security-scheme=jwt\n" + "quarkus.smallrye-openapi.security-scheme-name=JWTCompanyAuthentication\n" @@ -71,6 +72,7 @@ void testAutoSecurityRequirement() { .body("paths.'/resource2/test-security/methodLevel/public'.get.security", nullValue()) .body("paths.'/resource2/test-security/annotated/documented'.get.security", defaultSecurity) .body("paths.'/resource2/test-security/methodLevel/3'.get.security", defaultSecurity) + .body("paths.'/resource2/test-security/methodLevel/4'.get.security", defaultSecurity) .and() // OpenApiResourceSecuredAtClassLevel .body("paths.'/resource2/test-security/classLevel/1'.get.security", defaultSecurity) @@ -79,7 +81,10 @@ void testAutoSecurityRequirement() { .body("paths.'/resource2/test-security/classLevel/4'.get.security", defaultSecurity) .and() // OpenApiResourceSecuredAtMethodLevel2 - .body("paths.'/resource3/test-security/annotated'.get.security", schemeArray("AtClassLevel")); + .body("paths.'/resource3/test-security/annotated'.get.security", schemeArray("AtClassLevel")) + .and() + // OpenApiResourceSecuredAtClassLevel2 + .body("paths.'/resource3/test-security/classLevel-2/1'.get.security", defaultSecurity); } @Test @@ -153,7 +158,19 @@ void testOpenAPIAnnotations() { Matchers.equalTo("Who are you?")) .and() .body("paths.'/resource2/test-security/methodLevel/3'.get.responses.403.description", - Matchers.equalTo("You cannot do that.")); + Matchers.equalTo("You cannot do that.")) + .and() + .body("paths.'/resource2/test-security/methodLevel/4'.get.responses.401.description", + Matchers.equalTo("Not Authorized")) + .and() + .body("paths.'/resource2/test-security/methodLevel/4'.get.responses.403.description", + Matchers.equalTo("Not Allowed")) + .and() + .body("paths.'/resource3/test-security/classLevel-2/1'.get.responses.401.description", + Matchers.equalTo("Not Authorized")) + .and() + .body("paths.'/resource3/test-security/classLevel-2/1'.get.responses.403.description", + Matchers.equalTo("Not Allowed")); } } diff --git a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceSecuredAtClassLevel2.java b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceSecuredAtClassLevel2.java new file mode 100644 index 0000000000000..5267e418b7558 --- /dev/null +++ b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceSecuredAtClassLevel2.java @@ -0,0 +1,26 @@ +package io.quarkus.smallrye.openapi.test.jaxrs; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +import org.eclipse.microprofile.openapi.annotations.servers.Server; +import org.eclipse.microprofile.openapi.annotations.tags.Tag; + +import io.quarkus.security.PermissionsAllowed; + +@Path("/resource3") +@Tag(name = "test") +@Server(url = "serverUrl") +@PermissionsAllowed("secure:read") +public class OpenApiResourceSecuredAtClassLevel2 { + + @SuppressWarnings("unused") + private ResourceBean resourceBean; + + @GET + @Path("/test-security/classLevel-2/1") + public String secureEndpoint1() { + return "secret"; + } + +} diff --git a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceSecuredAtMethodLevel.java b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceSecuredAtMethodLevel.java index 9e1d4c5cf6da9..24bb8695b83d9 100644 --- a/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceSecuredAtMethodLevel.java +++ b/extensions/smallrye-openapi/deployment/src/test/java/io/quarkus/smallrye/openapi/test/jaxrs/OpenApiResourceSecuredAtMethodLevel.java @@ -10,6 +10,8 @@ import org.eclipse.microprofile.openapi.annotations.servers.Server; import org.eclipse.microprofile.openapi.annotations.tags.Tag; +import io.quarkus.security.PermissionsAllowed; + @Path("/resource2") @Tag(name = "test") @Server(url = "serverUrl") @@ -76,4 +78,11 @@ public String secureEndpoint3() { return "secret"; } + @GET + @Path("/test-security/methodLevel/4") + @PermissionsAllowed("secure:read") + public String secureEndpoint5() { + return "secret"; + } + }