quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.84k stars 2.7k forks source link

NPE during custom bean invocation via PreAuthorize annotation in Quarkus RESTEasy #44511

Open deidzen opened 1 week ago

deidzen commented 1 week ago

Describe the bug

According to documentation (https://quarkus.io/guides/spring-security#preauthorize), Quarkus supports custom bean invocation via PreAuthorize annotation before method executing

Image

But starting from 3.6.8 version (I personally checked 3.6.8, 3.9.5 and current 3.16.3), this functionality in Quarkus RESTEasy is not working, it throws NullPointerException.

I see that EagerSecurityFilter class mentioned in error stacktrace was changed in 3.6.8 version (https://github.com/quarkusio/quarkus/commit/6d76eafa5c7b28d0a9854695d0590f3db969c49d#diff-fbf38214479c02a3e1bae50b5b595d13c12c28e64d34246398151ef3b521e5db). Maybe that caused the issue.

Expected behavior

Custom bean is invoked through @PreAuthorize annotation succesfully

Actual behavior

NPE is thrown during custom bean invocation

java.lang.NullPointerException: Cannot load from object array because "<parameter2>" is null
    at io.quarkus.spring.security.check.PersonChecker_2d2da3d8eb389fe1c70f7b93d91d35c2a8f20142_CheckFor_check.check(Unknown Source)
    at io.quarkus.spring.security.runtime.interceptor.check.AbstractBeanMethodSecurityCheck.doApply(AbstractBeanMethodSecurityCheck.java:30)
    at io.quarkus.spring.security.runtime.interceptor.check.AbstractBeanMethodSecurityCheck.apply(AbstractBeanMethodSecurityCheck.java:26)
    at io.quarkus.resteasy.runtime.EagerSecurityFilter.applySecurityChecks(EagerSecurityFilter.java:127)
    at io.quarkus.resteasy.runtime.EagerSecurityFilter.filter(EagerSecurityFilter.java:78)
    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:276)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:415)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:378)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:356)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:70)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:429)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invokePropagateNotFound$6(SynchronousDispatcher.java:275)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:154)
    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:321)
    at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:157)
    at org.jboss.resteasy.core.SynchronousDispatcher.invokePropagateNotFound(SynchronousDispatcher.java:260)
    at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:86)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:151)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler$1.run(VertxRequestHandler.java:97)
    at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:627)
    at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2675)
    at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2654)
    at org.jboss.threads.EnhancedQueueExecutor.runThreadBody(EnhancedQueueExecutor.java:1627)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1594)
    at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:11)
    at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:11)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:842)
Resulted in: org.jboss.resteasy.spi.UnhandledException: java.lang.NullPointerException: Cannot load from object array because "<parameter2>" is null
    at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:357)
    at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:205)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:452)
    ... 17 more

How to Reproduce?

Reproducer: https://github.com/deidzen/quarkus-preauthorized-test

Steps to reproduce:

  1. Pull the reproducer.
  2. Run mvn clean test . 2 tests will fail with 500 error java.lang.NullPointerException: Cannot load from object array because "<parameter2>" is null

For compare you can switch to 3.6.7 Quarkus version (quarkus-3.6.7-resteasy branch) and try once again - tests will pass

Output of uname -a or ver

Microsoft Windows [Version 10.0.26100.2033]

Output of java -version

17.0.10, vendor: Oracle OpenJDK

Quarkus version or git rev

3.6.8+ (I personally checked 3.6.8, 3.9.5 and current 3.16.3)

Build tool (ie. output of mvnw --version or gradlew --version)

Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937)

Additional information

No response

sberyozkin commented 1 week ago

@deidzen While this issue is being addressed, you may want to to have a look at @PermissionChecker in Quarkus 3.17.0.CR1:

https://quarkus.io/version/main/guides/security-authorize-web-endpoints-reference#permission-checker

We believe it offers a simpler alternative to @PreAuthorize

michalvavrik commented 2 days ago

I see that EagerSecurityFilter class mentioned in error stacktrace was changed in 3.6.8 version (https://github.com/quarkusio/quarkus/commit/6d76eafa5c7b28d0a9854695d0590f3db969c49d#diff-fbf38214479c02a3e1bae50b5b595d13c12c28e64d34246398151ef3b521e5db). Maybe that caused the issue.

We keep changing it, that is nothing out of ordinary. I will put this issue on my (extended) list.