Currently I have a security configuration using spring security with oauth2 resourceServer. Its all working fine with the JWT token this is my security filter chain looks like this:
httpSecurity.authorizeRequests()
.anyRequest().authenticated()
.and().cors()
.and().csrf()
.and().oauth2ResourceServer().jwt();
I need now to introduce this custom userDetailsService bean, in order to use preAuthorized annotation with custom roles and privileges:
@Bean
public UserDetailsService userDetailsService(IIUserService iiUserService) {
return new CustomUserDetailsService(new IIUserServiceFake());
}
public class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) {
//here I need to go to another micro-service to retrive the user roles/privileges and build a UserDetails Object
}
Lets say I have this endpoint:
@GetMapping("/custom")
@PreAuthorize( "hasRole('ROLE_ADMIN')")
public String getData(){
return "I was able to see this endpoint";
}
And my integration test looks like this:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
public class ControllerTest {
@LocalServerPort
private int serverPort;
@Autowired
private TestRestTemplate testRestTemplate;
@Test
public void entitlementTest() {
String uri = UriComponentsBuilder.fromHttpUrl("http://localhost").port(serverPort).path("/custom")
.build().toUriString();
ResponseEntity<String> forEntity = testRestTemplate.getForEntity(uri, String.class);
assertEquals(200, forEntity.getStatusCodeValue());
}
}
But now I want to be able to introduce roles/privileges with custom UserDetailsService Couple questions here: 1.- How do I mock the JWT resourceServer integration so that with the security enable during test the request looks authenticated. 2.- Using that UserDetailsService custom implementation how do I tell spring which field is the one to use because in my case i have a custom field comming from the token which is not call "username", lets say its called "custom_user_name".
Bassically I want to be able to test my controller that uses JWT token authentication with PreAuthorized annotation, using SpringBootTest
I already look this but still haven figure out a clean way to do this,
Again i dont want to change how the authentication is handle(JWT) but, have a custom way to determine if a user have the roles in my DB and being able to test that using integration test.
Thanks
I need now to introduce this custom userDetailsService bean, in order to use preAuthorized annotation with custom roles and privileges
What you need is reading the manual and a Converter<Jwt, AbstractAuthenticationToken>
bean (like JwtAuthenticationConverter
with proper configuration or an implementation of your own).
In your tests, if you use MockMvc
instead of TestRestTemplate
, then you can use SecurityMockMvcRequestPostProcessors.jwt()
to setup the security-context for you (without an authorization server to be up and running). You could also have a look at this lib I wrote, it provides with test annotations similar to @WithMockUser
, but for OAuth2. Sample integration test taken from there:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
class SampleApiIntegrationTest {
@Autowired
MockMvc api;
@Test
@WithAnonymousUser
void givenRequestIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception {
api.perform(get("/greet")).andExpect(status().isUnauthorized());
}
@Test
@WithJwt("ch4mp.json")
void givenUserIsCh4mp_whenGetGreet_thenOk() throws Exception {
api.perform(get("/greet")).andExpect(content().string("Hello ch4mp! You are granted with [USER_ROLES_EDITOR, ROLE_AUTHORIZED_PERSONNEL]."));
}
}
The @WithJwt
above uses the authentication converter (an implementation of Converter<Jwt, ? extends AbstractAuthenticationToken>
, JwtAuthenticationConverter
by default in Spring Boot) to build the Authentication
in stance and populate test security context, using a JSON payload in test classpath.