Testing Spring Security Controller Using Spring Mvc Test

2.7k views Asked by At

Login jsp form and spring security xml configuration look like:

<spring:url value="/j_spring_security_check" var="login" />
<form action="${login}" method="POST">
<fieldset>
    <legend>Login</legend>
        <input type="text" name="j_username" id="username" placeholder="Usename"/>
        <input type="text" name="j_password" id="password" placeholder="Password"/>
        <input type="submit" value="Login" />
</fieldset>
</form>
...
<security:form-login login-page="/public/authentication/login.htm"
     login-processing-url="/j_spring_security_check"
     default-target-url="/public/index.htm"
     authentication-failure-url="/public/authentication/login.htm?authenticationNok=1"/>

Here is the test for form sumbission:

@Test
public void testLoginPostController() throws Exception {
    Account account = new AccountBuilder("test", "test", "[email protected]", Address.FAKE_EMPTY_ADDRESS4TESTS)
            .build();
    this.mockMvc.perform(post("/j_spring_security_check").param("j_username", account.getUsername()).param("j_password", "test"))
            .andDo(print())
            .andExpect(status().isMovedTemporarily())
            .andExpect(view().name("redirect:/public/index.htm"));
}

But I'm getting: java.lang.AssertionError: Status expected:<302> but was:<404>

When I open login page in browser I see that the generated form is:

<form action="/SpringMvcExample/j_spring_security_check" method="POST">

Ok, I tried to change test to:

this.mockMvc.perform(post("/SpringMvcExample/j_spring_security_check").param("j_username", account.getUsername()).param("j_password", "test"))

But got the same result. At the same time, when I submit the login form in the browser, it redirects me to the public/index.htm page, as exptect in test.

What am I doing wrong?

2

There are 2 answers

0
Rob Winch On BEST ANSWER

UPDATE: Spring Security 4 has added official Test Support. There is a section that describes testing with MockMvc in detail.

It sounds as though you have not added the Spring Security Filter to your MockMvc. For example:

public class MyTests {

    @Autowired
    private FilterChainProxy springSecurityFilterChain;

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.webApplicationContextSetup(this.wac)
            .addFilters(this.springSecurityFilterChain).build();
    }

    @Test
    public void testLoginPostController() throws Exception {
        Account account = new AccountBuilder("test", "test", "[email protected]", Address.FAKE_EMPTY_ADDRESS4TESTS)
                .build();
        this.mockMvc.perform(post("/j_spring_security_check").param("j_username", account.getUsername()).param("j_password", "test"))
                .andDo(print())
                .andExpect(status().isMovedTemporarily())
                .andExpect(view().name("redirect:/public/index.htm"));
    }

}

The reason this is happening is because right now the MockMvc is only aware of your Spring MVC configuration and is not aware of any Filter (i.e. the FilterChainProxy). Since validation of the username and password (i.e. processing of /j_spring_security_check) occurs within FilterChainProxy before it is sent to Spring MVC and you have not included it you are getting a 404.

0
billc.cn On

/j_spring_security_check is a special address handled by Spring Security (possibly via its filter, but I did not verify this). It is not a request handler registered with Spring MVC, so you cannot use the MockMVC to test it.

You'll need to start a real application container and use something HttpClient or Selenium.