I have the following controller:
@CrossOrigin
@RestController
@RequestMapping("api")
public class MyController {
@GetMapping("/principal")
public void principalEndpoint(Principal user) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
System.out.println(user);
System.out.println(authentication);
}
}
and the corresponding integration test whcich uses @WithMockUser as described in the docs:
/**
* implementation according to https://docs.spring.io/spring-security/reference/servlet/test/index.html
*/
@ExtendWith(SpringExtension.class)
@SpringBootTest
@WebAppConfiguration
@ContextConfiguration
public class MyControllerIT {
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@BeforeEach
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
@Test
@WithMockUser(value = "Dani", username = "TAATIDA3")
public void testWithPrincipal() throws Exception {
mvc.perform(get("/api/principal").principal(new PrincipalImpl()))
.andExpect(status().isOk());
}
}
PrincipalImpl is a simple implementation of Principal:
public class PrincipalImpl implements Principal {
@Override
public String getName() {
return "MOCKUSER";
}
}
I also have the following SpringBoot configuration to authorize requests under the /api path:
@Configuration
@EnableResourceServer
@EnableCaching
@EnableScheduling
@EnableMongoAuditing
public class MyApiConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/api/**").authorizeRequests()
.antMatchers("/api/**").not().anonymous();
}
}
My problem is that the request dispatched by mockMvc in MyControllerIT fails because a HTTP Status 401 is returned (not authorized). It would work if I change the HttpSecurity configuration to this
http.antMatcher("/api/**").authorizeRequests()
.antMatchers("/api/**").permitAll();
then the request succeeds (HTTP status 200), but no Principal is injected and the Authentication object from SecurityContextHolder.getContext().getAuthentication() is from an anonymous user:
null
AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]]
If I change the paths in MyApiConfig e.g. to this:
http.antMatcher("/someOtherApi/**").authorizeRequests()
.antMatchers("/someOtherApi/**").permitAll();
then the call from MyControllerIT succeeds and also a Principal is injected, which is what I want. However, in this case the actual api under /api/** is not secured anymore...
I'm quite new to the concepts of Spring Boot Security. Somehow I would have to override the MyApiConfig to configure HttpSecurity differently for tests (or use a separate configuration for test while at the same time excluding MyApiConfig). How do I do that, or what's the best way to make the HttpSecurity setup not interfere with MockMvc setup?