Pertanyaan Spring Test mengembalikan 401 untuk URL yang tidak aman


Saya menggunakan Spring untuk tes MVC

Ini kelas tes saya

@RunWith(SpringRunner.class)
@WebMvcTest
public class ITIndexController {

    @Autowired
    WebApplicationContext context;

    MockMvc mockMvc;

    @MockBean
    UserRegistrationApplicationService userRegistrationApplicationService;

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

    @Test
    public void should_render_index() throws Exception {
        mockMvc.perform(get("/"))
            .andExpect(status().isOk())
            .andExpect(view().name("index"))
            .andExpect(content().string(containsString("Login")));
    }
}

Berikut ini konfigurasi MVC

@Configuration
@EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/login/form").setViewName("login");
    }
}

Ini adalah konfigurasi keamanan

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier("customUserDetailsService")
    UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/resources/**", "/signup", "/signup/form", "/").permitAll()
            .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login/form").permitAll().loginProcessingUrl("/login").permitAll()
                .and()
            .logout().logoutSuccessUrl("/login/form?logout").permitAll()
                .and()
            .csrf().disable();
    }

    @Autowired
    public void configureGlobalFromDatabase(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }
}

Ketika saya menjalankan tes saya gagal dengan pesan:

java.lang.AssertionError: Status expected:<200> but was:<401>
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:54)
at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:81)
at org.springframework.test.web.servlet.result.StatusResultMatchers$10.match(StatusResultMatchers.java:664)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:171)
at com.marco.nutri.integration.web.controller.ITIndexController.should_render_index(ITIndexController.java:46)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

Saya mengerti bahwa itu gagal karena fakta bahwa url dilindungi dengan keamanan musim semi, tetapi ketika saya menjalankan aplikasi saya, saya dapat mengakses url itu bahkan tanpa diotentikasi.

Apakah saya melakukan kesalahan?


6
2017-09-18 05:00


asal


Jawaban:


Saya menemukan jawabannya
Dokumen musim semi mengatakan bahwa:

@WebMvcTest akan mengkonfigurasi secara otomatis infrastruktur Spring MVC dan   membatasi biji yang dipindai ke @Controller, @ControllerAdvice, @JsonComponent,   Filter, WebMvcConfigurer dan HandlerMethodArgumentResolver. Reguler   Kacang @Component tidak akan dipindai saat menggunakan anotasi ini.

Dan menurut masalah ini di github:

https://github.com/spring-projects/spring-boot/issues/5476

The @WebMvcTest secara default mengkonfigurasi otomatis keamanan musim semi jika semi-keamanan-tes hadir di jalur kelas (yang dalam kasus saya adalah).

Jadi karena kelas WebSecurityConfigurer tidak dipilih, keamanan default dikonfigurasikan secara otomatis, itu adalah motif saya menerima 401 di url yang tidak dijamin dalam konfigurasi keamanan saya. Konfigurasi otomatis default keamanan Spring melindungi semua url dengan otentikasi dasar.

Apa yang saya lakukan untuk memecahkan masalah adalah untuk membubuhi keterangan kelas dengan @ContextConfiguration, dan @MockBean seperti yang dijelaskan dalam dokumentasi:

Seringkali @WebMvcTest akan terbatas pada satu pengontrol dan digunakan dalam   kombinasi dengan @MockBean untuk menyediakan implementasi tiruan untuk   kolaborator yang dibutuhkan.

Dan inilah kelas ujiannya

@RunWith(SpringRunner.class)
@WebMvcTest
@ContextConfiguration(classes={Application.class, MvcConfig.class, SecurityConfig.class})
public class ITIndex {

    @Autowired
    WebApplicationContext context;

    MockMvc mockMvc;

    @MockBean
    UserRegistrationApplicationService userRegistrationApplicationService;

    @MockBean
    UserDetailsService userDetailsService;

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

    @Test
    public void should_render_index() throws Exception {
        mockMvc.perform(get("/"))
            .andExpect(status().isOk())
            .andExpect(view().name("index"))
            .andExpect(content().string(containsString("Login")));
    }
}

Aplikasi, MvcConfig dan SecurityConfig adalah semua kelas konfigurasi saya


7
2017-09-18 06:08



Jika Anda menggunakan SpringJUnit4ClassRunner bukan SpringRunner Anda dapat menangkap permintaan Anda di lapisan keamanan. Jika Anda menggunakan otentikasi dasar, Anda harus menggunakan metode httpBasic di mockMvc.perform

 mockMvc.perform(get("/").with(httpBasic(username,rightPassword))

0
2018-04-03 11:33



Tidak yakin apakah ini tersedia ketika pertanyaan asli diminta, tetapi jika benar-benar tidak ingin menguji bagian keamanan permintaan web (yang tampaknya masuk akal jika titik akhir diketahui tidak aman), maka saya pikir ini bisa dilakukan hanya dengan menggunakan secure atribut dari @WebMvcTest anotasi (secara default ke true jadi mengaturnya false harus menonaktifkan konfigurasi otomatis dari dukungan MockMvc Keamanan Musim Semi):

@WebMvcTest(secure = false)

Info lebih lanjut tersedia di javadocs


0
2017-08-23 07:55