October 26, 2024
Chicago 12, Melborne City, USA
java

Java Spring Integration Test: Mock BearerTokenAuthentication with Oauth2


Im facing an issue when running integration tests on my web layer.

I wanna mock this endpoint:

public ResponseEntity<List<Book>> getBooks(BearerTokenAuthentication auth,  @AuthenticationPrincipal OidcUser principal) {...}

So essentially it takes in a bearer token and optionally a principal, looks for the books and returns them.

I also have the following configuration for the security filter chain:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.csrf(CsrfConfigurer::disable)
            .authorizeHttpRequests((authz) ->
                    authz.anyRequest().authenticated()
            ).oauth2ResourceServer(oauth2 -> oauth2.jwt().decoder(jwtDecoder()).jwtAuthenticationConverter(new JwtBearerTokenAuthenticationConverter()));
    return http.build();
}


public JwtDecoder jwtDecoder() {
        return (token) -> {
        JWT jwt = null;
        try {
            jwt = JWTParser.parse(token);
            Map<String, Object> headers = new LinkedHashMap<>(jwt.getHeader().toJSONObject());
            Map<String, Object> claims = jwt.getJWTClaimsSet().getClaims();
            return new Jwt(token, null, null, headers, claims);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    };
}

So essentially Im receiving a jwt and I’m converting it into an authentication object to put it in springs security context.

Now what Im kinda having trouble with is testing it.
Im mocking the jwt using c4_soft.springaddons @WithJwt() where I pass some standard jwt with mock values.
This is what my test currently looks like:

@SpringBootTest
@AutoConfigureMockMvc
public class BookApiTest {
    private final MockMvc mockMvc;

    @MockBean
    FeignClient feignClient;

    @MockBean
    JwtDecoder jwtDecoder;

   
    @Autowired
    BookApiTest(MockMvc mockMvc) {
        this.mockMvc = mockMvc;
    }


    @Test
    @WithJwt("jwt.json")
    public void testGetBooks() throws Exception {



        ResponseEntity<List<Book>> responseEntity = ResponseEntity.ok(List.of(sampleBooks));
        when(feignClient.getBooks()).thenReturn(responseEntity);

        this.mockMvc.perform(MockMvcRequestBuilders.get("/books")
                        .with(SecurityMockMvcRequestPostProcessors.csrf()))

                .andExpect(status().isOk());
    }
}

Now my problem is that whenever. I run my test in this setup, Im getting:
jakarta.servlet.ServletException: Request processing failed: java.lang.IllegalStateException: Current user principal is not of type [org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication]: JwtAuthenticationToken [Principal=org.springframework.security.oauth2.jwt.Jwt@a795d843, Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[]]

And that’s whats irritating for me.
Provided I have a valid jwt and I’m using the configuration above using @autoconfiguremvc, I expect the jwt to be automatically converted into an Authentication object and provided to the security context.
Why it fails during the test, I don’t get it.

The spring documentation, articles on SO or other sites could not help me so far.

Maybe someone notices a crucial error or something that Im missing.
Id be gratefull.



You need to sign in to view this answers

Leave feedback about this

  • Quality
  • Price
  • Service

PROS

+
Add Field

CONS

+
Add Field
Choose Image
Choose Video