I have a Quarkus project that expose some REST Endpoints. When working on dev mode or running from the local build docker container all work fine, those endpoints annotated with @RolesAllowed and @PermitAll work as supposed to be. But when I deploy to a AWS service with the following steps:
- Commit to Gitlab
- Run Gitlab CICD
- Send result with the config to an AWS S3 Bucket
- Trigger AWS codepipeline
- Deploy to Elastic Bean using docker image
After that the container is deployed all endpoints with @PermitAll work fine but those with @RolesAllowed responds with 401 Unauthorized, the token sent to those endpoints is valid, it is correctly formed and has not expired.
HTTP/1.1 401 Unauthorized Date: Mon, 25 Oct 2021 15:51:01 GMT Content-Length: 0 Connection: keep-alive Server: nginx/1.20.0 www-authenticate: Bearer <Response body is empty> Response code: 401 (Unauthorized); Time: 397ms; Content length: 0 bytes
The project is running on Quarkus Platform 2.2.3.Final on JDK 11 and I’m using the following extensions
Installed features: [agroal, cdi, config-yaml, hibernate-orm, hibernate-orm-panache, hibernate-validator, jaeger, jdbc-h2, jdbc-mysql, mailer, narayana-jta, qute, rest-client, rest-client-jackson, resteasy, resteasy-jackson, security, smallrye-context-propagation, smallrye-health, smallrye-jwt, smallrye-openapi, smallrye-opentracing, swagger-ui, vertx, vertx-web]
UPDATE:
I dive into the Quarkus documentation and added a few configurations and map all authorization exceptions and get the log and stacktrace, But I don’t know why is happening as I’m using the procedure that que guide says when create the public and private key. And also if I put all the base64 token in the jwt.io debugger and I paste the public key content it says that the signature is valid.
io.quarkus.security.AuthenticationFailedException at io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator$1.accept(MpJwtValidator.java:61) 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.operators.uni.UniOnItemTransformToUni.subscribe(UniOnItemTransformToUni.java:25) at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36) at io.smallrye.mutiny.operators.uni.UniOnTermination.subscribe(UniOnTermination.java:21) 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.operators.uni.UniBlockingAwait.await(UniBlockingAwait.java:54) at io.smallrye.mutiny.groups.UniAwait.atMost(UniAwait.java:61) at io.smallrye.mutiny.groups.UniAwait.indefinitely(UniAwait.java:42) at io.quarkus.security.runtime.SecurityIdentityAssociation.getIdentity(SecurityIdentityAssociation.java:66) at io.quarkus.security.runtime.SecurityIdentityAssociation_ClientProxy.getIdentity(SecurityIdentityAssociation_ClientProxy.zig:250) at io.quarkus.security.runtime.SecurityIdentityProxy.hasRole(SecurityIdentityProxy.java:38) at io.quarkus.security.runtime.SecurityIdentityProxy_ClientProxy.hasRole(SecurityIdentityProxy_ClientProxy.zig:401) at io.quarkus.security.runtime.interceptor.check.RolesAllowedCheck.apply(RolesAllowedCheck.java:55) at io.quarkus.security.runtime.interceptor.SecurityConstrainer.check(SecurityConstrainer.java:28) at io.quarkus.security.runtime.interceptor.SecurityHandler.handle(SecurityHandler.java:23) at io.quarkus.security.runtime.interceptor.RolesAllowedInterceptor.intercept(RolesAllowedInterceptor.java:29) at io.quarkus.security.runtime.interceptor.RolesAllowedInterceptor_Bean.intercept(RolesAllowedInterceptor_Bean.zig:386) 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 za.co.tenfour.controller.UserController_Subclass.findMyself(UserController_Subclass.zig:1031) at za.co.tenfour.controller.UserController_ClientProxy.findMyself(UserController_ClientProxy.zig:262) 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:566) at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170) at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130) at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:660) at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:524) at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:474) at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364) at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:476) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:434) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:408) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:69) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161) at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364) at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247) at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:138) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler$1.run(VertxRequestHandler.java:93) at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:543) at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449) at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478) at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29) at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base/java.lang.Thread.run(Thread.java:829)nCaused by: io.smallrye.jwt.auth.principal.ParseException: SRJWT07000: Failed to verify a token at io.smallrye.jwt.auth.principal.DefaultJWTTokenParser.parseClaims(DefaultJWTTokenParser.java:166) 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_ClientProxy.parse(DefaultJWTParser_ClientProxy.zig:298) at io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator$1.accept(MpJwtValidator.java:53) ... 59 morenCaused by: org.jose4j.jwt.consumer.InvalidJwtSignatureException: JWT rejected due to invalid signature. Additional details: [[9] Invalid JWS Signature: JsonWebSignature{"typ":"JWT","alg":"RS256"}->eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovLzEwZm91ci5jby56YS9pc3N1ZXIiLCJncm91cHMiOlsiQWRtaW5pc3RyYXRvciJdLCJpYXQiOjE2MzUxOTcyMjUsImV4cCI6MTY2Njc1NDgyNSwidXBuIjoic3VwcG9ydEAxMGZvdXIuY28uemEiLCJ1aWQiOjEsImZ1bGxfbmFtZSI6IjEwRm91ciBBZG1pbmlzdHJhdG9yIiwianRpIjoiMWZmNDA4MjYtNmNhNy00NzQxLTk0Y2QtOTlhY2Q0ZGY4M2IyIn0.i8skIOrh6Et84uuASjwhQQMnIjRnfiP4zjPQAB7XsyVwSEuZEc31m9reXTW1uWjzvoZTbllYZ79Aiu4Vq7MqMPJKvXIqXhmTWbX-R9JnQoI0M_Sb1c6DAXDD_biZGYUM48-FO3lRG9XCu_qr06uT4sOb1DLwh6pjdehTwnkbMX_B1Jckn-7hStCcV04XwXOOZkZWnP6_uFltsDLIQd7PsYbnRzgO19xhaAb6sfuUeKwhTs2WJL7msj0FhH_HbeEFel5OnH_NLfPhEvzByS5VRdN9j3LRNZ5z0OOm3rK_W9A6r34VRaUvddJ2_wXiyv3hvtMKLoN8wJUJuhhjqQKtTQ] at org.jose4j.jwt.consumer.JwtConsumer.processContext(JwtConsumer.java:224) at org.jose4j.jwt.consumer.JwtConsumer.process(JwtConsumer.java:433) at io.smallrye.jwt.auth.principal.DefaultJWTTokenParser.parseClaims(DefaultJWTTokenParser.java:145) ... 64 moren
Advertisement
Answer
The problem was the AWS time zone configuration, for some strange reason it interfered with how Quarkus validates the IAT and EXP claims of the token. I removed the AWS time zone settings and set the zone using a system property at the JVM level and the problem was completely fixed.