Repository: quarkusio/quarkus
Issue: MicroProfile JWT application works with Payara Micro, Thorntail, TomEE and fails with Quarkus

Hello,

I am working on adding Quarkus runtime to https://start.microprofile.io/ project generator, [MicroProfile Starter issue 195](https://github.com/eclipse/microprofile-starter/issues/195), [Quarkus issue 1310](https://github.com/quarkusio/quarkus/issues/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```
* Split into two terminals, one for service-a and the other for service-b
* ```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 :heavy_check_mark:. 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 :heavy_check_mark: . **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:**

```
<         return "Protected Resource; Custom value : " + (Object) custom.getValue();
---
>         return "Protected Resource; Custom value : " + custom.getValue();
```

Quarkus cannot cast ```org.glassfish.json.JsonStringImpl``` to ```java.lang.String```, hence the ```(Object)``` cast.


Let's copy Thorntail code to Quarkus and run it again:

### Quarkus fails :x: 

* ```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```
```
    <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?

Changed files:
extensions/smallrye-jwt/deployment/src/test/java/io/quarkus/jwt/test/JwtCallerPrincipalUnitTest.java
extensions/smallrye-jwt/runtime/src/main/java/io/quarkus/smallrye/jwt/runtime/auth/ElytronJwtCallerPrincipal.java

diff --git a/extensions/smallrye-jwt/deployment/src/test/java/io/quarkus/jwt/test/JwtCallerPrincipalUnitTest.java b/extensions/smallrye-jwt/deployment/src/test/java/io/quarkus/jwt/test/JwtCallerPrincipalUnitTest.java
index 4ebdad105f5..9ee3c7c28bf 100644
--- a/extensions/smallrye-jwt/deployment/src/test/java/io/quarkus/jwt/test/JwtCallerPrincipalUnitTest.java
+++ b/extensions/smallrye-jwt/deployment/src/test/java/io/quarkus/jwt/test/JwtCallerPrincipalUnitTest.java
@@ -9,7 +9,6 @@
 import javax.json.JsonArray;
 import javax.json.JsonNumber;
 import javax.json.JsonObject;
-import javax.json.JsonString;
 
 import org.eclipse.microprofile.jwt.Claims;
 import org.jose4j.jwt.JwtClaims;
@@ -62,8 +61,7 @@ public void testAllClaims() throws InvalidJwtException {
         Assertions.assertEquals(Json.createValue(4.4), customDoubleArray.getJsonNumber(4));
 
         // "customString": "customStringValue",
-        JsonString customString = principal.getClaim("customString");
-        Assertions.assertEquals(Json.createValue("customStringValue"), customString);
+        Assertions.assertEquals("customStringValue", principal.getClaim("customString"));
         // "customInteger": 123456789,
         JsonNumber customInteger = principal.getClaim("customInteger");
         Assertions.assertEquals(Json.createValue(123456789), customInteger);
diff --git a/extensions/smallrye-jwt/runtime/src/main/java/io/quarkus/smallrye/jwt/runtime/auth/ElytronJwtCallerPrincipal.java b/extensions/smallrye-jwt/runtime/src/main/java/io/quarkus/smallrye/jwt/runtime/auth/ElytronJwtCallerPrincipal.java
index 5116636f334..f16ab8153b0 100644
--- a/extensions/smallrye-jwt/runtime/src/main/java/io/quarkus/smallrye/jwt/runtime/auth/ElytronJwtCallerPrincipal.java
+++ b/extensions/smallrye-jwt/runtime/src/main/java/io/quarkus/smallrye/jwt/runtime/auth/ElytronJwtCallerPrincipal.java
@@ -1,8 +1,5 @@
 package io.quarkus.smallrye.jwt.runtime.auth;
 
-import javax.json.JsonStructure;
-
-import org.eclipse.microprofile.jwt.Claims;
 import org.jose4j.jwt.JwtClaims;
 import org.wildfly.security.authz.Attributes;
 
@@ -46,15 +43,4 @@ public String getName() {
         return customPrincipalName != null ? customPrincipalName : super.getName();
     }
 
-    @Override
-    protected Object getClaimValue(String claimName) {
-        Object value = super.getClaimValue(claimName);
-
-        Claims claimType = getClaimType(claimName);
-        if (claimType == Claims.UNKNOWN && !(value instanceof JsonStructure)) {
-            value = wrapClaimValue(value);
-        }
-
-        return value;
-    }
 }