How to avoid 302 response on https spring security unit test?
Asked Answered
G

4

10

I've got java Spring Security app (built with jhipster) and I'm trying to add some unit tests that test logic based on the current authenticated user.

To do that i've configured my MockMvc object to use a web application context and spring security as so:

@Test
@Transactional
public void getAllContacts() throws Exception {
    restContactMockMvc = MockMvcBuilders
        .webAppContextSetup(context)
        .apply(springSecurity())
        .build();
    restContactMockMvc.perform(get("/api/contacts")).andExpect(status().isOk());
}

The problem is that I've also configured the app to require HTTPS, and whenever I run this unit test I get a 302 redirect response since it appears to be trying to send an HTTP request instead of HTTPS.

The way I've enforced HTTPS is with the following line in SecurityConfiguration.configure(HttpSecurity http):

if (env.acceptsProfiles("!dev"))http.requiresChannel().anyRequest().requiresSecure();

So, my question is how can I get my unit test to run correctly? Probably either by sending a mock HTTPS request, or by disabling HTTPS in the case of running a unit test?

Glassworks answered 11/1, 2016 at 22:50 Comment(0)
N
20

Using Springs MockMvc stuff you can also specify that you want to send a mock HTTPS request using the secure(true) method as follows:

restContactMockMvc.perform( get("/api/contacts").secure( true ) ).andExpect( status().isOk() )
Naoma answered 9/3, 2016 at 10:18 Comment(1)
How to set mock call secure by default?Syrupy
G
1

I'm answering my own question with the fix that i've started using, in hopes that this can help others. I'm still open to other better solutions.

In SecurityConfiguration.configure(HttpSecurity http) method, i've modified the if statement for enforcing https to skip it if we are running an integrationTest:

if (env.acceptsProfiles("!dev") && !((StandardEnvironment) env).getPropertySources().contains("integrationTest")) {
        http.requiresChannel().anyRequest().requiresSecure();
}
Glassworks answered 12/1, 2016 at 20:11 Comment(0)
S
1

In addition to the correct answer of @rhinds you can also add this code to your @Before method to have all calls be secure by default:

import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.testSecurityContext;

public class YourTestClass {
    @Autowired
    private Filter springSecurityFilterChain;
    @Autowired
    private SecurityTestController securityTestController;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        mockMvc = standaloneSetup(securityTestController)
            .addFilters(springSecurityFilterChain)
            .defaultRequest(get("/").secure(true).with(testSecurityContext()))
            .build();
    }

    // Your Tests Here

    @Test
    public void httpsRedirect() throws Exception {
        mockMvc.perform(get("/").secure(false))
            .andExpect(status().isFound())
            .andExpect(result -> StringUtils.isNotEmpty(result.getResponse().getHeader("Location")))
            .andExpect(result -> result.getResponse().getHeader("Location").startsWith("https://"));
    }
}
Surroundings answered 9/8, 2018 at 15:54 Comment(0)
H
0

With a bad configuration, Spring Security can change response status to "302 FOUND". Double check your security config.

@Bean
@Throws(Exception::class)
fun authTokenFilterBean(): CustomAuthTokenFilter {
    val authTokenFilter = CustomAuthTokenFilter()
    // if you don't have these lines, add them:
    authTokenFilter.setAuthenticationSuccessHandler(MyAuthSuccessHandler())
    authTokenFilter.setAuthenticationFailureHandler(MyAuthFailureHandler())
    return authTokenFilter
}

where

  • CustomAuthTokenFilter is your custom implementation of AbstractAuthenticationProcessingFilter;
  • MyAuthSuccessHandler and MyAuthFailureHandler are handlers provided by you. They can be empty, or they can contain your custom logic.
Holocaine answered 9/9, 2022 at 12:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.