From 94ed0d39cc641c31a8de67f70ea147e41cc2a4a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vav=C5=99=C3=ADk?= Date: Sat, 25 May 2024 17:47:11 +0200 Subject: [PATCH] Fix priority of interceptors preventing repeated checks --- .../StandardSecurityCheckInterceptor.java | 8 ++-- .../security/RolesAllowedJaxRsTestCase.java | 16 +++++++ .../test/security/RolesAllowedService.java | 16 +++++++ .../security/RolesAllowedServiceResource.java | 45 +++++++++++++++++++ .../StandardSecurityCheckInterceptor.java | 8 ++-- 5 files changed, 85 insertions(+), 8 deletions(-) diff --git a/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/StandardSecurityCheckInterceptor.java b/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/StandardSecurityCheckInterceptor.java index 657be48853e07..eb82be3eabf5d 100644 --- a/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/StandardSecurityCheckInterceptor.java +++ b/extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/StandardSecurityCheckInterceptor.java @@ -58,7 +58,7 @@ public Object intercept(InvocationContext ic) throws Exception { */ @Interceptor @RolesAllowed("") - @Priority(Interceptor.Priority.PLATFORM_BEFORE) + @Priority(Interceptor.Priority.LIBRARY_BEFORE - 100) public static final class RolesAllowedInterceptor extends StandardSecurityCheckInterceptor { } @@ -68,7 +68,7 @@ public static final class RolesAllowedInterceptor extends StandardSecurityCheckI */ @Interceptor @PermissionsAllowed("") - @Priority(Interceptor.Priority.PLATFORM_BEFORE) + @Priority(Interceptor.Priority.LIBRARY_BEFORE - 100) public static final class PermissionsAllowedInterceptor extends StandardSecurityCheckInterceptor { } @@ -78,7 +78,7 @@ public static final class PermissionsAllowedInterceptor extends StandardSecurity */ @Interceptor @PermitAll - @Priority(Interceptor.Priority.PLATFORM_BEFORE) + @Priority(Interceptor.Priority.LIBRARY_BEFORE - 100) public static final class PermitAllInterceptor extends StandardSecurityCheckInterceptor { } @@ -88,7 +88,7 @@ public static final class PermitAllInterceptor extends StandardSecurityCheckInte */ @Interceptor @Authenticated - @Priority(Interceptor.Priority.PLATFORM_BEFORE) + @Priority(Interceptor.Priority.LIBRARY_BEFORE - 100) public static final class AuthenticatedInterceptor extends StandardSecurityCheckInterceptor { } diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/RolesAllowedJaxRsTestCase.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/RolesAllowedJaxRsTestCase.java index 6df18df664b07..67cc925f5e5f6 100644 --- a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/RolesAllowedJaxRsTestCase.java +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/RolesAllowedJaxRsTestCase.java @@ -1,5 +1,6 @@ package io.quarkus.resteasy.reactive.server.test.security; +import static io.quarkus.resteasy.reactive.server.test.security.RolesAllowedService.EVENT_BUS_MESSAGES; import static org.hamcrest.Matchers.is; import java.io.IOException; @@ -14,6 +15,7 @@ import jakarta.ws.rs.ext.MessageBodyReader; import jakarta.ws.rs.ext.Provider; +import org.awaitility.Awaitility; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -90,6 +92,20 @@ public void testSecurityRunsBeforeValidation() { Assertions.assertFalse(read); } + @Test + public void testSecurityInterceptorsAfterHttpRequestCompleted() { + RestAssured + .given() + .auth().preemptive().basic("user", "user") + .body("message one") + .post("/roles-service/secured-event-bus") + .then() + .statusCode(204); + Awaitility.await().until(() -> !EVENT_BUS_MESSAGES.isEmpty()); + Assertions.assertEquals(1, EVENT_BUS_MESSAGES.size(), EVENT_BUS_MESSAGES.toString()); + Assertions.assertEquals("permit all message one", EVENT_BUS_MESSAGES.get(0)); + } + static volatile boolean read = false; @Provider diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/RolesAllowedService.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/RolesAllowedService.java index 7a4d5e2a247bd..083b15faddb1f 100644 --- a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/RolesAllowedService.java +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/RolesAllowedService.java @@ -1,14 +1,19 @@ package io.quarkus.resteasy.reactive.server.test.security; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + import jakarta.annotation.security.PermitAll; import jakarta.annotation.security.RolesAllowed; import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.context.control.ActivateRequestContext; @ApplicationScoped public class RolesAllowedService { public static final String SERVICE_HELLO = "Hello from Service!"; public static final String SERVICE_BYE = "Bye from Service!"; + public static final List EVENT_BUS_MESSAGES = new CopyOnWriteArrayList<>(); @RolesAllowed("admin") public String hello() { @@ -20,4 +25,15 @@ public String bye() { return SERVICE_BYE; } + @PermitAll + @ActivateRequestContext + void receivePermitAllMessage(String m) { + EVENT_BUS_MESSAGES.add("permit all " + m); + } + + @RolesAllowed("admin") + @ActivateRequestContext + void receiveRolesAllowedMessage(String m) { + EVENT_BUS_MESSAGES.add("roles allowed " + m); + } } diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/RolesAllowedServiceResource.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/RolesAllowedServiceResource.java index 660dfad5adcad..12ecf9c9752a4 100644 --- a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/RolesAllowedServiceResource.java +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/security/RolesAllowedServiceResource.java @@ -1,16 +1,30 @@ package io.quarkus.resteasy.reactive.server.test.security; import jakarta.annotation.security.RolesAllowed; +import jakarta.enterprise.event.Observes; import jakarta.inject.Inject; import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; +import io.quarkus.runtime.ShutdownEvent; +import io.quarkus.runtime.StartupEvent; +import io.vertx.core.Vertx; +import io.vertx.mutiny.core.eventbus.EventBus; +import io.vertx.mutiny.core.eventbus.MessageConsumer; + @Path("/roles-service") public class RolesAllowedServiceResource { + private MessageConsumer permitAllConsumer; + private MessageConsumer rolesAllowedConsumer; + @Inject RolesAllowedService rolesAllowedService; + @Inject + EventBus bus; + @Path("/hello") @RolesAllowed({ "user", "admin" }) @GET @@ -23,4 +37,35 @@ public String getServiceHello() { public String getServiceBye() { return rolesAllowedService.bye(); } + + @Path("/secured-event-bus") + @POST + public void sendMessage(String message) { + bus.send("roles-allowed-message", message); + bus.send("permit-all-message", message); + } + + void observeStartup(@Observes StartupEvent startupEvent, EventBus eventBus, Vertx vertx) { + permitAllConsumer = eventBus + . consumer("permit-all-message") + .handler(msg -> rolesAllowedService.receivePermitAllMessage(msg.body())); + + // this must always fail because the authorization is happening in a blank CDI request context + rolesAllowedConsumer = eventBus + . consumer("roles-allowed-message") + .handler(msg -> vertx.executeBlocking(() -> { + // make sure authentication is attempted on a worker thread to prevent blocking event loop + rolesAllowedService.receiveRolesAllowedMessage(msg.body()); + return null; + })); + } + + void observerShutdown(@Observes ShutdownEvent shutdownEvent) { + if (permitAllConsumer != null) { + permitAllConsumer.unregister().await().indefinitely(); + } + if (rolesAllowedConsumer != null) { + rolesAllowedConsumer.unregister().await().indefinitely(); + } + } } diff --git a/extensions/resteasy-reactive/rest/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/StandardSecurityCheckInterceptor.java b/extensions/resteasy-reactive/rest/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/StandardSecurityCheckInterceptor.java index 9f86466ac25d7..a58c53c83ad62 100644 --- a/extensions/resteasy-reactive/rest/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/StandardSecurityCheckInterceptor.java +++ b/extensions/resteasy-reactive/rest/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/StandardSecurityCheckInterceptor.java @@ -54,7 +54,7 @@ private boolean alreadyDoneByEagerSecurityHandler(Object methodWithFinishedCheck */ @Interceptor @RolesAllowed("") - @Priority(Interceptor.Priority.PLATFORM_BEFORE) + @Priority(Interceptor.Priority.LIBRARY_BEFORE - 100) public static final class RolesAllowedInterceptor extends StandardSecurityCheckInterceptor { } @@ -64,7 +64,7 @@ public static final class RolesAllowedInterceptor extends StandardSecurityCheckI */ @Interceptor @PermissionsAllowed("") - @Priority(Interceptor.Priority.PLATFORM_BEFORE) + @Priority(Interceptor.Priority.LIBRARY_BEFORE - 100) public static final class PermissionsAllowedInterceptor extends StandardSecurityCheckInterceptor { } @@ -74,7 +74,7 @@ public static final class PermissionsAllowedInterceptor extends StandardSecurity */ @Interceptor @PermitAll - @Priority(Interceptor.Priority.PLATFORM_BEFORE) + @Priority(Interceptor.Priority.LIBRARY_BEFORE - 100) public static final class PermitAllInterceptor extends StandardSecurityCheckInterceptor { } @@ -84,7 +84,7 @@ public static final class PermitAllInterceptor extends StandardSecurityCheckInte */ @Interceptor @Authenticated - @Priority(Interceptor.Priority.PLATFORM_BEFORE) + @Priority(Interceptor.Priority.LIBRARY_BEFORE - 100) public static final class AuthenticatedInterceptor extends StandardSecurityCheckInterceptor { }