1

I have a simple controller that should only be accessible in a secured context. In my application, I only whitelist other URLs, not /user.

In the unit test for the single @GetResponse I get an Http Status of 401 instead of a 200. I expect this, as it is secured.

When I actually run the application with a logged in user, I get a 200, and a valid result.

How can I Unit Test the behaviour of the request and any other secured controller paths?

Unit test:

@SpringBootTest
@AutoConfigureMockMvc
class UserControllerTest {

  @InjectMocks
  UserController userController;
  @Autowired
  private MockMvc mockMvc;
  @Autowired
  private ApplicationContext applicationContext;

  @Test
  void getUserNone() throws Exception {

    mockMvc
        .perform(MockMvcRequestBuilders.get("/user"))
        .andExpect(status().isOk());
  }
}

App:

@SpringBootApplication
public class WebApp extends WebSecurityConfigurerAdapter {

  public static void main(final String... args) {
    SpringApplication.run(WebApp.class, args);
  }

  @Override
  protected void configure(final HttpSecurity http) throws Exception {
    http
        .authorizeRequests(a -> a
            .antMatchers("/error", "/css/**", "/webjars/**").permitAll()
            .anyRequest().authenticated()
        )
        .exceptionHandling(e -> e
            .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
        )
        .oauth2Login();
  }   
}

Controller:

@Controller
public class UserController {

  @GetMapping("/user")
  public @ResponseBody
  Map<String, Object> getUser(@AuthenticationPrincipal final OAuth2User principal) {
    if (principal == null) {
      return Collections.EMPTY_MAP;
    } else {
      return Collections.singletonMap("name", principal.getName());
    }   
  }
}

Obviously, I could add /user to the whitelisted paths, but that would be incorrect for any secured parts of the application.

Dragonthoughts
  • 2,180
  • 8
  • 25
  • 28

1 Answers1

3

You can use the annotation @WithMockUser and @WithAnonymousUser which creates a fake Authentication that is populated in SecurityContext. Documentation can be found here .

Example code:

@Test
@WithMockUser("john")   
void testAuthorize() throws Exception {
        mockMvc
           .perform(MockMvcRequestBuilders.get("/user"))
           .andExpect(status().isOk());
}
@Test
@WithAnonymousUser
void testUnauthorized() throws Exception {
        mockMvc
           .perform(MockMvcRequestBuilders.get("/user"))
           .andExpect(status().isUnauthorized());
}
  • 1
    Thanks, I had to add `testImplementation('org.springframework.security:spring-security-test:5.3.2.RELEASE')` to my gradle.build and `import org.springframework.security.test.context.support.WithMockUser;` and it worked like a dream. – Dragonthoughts May 24 '20 at 18:24