Spring Boot: Integration test with HttpSecurity

Viewed 34

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?

0 Answers
Related