vertx-web icon indicating copy to clipboard operation
vertx-web copied to clipboard

ChainAuthHandler.any() doesn't work well with multiple JWTAuthHandlers

Open ayhanap opened this issue 11 months ago • 0 comments
trafficstars

Version

>=4.5.6

Context

This(https://github.com/vert-x3/vertx-web/pull/2582) pull request broke multiple JWTAuthHandlers hooked with a ChainAuthHandler.any() (Well actually it wasn't checking for scopes before)

So I am using vertx-web-openapi-router and it creates this similar double JWTAuthHandler inside a ChainAuthHandler when a route has security like this

      security:
        - oauth:
            - 'users:read'
        - oauth:
            - 'users:all'

With the change in referenced PR, ChainAuthHandler now calls postAuthentication for each JWTAuthHandler. But in postAuthentication JWTAuthHandler ends the context while checking for scopes at this line.. https://github.com/vert-x3/vertx-web/blob/a6d16eb0e7f885755527be51d976020a118ea933/vertx-web/src/main/java/io/vertx/ext/web/handler/impl/JWTAuthHandlerImpl.java#L154 Which causes ChainAuthHandler not to continue with the other handlers in the chain. This flow is not expected as its a any() handler and should continue and be successful if one of the handlers are successful.

Do you have a reproducer?

  @Test
  public void testWithMultipleJWTAuthHandlers() throws Exception {
    router.clear();

    JWTAuth authProvider = JWTAuth.create(vertx, new JWTAuthOptions()
        .setKeyStore(new KeyStoreOptions()
          .setType("jceks")
          .setPath("keystore.jceks")
          .setPassword("secret")));

    chain = ChainAuthHandler.any()
      .add(JWTAuthHandler.create(authProvider).withScope("users:read"))
      .add(JWTAuthHandler.create(authProvider).withScope("users:all"));
    router.route()
      .handler(chain)
      .handler(RoutingContext::end);

    final JsonObject payloadA = new JsonObject()
      .put("sub", "Paulo")
      .put("scope", String.join(" ", Arrays.asList("users:read")));

    testRequest(HttpMethod.GET, "/", req -> req.putHeader("Authorization", "Bearer " + authProvider.generateToken(payloadA)), 200, "OK", null);

    final JsonObject payloadB = new JsonObject()
      .put("sub", "Paulo")
      .put("scope", String.join(" ", Arrays.asList("users:read", "users:all")));

    testRequest(HttpMethod.GET, "/", req -> req.putHeader("Authorization", "Bearer " + authProvider.generateToken(payloadB)), 200, "OK", null);

    final JsonObject payloadC = new JsonObject()
      .put("sub", "Paulo")
      .put("scope",String.join(" ",Arrays.asList("users:all")));

    testRequest(HttpMethod.GET, "/", req -> req.putHeader("Authorization", "Bearer " + authProvider.generateToken(payloadC)), 200, "OK", null);
  }

Steps to reproduce

Add this test to ChainAuthHandlerTest class and run.

ayhanap avatar Dec 16 '24 20:12 ayhanap