LoginSignup
1
3

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-08-21

概要

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 になります。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3