Environment: I have a spring boot based microservice architecture application consisting of multiple infrastructural services and resource services (containing the business logic). Authorization and authentication is handled by an oAuth2-Service managing the user entities and creating JWT tokens for the clients.
To test a single microservice application in its entirety i tried to build tests with testNG, spring.boot.test, org.springframework.security.test ...
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, properties = {"spring.cloud.discovery.enabled=false", "spring.cloud.config.enabled=false", "spring.profiles.active=test"})
@AutoConfigureMockMvc
@Test
public class ArtistControllerTest extends AbstractTestNGSpringContextTests {
@Autowired
private MockMvc mvc;
@BeforeClass
@Transactional
public void setUp() {
// nothing to do
}
@AfterClass
@Transactional
public void tearDown() {
// nothing to do here
}
@Test
@WithMockUser(authorities = {"READ", "WRITE"})
public void getAllTest() throws Exception {
// EXPECT HTTP STATUS 200
// BUT GET 401
this.mvc.perform(get("/")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
}
}
where the security (resource server) config is the following
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
// get the configured token store
@Autowired
TokenStore tokenStore;
// get the configured token converter
@Autowired
JwtAccessTokenConverter tokenConverter;
/**
* !!! configuration of springs http security !!!
*/
@Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/**").authenticated();
}
/**
* configuration of springs resource server security
*/
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
// set the configured tokenStore to this resourceServer
resources.resourceId("artist").tokenStore(tokenStore);
}
}
and the following method based security check annotated inside the controller class
@PreAuthorize("hasAuthority('READ')")
@RequestMapping(value = "/", method = RequestMethod.GET)
public List<Foo> getAll(Principal user) {
List<Foo> foos = fooRepository.findAll();
return foos;
}
I thought that would work but when running the test i only get an assertion error
java.lang.AssertionError: Status
Expected :200
Actual :401
Question:
Is there something totally obvious that i am doing wrong? Or is @WithMockUser not going to work with @SpringBootTest and @AutoConfigureMockMvc in an oAuth2 environment? If this is the case... what would be the best approach for testing route and method based security configurations as part of such an (integration) test like this one?
Appendix:
I also tried different approaches like something like the following... but it led to the same result :(
this.mvc.perform(get("/")
.with(user("admin").roles("READ","WRITE").authorities(() -> "READ", () -> "WRITE"))
.accept(MediaType.APPLICATION_JSON))