Spring Security Unit Test With Csrf causes HttpSer

2019-07-19 15:09发布

问题:

I was unable to find this question asked anywhere else.

I have my unit test setup as follows:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
//@DatabaseSetup("classpath:decks.xml")
@WebIntegrationTest
public class DeckControllerTest {
    @Autowired
    private WebApplicationContext context;

    private MockMvc mockMvc;

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

    @Test
    @WithMockUser
    public void addDeck_ShouldRedirectIfUserLoggedInAndPostsInvalidDeck() throws Exception {
        DeckbuilderForm form = new DeckbuilderForm();
        ObjectMapper mapper = new ObjectMapper();
        String queryString = mapper.convertValue(form, UriFormat.class).toString();
        mockMvc.perform(post("/decks")
            .with(csrf())
            .contentType(MediaType.ALL)
            .content(queryString)
        )
                .andExpect(status().is3xxRedirection())
                .andExpect(flash().attributeExists("flash"));
    }

    @Test
    @WithMockUser
    public void addDeck_ShouldBeOkWithValidInput() throws Exception {
        DeckbuilderForm form = sampleValidDeckbuilderForm();
        ObjectMapper mapper = new ObjectMapper();
        String queryString = mapper.convertValue(form, UriFormat.class).toString();

        mockMvc.perform(post("/decks")
            .with(csrf().useInvalidToken())
            .content(queryString)
        )
                .andExpect(status().is3xxRedirection());
    }
}

I receive the following stacktrace upon running the test:

java.lang.IllegalArgumentException: The HttpServletRequest attribute must contain an HttpServletResponse for the attribute javax.servlet.http.HttpServletResponse

This comes from the class LazyCsrfTokenRepository:

private HttpServletResponse getResponse(HttpServletRequest request) {
    HttpServletResponse response = (HttpServletResponse) request
            .getAttribute(HTTP_RESPONSE_ATTR);
    if (response == null) {
        throw new IllegalArgumentException(
                "The HttpServletRequest attribute must contain an HttpServletResponse for the attribute "
                        + HTTP_RESPONSE_ATTR);
    }
    return response;
}

Any suggestions to resolve this problem would be highly appreciated, I understand that normally one would use @ContextConfiguration instead of @SpringApplicationConfiguration but I am only able to use this method since I am using Java Config and would not like to duplicate my configuration for tests.

回答1:

I've just encountered the same issue after upgrading to spring-boot 1.4. The problem was that my pom for some reason contained a specific version of spring-security-test (4.0.2). After removing this specific version, the project now uses version 4.1.1, which resolved the problem. If I take a look in the release commits for version 4.1.0 (https://github.com/spring-projects/spring-security/compare/4.1.0.RELEASE...master), it contains the update to spring-boot 1.4, so it makes sense.