简体   繁体   中英

Test method secured by spring security

I have just added spring security for my project with configuration:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    private final DataSource dataSource;

    @Autowired
    public SecurityConfiguration(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication()
                .withDefaultSchema()
                .dataSource(dataSource)
                .withUser("user")
                .password("{bcrypt}" + new BCryptPasswordEncoder().encode("password"))
                .roles("USER")
                .and()
                .withUser("admin")
                .password("{bcrypt}" + new BCryptPasswordEncoder().encode("admin"))
                .roles("ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/h2-console/**").permitAll()
                .antMatchers("/user").hasAnyRole("USER", "ADMIN")
                .antMatchers("/admin").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and()
                .formLogin().permitAll();
        http.headers().frameOptions().disable();
    }
}

And added some dummy methods just to test it:

@RestController
public class LoginController {

    @PostMapping("/user")
    public String userPanel() {
        return "userPanel";
    }

    @PostMapping("/admin")
    public String adminPanel() {
        return "adminPanel";
    }
}

From browser it works okay, so when I login as admin then I can access both endpoints (405 http error code) and when I am login with user and try to access /admin endpoint then I get 403 Forbidden which is perfectly fine. However when I wrote test for it:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class SecurityTest {
    private LoginController loginController;

    @Before
    public void setUp(){
        loginController = new LoginController();
    }

    @Test
    @WithMockUser(username = "admin", roles = {"USER", "ADMIN"})
    public void testUserPanel() {
        assertThat(loginController.userPanel()).isEqualTo("userPanel");
    }

    @Test
    @WithMockUser(username = "user", roles = {"USER"})
    public void testAdminPanel() {
        assertThat(loginController.adminPanel()).isEqualTo("adminPanel");
    }
}

both tests are working even when I am trying to access /admin endpoint with USER role. I would expect this test to fail and throw 403 as in browser. What's wrong here?

Final response after @crizzis answer:

import com.storageroom.StorageRoomApplication;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = StorageRoomApplication.class)
public class SecurityTest {
    @Autowired
    private WebApplicationContext context;

    private MockMvc mockMvc;

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

    @Test
    @WithMockUser(value = "user", roles = {"USER"})
    public void testUserPanelWithUserRole() throws Exception {
        mockMvc
                .perform(
                        post("/user")
                                .contentType(
                                        MediaType.APPLICATION_JSON).
                                content("")).
                andExpect(status().isOk())
                .andReturn().getResponse().getContentAsString();
    }

    @Test
    @WithMockUser(value = "user", roles = {"USER"})
    public void testAdminPanelWithUserRole() throws Exception {
        mockMvc
                .perform(
                        post("/admin")
                                .contentType(
                                        MediaType.APPLICATION_JSON).
                                content("")).
                andExpect(status().isForbidden())
                .andReturn().getResponse().getContentAsString();
    }

    @Test
    @WithMockUser(value = "admin", roles = {"ADMIN"})
    public void testAdminPanelWithAdminRole() throws Exception {
        mockMvc
                .perform(
                        post("/admin")
                                .contentType(
                                        MediaType.APPLICATION_JSON).
                                content("")).
                andExpect(status().isOk())
                .andReturn().getResponse().getContentAsString();
    }
}

You created a plain new LoginController() , how did you expect it to have security rules applied?

It's called HttpSecurity for a reason, you need to make the request via HTTP for the rules to actually have any effect.

Instead of interacting with LoginController directly, add @AutoConfigureMockMvc and inject MockMvc into your test. Then use it to execute a request against your endpoints.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM