0

I have created REST resource with RestEasy reactive in Quarkus. It's expecting a JWT and is protected with this annotation in method:

@RolesAllowed({"read.access"}) 

I've defined JWKS URL in properties:

  mp:
    jwt:
      verify:
        publickey:
          location: http://my.server/jwks

The problem is that it is using Java HttpClient to refresh JWKS in a blocking manner which causes this when the reactive REST resource is called:

 io.vertx.core.VertxException: Thread blocked
        at java.base@11.0.2/java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.base@11.0.2/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399)
        at java.base@11.0.2/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242)
        at java.base@11.0.2/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224)
        at java.base@11.0.2/java.net.Socket.connect(Socket.java:591)
        at java.base@11.0.2/sun.net.NetworkClient.doConnect(NetworkClient.java:177)
        at java.base@11.0.2/sun.net.www.http.HttpClient.openServer(HttpClient.java:474)
        at java.base@11.0.2/sun.net.www.http.HttpClient.openServer(HttpClient.java:569)
        at java.base@11.0.2/sun.net.www.http.HttpClient.<init>(HttpClient.java:242)
        at java.base@11.0.2/sun.net.www.http.HttpClient.New(HttpClient.java:341)
        at java.base@11.0.2/sun.net.www.http.HttpClient.New(HttpClient.java:362)
        at java.base@11.0.2/sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1242)
        at java.base@11.0.2/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1181)
        at java.base@11.0.2/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1075)
        at java.base@11.0.2/sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:1009)
        at java.base@11.0.2/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1581)
        at java.base@11.0.2/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1509)
        at java.base@11.0.2/java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:527)
        at org.jose4j.http.Get.get(Get.java:80)
        at org.jose4j.jwk.HttpsJwks.refresh(HttpsJwks.java:204)
        at io.smallrye.jwt.auth.principal.AbstractKeyLocationResolver.isHttpsJwksInitialized(AbstractKeyLocationResolver.java:100)
        at io.smallrye.jwt.auth.principal.KeyLocationResolver.initializeKeyContent(KeyLocationResolver.java:88)
        at io.smallrye.jwt.auth.principal.KeyLocationResolver.<init>(KeyLocationResolver.java:44)
        at io.smallrye.jwt.auth.principal.DefaultJWTTokenParser.getVerificationKeyResolver(DefaultJWTTokenParser.java:226)
        at io.smallrye.jwt.auth.principal.DefaultJWTTokenParser.parseClaims(DefaultJWTTokenParser.java:95)
        at io.smallrye.jwt.auth.principal.DefaultJWTTokenParser.parse(DefaultJWTTokenParser.java:56)
        at io.smallrye.jwt.auth.principal.DefaultJWTCallerPrincipalFactory.parse(DefaultJWTCallerPrincipalFactory.java:31)
        at io.smallrye.jwt.auth.principal.DefaultJWTParser.parse(DefaultJWTParser.java:60)
        at io.smallrye.jwt.auth.principal.DefaultJWTParser_Subclass.parse$$superaccessor9(DefaultJWTParser_Subclass.zig:1575)
        at io.smallrye.jwt.auth.principal.DefaultJWTParser_Subclass$$function$$9.apply(DefaultJWTParser_Subclass$$function$$9.zig:33)
        at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54)
        at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.proceed(InvocationInterceptor.java:63)
        at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.monitor(InvocationInterceptor.java:51)
        at io.quarkus.arc.runtime.devconsole.InvocationInterceptor_Bean.intercept(InvocationInterceptor_Bean.zig:521)
        at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
        at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)
        at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)
        at io.smallrye.jwt.auth.principal.DefaultJWTParser_Subclass.parse(DefaultJWTParser_Subclass.zig:1523)
        at io.smallrye.jwt.auth.principal.DefaultJWTParser_ClientProxy.parse(DefaultJWTParser_ClientProxy.zig:368)
        at io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator$1.accept(MpJwtValidator.java:53)
        at io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator$1.accept(MpJwtValidator.java:49)
        at io.smallrye.context.impl.wrappers.SlowContextualConsumer.accept(SlowContextualConsumer.java:21)
        at io.smallrye.mutiny.operators.uni.builders.UniCreateWithEmitter.subscribe(UniCreateWithEmitter.java:22)
        at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
        at io.smallrye.mutiny.operators.uni.UniMemoizeOp.subscribe(UniMemoizeOp.java:76)
        at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
        at io.smallrye.mutiny.groups.UniSubscribe.withSubscriber(UniSubscribe.java:50)
        at io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder$2.handle(HttpSecurityRecorder.java:104)
        at io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder$2.handle(HttpSecurityRecorder.java:51)
        at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1038)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:137)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:132)
        at io.quarkus.micrometer.runtime.binder.vertx.VertxMeterFilter.handle(VertxMeterFilter.java:19)
        at io.quarkus.micrometer.runtime.binder.vertx.VertxMeterFilter.handle(VertxMeterFilter.java:14)
        at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1038)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:137)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:132)
        at io.quarkus.vertx.http.runtime.devmode.VertxHttpHotReplacementSetup$3.handle(VertxHttpHotReplacementSetup.java:88)
        at io.quarkus.vertx.http.runtime.devmode.VertxHttpHotReplacementSetup$3.handle(VertxHttpHotReplacementSetup.java:77)
        at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:327)
        at io.vertx.core.impl.ContextImpl$$Lambda$766/0x00000008005f8840.handle(Unknown Source)
        at io.vertx.core.impl.ContextImpl.executeTask(ContextImpl.java:366)
        at io.vertx.core.impl.EventLoopContext.lambda$executeAsync$0(EventLoopContext.java:38)
        at io.vertx.core.impl.EventLoopContext$$Lambda$713/0x0000000800588840.run(Unknown Source)
        at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base@11.0.2/java.lang.Thread.run(Thread.java:834)

Because of this I would like the JWKS refresh to happen as a separate scheduled process outside of the reactive request. I haven't found support for this in Quarkus.

Currently I'm planning to create a scheduled task to call the JWKS URL, extract the public key and save it as a file. Then I can point publickey location to that file.

Edit

Tried it but the public key file is cached by Quarkus so refreshing it does not help.

As of now the problem has disappeared and also at some point before the problem did not occur. It looks like it depends on luck if Quarkus decides to refresh the JWKS during a reactive REST resource request or not.

I'm expecting the problem to appear again but let's see.

Panu Haaramo
  • 2,932
  • 19
  • 41

0 Answers0