quarkusio / quarkus

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

Quarkus Security: @RolesAllowed crashes on class level but not on method level #14235

Closed vvavepacket closed 3 weeks ago

vvavepacket commented 3 years ago

Describe the bug

I'm currently using io.quarkus:quarkus-security and implemented ContainerRequestFilter as per this guide Custom JAX-RS SecurityContext. I have my REST classes annotated with @RolesAllowed on the class level but every time a request comes to one of the methods, I'm getting the below error

javax.enterprise.context.ContextNotActiveException: null
    at io.quarkus.arc.impl.ClientProxies.getDelegate(ClientProxies.java:40) ~[arc-1.10.2.Final.jar:1.10.2.Final]
    at io.quarkus.security.runtime.SecurityIdentityProxy_ClientProxy.arc$delegate(SecurityIdentityProxy_ClientProxy.zig:42) ~[quarkus:/:1.10.2.Final]
    at io.quarkus.security.runtime.SecurityIdentityProxy_ClientProxy.hasRole(SecurityIdentityProxy_ClientProxy.zig:398) ~[quarkus:/:1.10.2.Final]
    at io.quarkus.security.runtime.interceptor.check.RolesAllowedCheck.apply(RolesAllowedCheck.java:54) ~[quarkus-security-1.10.2.Final.jar:1.10.2.Final]
    at io.quarkus.security.runtime.interceptor.SecurityConstrainer.check(SecurityConstrainer.java:27) ~[quarkus-security-1.10.2.Final.jar:1.10.2.Final]
    at io.quarkus.security.runtime.interceptor.SecurityHandler.handle(SecurityHandler.java:23) ~[quarkus-security-1.10.2.Final.jar:1.10.2.Final]
    at io.quarkus.security.runtime.interceptor.RolesAllowedInterceptor.intercept(RolesAllowedInterceptor.java:29) ~[quarkus-security-1.10.2.Final.jar:1.10.2.Final]
    at io.quarkus.security.runtime.interceptor.RolesAllowedInterceptor_Bean.intercept(RolesAllowedInterceptor_Bean.zig:386) ~[quarkus:/:1.10.2.Final]
    at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41) ~[arc-1.10.2.Final.jar:1.10.2.Final]
    at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41) ~[arc-1.10.2.Final.jar:1.10.2.Final]
    at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32) ~[arc-1.10.2.Final.jar:1.10.2.Final]

It fails on my API method where I'm using RxJava constructs. It seems that when @RolesAllowed is class annotated, the context is not properly pass inside the chain RxJava constructs causing NPE.

The setup below doesn't work:

@Path("/demo")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@RolesAllowed("role1")
class DemoAPI(
    @Inject
    val personRepository: PersonRepository
) {

    @GET
    fun get(): CompletionStage<Response> {
        return personRepository.getPersons()
            .subscribeOn(Schedulers.io())
            .flatMapSingle { person ->
                // personRepository here is NULL and throws an error when trying to access. Context is lost.
                person.doSomething(personRepository)
            }
            .toList()
            .map {
                Response.ok().entity(it).build()
            }
            .toCompletionStage()
    }
}

However below setup works when annotated in the method

@Path("/demo")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
class DemoAPI(
    @Inject
    val personRepository: PersonRepository
) {

    @GET
    @RolesAllowed("role1")
    fun get(): CompletionStage<Response> {
        return personRepository.getPersons()
            .subscribeOn(Schedulers.io())
            .flatMapSingle { person ->
                // personRepository here is valid and no longer NULL
                person.doSomething(personRepository)
            }
            .toList()
            .map {
                Response.ok().entity(it).build()
            }
            .toCompletionStage()
    }
}

Expected behavior Injected classes should be accessible

Actual behavior Injected classes are null

To Reproduce

It is related to a previous issue, only difference is I'm using RxJava3 and context is not pass during chaining operations. If more details is required I can create a mini reproducer project.

Steps to reproduce the behavior:

  1. Annotate REST class with @RolesAllowed and do constructor injection for any dependencies
  2. Do RxJava3 chain calls in one of the methods of the REST class
  3. Access one of the injected variables inside the RxJava3 operations

Environment (please complete the following information):

Additional context I'm using RxJava3. It seems in one of the guides when using custom security authorization, we need to do context propagation. I tried adding smallrye-context-propagation-propagators-rxjava2 but it seems that there is no version that supports RxJava 3 yet (this could be the reason?)

ghost commented 3 years ago

/cc @sberyozkin

sberyozkin commented 3 years ago

Also CC @stuartwdouglas @mkouba

stuartwdouglas commented 3 years ago

RxJava3 not having context propagation support would be the cause of this. Why are you using RxJava3 and not Mutiny?

cc @cescoffier @FroMage

FroMage commented 3 years ago

We could add support for RxJava3, should we?

vvavepacket commented 3 years ago

@stuartwdouglas Our team skills is leaning towards ReactiveX so we figured out it makes sense to continue and build on that. I see that there was no support for RxJava3. Thanks for clearing it up.

geoand commented 3 years ago

We could add support for RxJava3, should we?

If we do this, then this would inevitably lead to supporting multiple RxJava versions and then Project Reactor. I'm -1 on spreading our efforts out like that.

cescoffier commented 3 years ago

I would rather not adding support for rxjava 3. It would provide a very different API and experience without any good integration with the rest of the Quarkus APIs. The integration can be achieved with the built-in converters of Mutiny (rxjava 3 converters were implemented last August).

geoand commented 1 month ago

Is this still an issue with the latest versions of Quarkus?

geoand commented 3 weeks ago

Closing for lack of feedback