You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I am working on adding Quarkus runtime to https://start.microprofile.io/ project generator, MicroProfile Starter issue 195, Quarkus issue 1310. I seem to be having a weird issue with our JWT example that fails with Quarkus unless Java code is modified. I do realize Quarkus is neither MP22 nor MP30 TCK compliant at the time of writing. For the propose of the exercise, I work with MP22 as seen below.
I will show an example that works and then I break it by removing Quarkus specific hack.
<h1 class="container">Internal Server Error</h1>
<div class="exception-message">
<h2 class="container">java.lang.ClassCastException: org.glassfish.json.JsonStringImpl cannot be cast to java.base/java.lang.StringError id 91aa7964-4a51-4087-8070-11794337b74c-1</h2>
</div>
Logs:
2019-08-20 14:30:11,842 INFO [io.quarkus] (main) Quarkus 0.20.0 started in 0.784s. Listening on: http://[::]:8180
2019-08-20 14:30:11,865 INFO [io.quarkus] (main) Installed features: [cdi, resteasy, security, smallrye-jwt]
2019-08-20 14:30:20,699 ERROR [io.und.req.io] (executor-thread-1) Exception handling request 91aa7964-4a51-4087-8070-11794337b74c-1 to /data/protected: org.jboss.resteasy.spi.UnhandledException: java.lang.ClassCastException: org.glassfish.json.JsonStringImpl cannot be cast to java.base/java.lang.String
at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:106)
at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:372)
at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:209)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:496)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:252)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:153)
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:363)
at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:156)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:238)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:249)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:60)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:55)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:791)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at io.quarkus.elytron.security.runtime.SecurityContextPrincipalHandler.handleRequest(SecurityContextPrincipalHandler.java:24)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292)
at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$8$1$1.call(UndertowDeploymentRecorder.java:489)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:364)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1535)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1395)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
at java.base/java.lang.Thread.run(Thread.java:831)
at org.jboss.threads.JBossThread.run(JBossThread.java:479)
Caused by: java.lang.ClassCastException: org.glassfish.json.JsonStringImpl cannot be cast to java.base/java.lang.String
at com.example.demo.secure.ProtectedController.getJWTBasedValue(ProtectedController.java:26)
at com.example.demo.secure.ProtectedController_ClientProxy.getJWTBasedValue(ProtectedController_ClientProxy.zig:54)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:151)
at org.jboss.resteasy.core.MethodInjectorImpl.lambda$invoke$3(MethodInjectorImpl.java:122)
at java.base/java.util.concurrent.CompletableFuture.uniApplyNow(CompletableFuture.java:680)
at java.base/java.util.concurrent.CompletableFuture.uniApplyStage(CompletableFuture.java:658)
at java.base/java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:2094)
at java.base/java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:143)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:122)
at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:580)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:454)
at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:408)
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:363)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:410)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:379)
at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invoke$1(ResourceMethodInvoker.java:353)
at java.base/java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:1106)
at java.base/java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2235)
at java.base/java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:143)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:353)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:477)
... 44 more
It is noteworthy, that Thorntail's code works with TomEE and Payara Micro while it fails with Quarkus.
Ideas? Hints? Thoughts on the JWT example app?
The text was updated successfully, but these errors were encountered:
Hi @Karm I think I may know what is going on, or at least it rings a bell :-).
The code in the smallrye/smallrye-jwt does not wrap custom claims whose values are strings into JsonValue.String to meet the TCK requirements (at the moment only enforced at the Thorntail level), there is a faulty TCK test which expects a String, while Quarkus does, we discussed with @starksm64 and agreed it was better for Quarkus to stay the spec text compliant even though the TCK would not be happy (the test in question, org.eclipse.microprofile.jwt.tck.container.jaxrs.ClaimValueInjectionTest#verifyInjectedCustomString would have to be skipped).
So, if the example accesses a claim which is unknown per the MP JWT terminology, and expects a String, then there will be a class cast exception.
To be honest, I think this wrapping of Strings into JSON value is not really intuitive, but the spec wants it, and so Quarkus does it. But if Quarkus is the only implementation out there which actually does it then may be we can drop this code for now, or make this wrapping optional.
@Karm to be honest we can just drop the Quarkus code enforcing the wrapping of unknown claim Strings and worry about it if the TCK will ever try to force it, looks like no one is actually expecting JsonValue where a String is just a natural fit
Hello,
I am working on adding Quarkus runtime to https://start.microprofile.io/ project generator, MicroProfile Starter issue 195, Quarkus issue 1310. I seem to be having a weird issue with our JWT example that fails with Quarkus unless Java code is modified. I do realize Quarkus is neither MP22 nor MP30 TCK compliant at the time of writing. For the propose of the exercise, I work with MP22 as seen below.
I will show an example that works and then I break it by removing Quarkus specific hack.
Generate and build the starter example
Quarkus
curl -O -J 'https://starter.karms.biz/api/project?mpVersion=MP22&supportedServer=QUARKUS&selectedSpecs=JWT_AUTH'
unzip demo.zip -d q_jwt
cd q_jwt/demo/service-a
mvn clean compile quarkus:build && java -jar target/demo-runner.jar
cd q_jwt/demo/service-b
mvn clean compile quarkus:build && java -Dquarkus.http.port=8180 -jar target/demo-runner.jar
curl -i http://localhost:8080/data/secured/test
Claim value within JWT of 'custom-value' : Protected Resource; Custom value : "Jessie specific value"
That is the expected outcome ✔️. Service A acts as a client to Service B and the contents of the claim is "Jessie specific value".
Thorntail
rm -rf demo.zip
curl -O -J 'https://starter.karms.biz/api/project?mpVersion=MP22&supportedServer=THORNTAIL_V2&selectedSpecs=JWT_AUTH'
unzip demo.zip -d t_jwt
cd t_jwt/demo/service-a
mvn clean package && java -jar target/demo-thorntail.jar
cd t_jwt/demo/service-b
mvn clean package && java -jar target/demo-thorntail.jar -Dswarm.port.offset=100
curl -i http://localhost:8080/data/secured/test
Claim value within JWT of 'custom-value' : Protected Resource; Custom value : Jessie specific value
Both Thorntail and Quarkus work ✔️ . The problem is the Java code had to be adapted for Quarkus with a hack...
See the difference between classes that are supposed to be the same:
diff q_jwt/demo/service-b/src/main/java/com/example/demo/secure/ProtectedController.java t_jwt/demo/service-b/src/main/java/com/example/demo/secure/ProtectedController.java
Pertinent part:
Quarkus cannot cast
org.glassfish.json.JsonStringImpl
tojava.lang.String
, hence the(Object)
cast.Let's copy Thorntail code to Quarkus and run it again:
Quarkus fails ❌
mv q_jwt/demo/service-b/src/main/java/com/example/demo/secure/ProtectedController.java q_jwt/demo/service-b/src/main/java/com/example/demo/secure/ProtectedController.java.backup
cp t_jwt/demo/service-b/src/main/java/com/example/demo/secure/ProtectedController.java q_jwt/demo/service-b/src/main/java/com/example/demo/secure/ProtectedController.java
And we run Quarkus example again:
cd q_jwt/demo/service-a
mvn clean compile quarkus:build && java -jar target/demo-runner.jar
cd q_jwt/demo/service-b
mvn clean compile quarkus:build && java -Dquarkus.http.port=8180 -jar target/demo-runner.jar
curl -i http://localhost:8080/data/secured/test
Logs:
It is noteworthy, that Thorntail's code works with TomEE and Payara Micro while it fails with Quarkus.
Ideas? Hints? Thoughts on the JWT example app?
The text was updated successfully, but these errors were encountered: