0

Integration Tests (production code works well) fail while requesting REST endpoints secured with @RolesAllowed. Following error is thrown:

[5/20/19 8:44:21:363 CEST] 00000109 com.ibm.ws.security.jaspi.JaspiServiceImpl                   I CWWKS1652A: Authentication failed with status AuthStatus.SEND_FAILUR for the web request 
/banking/users/bed6109f-ef8a-47ec-8fa4-e57c71415a10. The user defined Java Authentication SPI for Containers (JASPIC) service null has determined that the authentication data is not valid.

Project is based on OpenLiberty with JWT. The difference is in the UI part. My UI is based on Angular, so for authentication (JWT issuing) following REST Endpoint is used:

@RequestScoped
@Path("/tokens")
@PermitAll
public class AuthResource {
    @Inject
    private SecurityContext securityContext;
    @Inject
    private AuthService authService;

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getJwt() {
        if (securityContext.isCallerInRole("USER") || securityContext.isCallerInRole("ADMIN")) {
            String name = securityContext.getCallerPrincipal().getName();
            AuthPojo authPojo = authService.createJwt(name);

            return Response.ok(authPojo).build();
        }

        return Response.status(Response.Status.UNAUTHORIZED).build();
    }
}

So:

  1. UI (Angular) calls https://localhost:5051/tokens with Header "Authorization: Basic ENCODED_USERNAME_PASSWORD"
  2. Backend responds with newly generated JWT Token in body and Header "Set-Cookie: LtpaToken2=SOME_TOKEN; Path=/; HttpOnly"
  3. UI uses this token for all other requests against REST Endpoints annotated with "@RolesAllowed({"ADMIN", "USER" })"

Once again, in production code, all this schema works well, but Integration Tests fail.

Here is Integration Test code:

public class MyResourceIT {
    private static final String URL = "https://localhost:" +
        System.getProperty("liberty.test.ssl.port") + "/users/" + USER_ID1;

    private String authHeader;

    @Before
    public void setup() throws Exception {
        authHeader = "Bearer " + new JwtVerifier().createAdminJwt(USER_NAME1);
    }

    @Test
    public void getUserAndAccounts() {
        Response response = HttpClientHelper.processRequest(URL, "GET", null, authHeader);
        System.out.println("My URL: " + URL);
        System.out.println("My Header: " + authHeader);

        assertThat("HTTP GET failed", response.getStatus(), is(Response.Status.OK.getStatusCode()));
    }
}

Looks like the problem why 401 instead 200 is returned is LtpaToken2 Cookie which is not set in Test. Instead Header "Authorization: Bearer JWT_TOKEN" is used, but this doesn't work.

I Expect that Endpoint secured with "@RolesAllowed" should respond with 200 when header "Authorization: Bearer JWT_TOKEN" is provided. Are there some tricks that should be done with a cookie?

UPDATE 2019-05-23

This is the whole project. Example test is located here. The failing test is ignored

    @Test
    public void getUserAndAccounts_withJwt_authorized() throws IOException {
        Response response = HttpClientHelper.processRequest(URL, "GET", null, authHeader, null);

        assertThat(response.getStatus(), is(Response.Status.OK.getStatusCode()));
    }

JWT token is created within following class in the @Before annotated method:

    private String authHeader;
    @Before
    public void setup() throws Exception {
        authHeader = "Bearer " + new JwtVerifier().createAdminJwt(USER_NAME1);
    }

One thing to notice, that project is based on the following project.

Vytautas Arminas
  • 387
  • 5
  • 16
  • seems JWT validation is failing. Can you show me how you configure JWT validation in micro services? or any error message from micro service. – Chunlong May 20 '19 at 20:19
  • JWT generated in the test is valid, it is also validated after creation. I have updated the post. – Vytautas Arminas May 24 '19 at 11:46
  • can you show me how you configure your microservices to consume JWT? – Chunlong May 26 '19 at 13:46
  • JWT is created in the following class: https://github.com/varminas/money-transfer/blob/master/backendServices/src/main/java/lt/arminai/moneyTransfer/service/AuthServiceImpl.java – Vytautas Arminas May 26 '19 at 19:13

1 Answers1

0

Since the CWWKS1652A message was issued without a provider name, this indicates that appSecurity-3.0 is set and that at least a JSR-375 (a.k.a. Java EE Security API Specification) HttpAuthenticationMechanism is configured for the application, either via annotation or bean implementation. This causes an internal JASPIC provider to be created, therefore the null in the CWWKS1652A message, and this provider invokes the configured HttpAuthenticationMechanism that returns a AuthStatus.SEND_FAILURE status.

Please ensure that you intend to use an HttpAuthenticationMechanism and that valid authentication credentials are passed when challenged by this mechanism.

If it is determined that there is no HttpAuthenticationMechanism configured, then determine if there is an external JASPIC provider factory (AuthConfigFactory implementation) set via the authconfigprovider.factory property. In either case, it is the provider that responds with the AuthStatus.SEND_FAILURE seen in the message.