Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client call fails with MP JWT #5537

Closed
danielkec opened this issue Nov 25, 2022 · 2 comments · Fixed by #6806
Closed

Client call fails with MP JWT #5537

danielkec opened this issue Nov 25, 2022 · 2 comments · Fixed by #6806
Assignees
Labels
3.x Issues for 3.x version branch bug Something isn't working P2 security

Comments

@danielkec
Copy link
Contributor

danielkec commented Nov 25, 2022

Environment Details

  • Helidon Version: 3.0.2
  • Helidon MP
  • JDK version: OpenJDK Runtime Environment (build 17.0.2+8-86)
  • OS: Ubuntu 22.04.1 LTS 5.15.0-53-generic

Problem Description

When using only MP JWT for securing Helidon MP service with following config:

mp.jwt.verify:
  issuer: "http://${keycloak.host}:${keycloak.port}/realms/helidon-in-action"
  publickey:
    location: ${mp.jwt.verify.issuer}/protocol/openid-connect/certs

It's not possible to use Jersey client.

@Path("/watchtower")
@RequestScoped
@Authenticated
public class WatchtowerResource {
    @POST
    @RolesAllowed({"warden"})
    @Path("/signal")
    public void signal(@Context SecurityContext securityContext, String url) {
        ClientBuilder.newBuilder()
                .build()
                .target(url)
                .path("/comm/ack")
                .request()
                .get();
    }
}
2022.11.25 15:40:28 SEVERE AUDIT Thread[helidon-security-thread-pool-3,5,security-thread-pool]: ERROR outbound.outbound d7a9625e-87f2-4519-a8c3-855917a2c8be:1  io.helidon.common.context.Contexts runInContext Contexts.java 117 :: "Provider io.helidon.microprofile.jwt.auth.JwtAuthProvider, Description io.helidon.security.OutboundSecurityClientImpl@5181afc0, Request java.lang.NullPointerException: Cannot invoke "io.helidon.security.providers.common.OutboundConfig.findTarget(io.helidon.security.SecurityEnvironment)" because "this.outboundConfig" is null. Subject java.util.concurrent.CompletionException: java.lang.NullPointerException: Cannot invoke "io.helidon.security.providers.common.OutboundConfig.findTarget(io.helidon.security.SecurityEnvironment)" because "this.outboundConfig" is null"
2022.11.25 15:40:28 WARNING io.helidon.security.integration.jersey.client.ClientSecurityFilter Thread[helidon-server-1,5,server]: Failed to process client filter.
io.helidon.security.SecurityException: Failure while executing asynchronous security
	at io.helidon.security.SecurityResponse.get(SecurityResponse.java:66)
	at io.helidon.security.SecurityClient.get(SecurityClient.java:46)
	at io.helidon.security.OutboundSecurityClientBuilder.buildAndGet(OutboundSecurityClientBuilder.java:106)
	at io.helidon.security.integration.jersey.client.ClientSecurityFilter.outboundSecurity(ClientSecurityFilter.java:141)
	at io.helidon.security.integration.jersey.client.ClientSecurityFilter.doFilter(ClientSecurityFilter.java:81)
	at io.helidon.security.integration.jersey.client.ClientSecurityFilter.filter(ClientSecurityFilter.java:68)
	at org.glassfish.jersey.client.ClientFilteringStages$RequestFilteringStage.apply(ClientFilteringStages.java:144)
	at org.glassfish.jersey.client.ClientFilteringStages$RequestFilteringStage.apply(ClientFilteringStages.java:132)
	at org.glassfish.jersey.process.internal.Stages.process(Stages.java:147)
	at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:297)
	at org.glassfish.jersey.client.JerseyInvocation.lambda$invoke$0(JerseyInvocation.java:662)
	at org.glassfish.jersey.client.JerseyInvocation.call(JerseyInvocation.java:697)
	at org.glassfish.jersey.client.JerseyInvocation.lambda$runInScope$3(JerseyInvocation.java:691)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:292)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:274)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:205)
	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:390)
	at org.glassfish.jersey.client.JerseyInvocation.runInScope(JerseyInvocation.java:691)
	at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:661)
	at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:413)
	at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:313)
	at io.course.jwt.sec.WatchtowerResource.signal(WatchtowerResource.java:32)
	at io.course.jwt.sec.WatchtowerResource$Proxy$_$$_WeldClientProxy.signal(Unknown Source)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.lambda$static$0(ResourceMethodInvocationHandlerFactory.java:52)
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:134)
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:177)
	at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$VoidOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:159)
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:81)
	at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:478)
	at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:400)
	at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:81)
	at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:255)
	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:248)
	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:244)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:292)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:274)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:244)
	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:265)
	at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:234)
	at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:684)
	at io.helidon.webserver.jersey.JerseySupport$JerseyHandler.lambda$doAccept$4(JerseySupport.java:334)
	at io.helidon.common.context.Contexts.runInContext(Contexts.java:117)
	at io.helidon.common.context.ContextAwareExecutorImpl.lambda$wrap$7(ContextAwareExecutorImpl.java:154)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.util.concurrent.ExecutionException: io.helidon.security.SecurityException: Failed to process security
	at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:396)
	at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2096)
	at io.helidon.security.SecurityResponse.get(SecurityResponse.java:62)
	... 49 more
Caused by: io.helidon.security.SecurityException: Failed to process security
	at io.helidon.security.OutboundSecurityClientImpl.lambda$submit$1(OutboundSecurityClientImpl.java:96)
	at java.base/java.util.concurrent.CompletableFuture.uniExceptionally(CompletableFuture.java:990)
	at java.base/java.util.concurrent.CompletableFuture$UniExceptionally.tryFire(CompletableFuture.java:974)
	at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1773)
	... 5 more
Caused by: java.util.concurrent.CompletionException: java.lang.NullPointerException: Cannot invoke "io.helidon.security.providers.common.OutboundConfig.findTarget(io.helidon.security.SecurityEnvironment)" because "this.outboundConfig" is null
	at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:315)
	at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:320)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1770)
	... 5 more
Caused by: java.lang.NullPointerException: Cannot invoke "io.helidon.security.providers.common.OutboundConfig.findTarget(io.helidon.security.SecurityEnvironment)" because "this.outboundConfig" is null
	at io.helidon.microprofile.jwt.auth.JwtAuthProvider.lambda$syncOutbound$10(JwtAuthProvider.java:399)
	at java.base/java.util.Optional.flatMap(Optional.java:289)
	at io.helidon.microprofile.jwt.auth.JwtAuthProvider.lambda$syncOutbound$11(JwtAuthProvider.java:398)
	at java.base/java.util.Optional.orElseGet(Optional.java:364)
	at io.helidon.microprofile.jwt.auth.JwtAuthProvider.syncOutbound(JwtAuthProvider.java:390)
	at io.helidon.security.spi.SynchronousProvider.lambda$outboundSecurity$2(SynchronousProvider.java:85)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1768)
	... 5 more
2022.11.25 15:40:28 WARNING io.helidon.microprofile.server.JaxRsCdiExtension Thread[helidon-server-1,5,server]: Internal server error
jakarta.ws.rs.ProcessingException: Failure while executing asynchronous security
	at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:309)
	at org.glassfish.jersey.client.JerseyInvocation.lambda$invoke$0(JerseyInvocation.java:662)
	at org.glassfish.jersey.client.JerseyInvocation.call(JerseyInvocation.java:697)
	at org.glassfish.jersey.client.JerseyInvocation.lambda$runInScope$3(JerseyInvocation.java:691)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:292)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:274)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:205)
	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:390)
	at org.glassfish.jersey.client.JerseyInvocation.runInScope(JerseyInvocation.java:691)
	at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:661)
	at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:413)
	at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:313)
	at io.course.jwt.sec.WatchtowerResource.signal(WatchtowerResource.java:32)
	at io.course.jwt.sec.WatchtowerResource$Proxy$_$$_WeldClientProxy.signal(Unknown Source)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.lambda$static$0(ResourceMethodInvocationHandlerFactory.java:52)
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:134)
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:177)
	at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$VoidOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:159)
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:81)
	at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:478)
	at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:400)
	at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:81)
	at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:255)
	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:248)
	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:244)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:292)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:274)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:244)
	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:265)
	at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:234)
	at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:684)
	at io.helidon.webserver.jersey.JerseySupport$JerseyHandler.lambda$doAccept$4(JerseySupport.java:334)
	at io.helidon.common.context.Contexts.runInContext(Contexts.java:117)
	at io.helidon.common.context.ContextAwareExecutorImpl.lambda$wrap$7(ContextAwareExecutorImpl.java:154)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: io.helidon.security.SecurityException: Failure while executing asynchronous security
	at io.helidon.security.SecurityResponse.get(SecurityResponse.java:66)
	at io.helidon.security.SecurityClient.get(SecurityClient.java:46)
	at io.helidon.security.OutboundSecurityClientBuilder.buildAndGet(OutboundSecurityClientBuilder.java:106)
	at io.helidon.security.integration.jersey.client.ClientSecurityFilter.outboundSecurity(ClientSecurityFilter.java:141)
	at io.helidon.security.integration.jersey.client.ClientSecurityFilter.doFilter(ClientSecurityFilter.java:81)
	at io.helidon.security.integration.jersey.client.ClientSecurityFilter.filter(ClientSecurityFilter.java:68)
	at org.glassfish.jersey.client.ClientFilteringStages$RequestFilteringStage.apply(ClientFilteringStages.java:144)
	at org.glassfish.jersey.client.ClientFilteringStages$RequestFilteringStage.apply(ClientFilteringStages.java:132)
	at org.glassfish.jersey.process.internal.Stages.process(Stages.java:147)
	at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:297)
	... 40 more
Caused by: java.util.concurrent.ExecutionException: io.helidon.security.SecurityException: Failed to process security
	at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:396)
	at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2096)
	at io.helidon.security.SecurityResponse.get(SecurityResponse.java:62)
	... 49 more
Caused by: io.helidon.security.SecurityException: Failed to process security
	at io.helidon.security.OutboundSecurityClientImpl.lambda$submit$1(OutboundSecurityClientImpl.java:96)
	at java.base/java.util.concurrent.CompletableFuture.uniExceptionally(CompletableFuture.java:990)
	at java.base/java.util.concurrent.CompletableFuture$UniExceptionally.tryFire(CompletableFuture.java:974)
	at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1773)
	... 5 more
Caused by: java.util.concurrent.CompletionException: java.lang.NullPointerException: Cannot invoke "io.helidon.security.providers.common.OutboundConfig.findTarget(io.helidon.security.SecurityEnvironment)" because "this.outboundConfig" is null
	at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:315)
	at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:320)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1770)
	... 5 more
Caused by: java.lang.NullPointerException: Cannot invoke "io.helidon.security.providers.common.OutboundConfig.findTarget(io.helidon.security.SecurityEnvironment)" because "this.outboundConfig" is null
	at io.helidon.microprofile.jwt.auth.JwtAuthProvider.lambda$syncOutbound$10(JwtAuthProvider.java:399)
	at java.base/java.util.Optional.flatMap(Optional.java:289)
	at io.helidon.microprofile.jwt.auth.JwtAuthProvider.lambda$syncOutbound$11(JwtAuthProvider.java:398)
	at java.base/java.util.Optional.orElseGet(Optional.java:364)
	at io.helidon.microprofile.jwt.auth.JwtAuthProvider.syncOutbound(JwtAuthProvider.java:390)
	at io.helidon.security.spi.SynchronousProvider.lambda$outboundSecurity$2(SynchronousProvider.java:85)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1768)
	... 5 more

@danielkec
Copy link
Contributor Author

Workaround

#TODO: Remove when https://github.com/helidon-io/helidon/issues/5537 is fixed
security:
  providers:
      - jwt:
          atn-token:
            verify-signature: false
          sign-token:
            outbound:
              - name: "propagate-token"

@m0mus m0mus added bug Something isn't working 3.x Issues for 3.x version branch security P2 labels Dec 1, 2022
@edthorne
Copy link

I ran into this today when migrating some services to Helidon from another MicroProfile implementation. My workaround was to simply add propagate: false to the application.yaml after reviewing the source to JwtAuthProvider.

After looking at the documentation and the MicroProfile JWT Auth Spec, I'm left with a few questions/observations:

  1. The MP JWT and REST Client specifications do not address JWT propagation. The default behavior of the provider is to enable it without the necessary configuration. This seems counterproductive and leads to the issue. I believe the propagate value should default to false absent the necessary configuration.
  2. The configuration value to disable propagation, and any configuration key not explicitly identified in the MP JWT specification, lacks context. Consider that all the specification config properties begin mp.jwt.*. This security provider is NOT configured under security.providers. Is the placement of these configuration values correct at the root?
  3. Formatting issues aside, the Configuration documentation for outbound security is not easy to understand and no examples are provided. How does the outbound security system work? Is it generating it's own token or working with an external token provider?

I'm working on getting the OCA signed so I can help address these and future issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.x Issues for 3.x version branch bug Something isn't working P2 security
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

4 participants