Reputation: 5743
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();
}
}
Upvotes: 0
Views: 556
Reputation: 10726
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.
Upvotes: 1