Edited at

Spring Security にてフォーム認証のテストを実施した際に 404 エラーが発生する

More than 1 year has passed since last update.


概要

Spring Security にて下記の構成のフォーム認証のテストを実施した際に、404 エラーが発生しました。


POST
--------------------------------->
フォーム画面 AuthenticationProvider (認証処理)
・ユーザー名
・パスワード <=================================
ユーザー情報


SecurityConfig.java

@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/webjars/**", "/css/");
}

@Override
protected void configure(HttpSecurity http) {
http.authorizeRequests()
.antMatchers("signin").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/authentication")
.loginPage("signin")
.failureUrl("signin" + "?error")
.successForwardUrl("/hoge/list")
.failureForwardUrl("/authenticationError")
.usernameParameter("username")
.passwordParameter("password")
.and()
.logout()
.logoutSuccessUrl("signin");

}



TestClass.java

@RunWith(SpringRunner.class)

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(classes = HogeApplication.class)
public class TestClass {

@Before
public void リクエストの用意する() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.build();
}

@Test
public void リクエストURLで認証する() throws Exception {
ResultActions result = mvc.perform(
MockMvcRequestBuilders.post("/authentication")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.param("username", ユーザーアカウント)
.param("password", パスワード)
);
result.andExpect(status().isOk())
.andExpect(forwardedUrl("/hoge/list"));
}
}



Assertion の結果

java.lang.AssertionError: Status
Expected :200
Actual :404


回避策

下記 2 つの対処策を実施します。


  • 要求時に csrf() を指定する

  • MockMvcBuider に springSecurity() を適用する

上記を適用するとテストクラスは下記のようになります。


TestClass.java

@RunWith(SpringRunner.class)

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(classes = HogeApplication.class)
public class TestClass {

@Before
public void リクエストの用意する() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity()) // これを apply しないと csrf を設定しても 404 になってしまう。
.build();
}

@Test
public void リクエストURLで認証する() throws Exception {
ResultActions result = mvc.perform(
MockMvcRequestBuilders.post("/authentication")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.with(csrf())
.param("username", ユーザーアカウント)
.param("password", パスワード)
);
result.andExpect(status().isOk())
.apply(springSecurity()) // これを apply しないと csrf を設定しても 404 になってしまう。
.andExpect(forwardedUrl("/hoge/list"));
}
}



formの設定について

公式のドキュメント にも csrf() への言及はありますが、明示的に post 要求せず、下記の実装である場合に、 username と password がサーバー側に渡りませんでした。何か問題はあるのでしょうが、わからず。。。


TestClass.java

public class TestClass {

public パラメーターが渡らないメソッド() {
ResultActions result2 = mvc.perform(formLogin("/authentication")
.user(ユーザーアカウント).password(パスワード));
result2.andExpect(status().isOk())
.andExpect(forwardedUrl("/clients/list"))
.andDo(MockMvcResultHandlers.print());
ResultActions result3 = mvc.perform(MockMvcRequestBuilders.post("/authentication")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.with(csrf())
.with(user(ユーザーアカウント).password(パスワード)));
result3.andExpect(status().isOk())
.andExpect(forwardedUrl("/clients/list"))
.andDo(MockMvcResultHandlers.print());
}
}

csrf().asHeader() でも結果は同じでした。


springSecurity の適用

springSecurity() を適用させないと、MockMvcRequestBuilders#post に csrf() を設定しても 404 になります。