1

I cannot set authentication for my integration test of rest controller. Controller's method looks like this:

@RestController
@RequestMapping(BASE_URL)
@RequiredArgsConstructor
public class EventController {

    public static final String BASE_URL = "/api/event";

    @PostMapping
    @PreAuthorize("hasRole('USER')")
    public void createEvent() {
        System.out.println("I am in controller");
    }
}

and here is my test:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class EventControllerTest {

    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext context;

    @BeforeEach
    public void setup() {
        mockMvc = MockMvcBuilders
            .webAppContextSetup(context)
            .apply(springSecurity())
            .build();
    }

    @Test
    void create() throws Exception {
        this.mockMvc.perform(post(EventController.BASE_URL)
            .with(authentication(new UsernamePasswordAuthenticationToken(
                new MyPrincipal(100, "denis"),
                null,
                Collections.singletonList(new SimpleGrantedAuthority("USER"))
            )))
            .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(content().contentType("application/json"));
    }

My test always failed due to status 401 so my mocked authentication doesn't work. Can you tell me how to fix it? Thank you in advice.

Denis Stephanov
  • 4,563
  • 24
  • 78
  • 174

1 Answers1

0

The easiest way to test secured requests is to use @WithMockUser(A_ROLE)

so your test could look like

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@SpringBootTest
@AutoConfigureMockMvc
class EventControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    @WithMockUser("USER")
    void create() throws Exception {
        this.mockMvc.perform(post(EventController.BASE_URL)
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().contentType("application/json"));
    }
}

Some remarks:

  • your test expects a result, so adopt your controller or test
    @PostMapping
    @PreAuthorize("hasRole('ROLE_USER')")
    public ResponseEntity<String> createEvent() {
        String result = "I am in controller";
        System.out.println(result);
        return ResponseEntity.ok().body(result);
    }

you are doing/testing a POST so make sure that in your security configuration you do http.csrf().disable()....

or provide a csrf-token in your test

 this.mockMvc.perform(post(EventController.BASE_URL)
         .with(SecurityMockMvcRequestPostProcessors.csrf()) // provide a csrf-token
         ....

'

Dirk Deyne
  • 6,048
  • 1
  • 15
  • 32