Open
Description
spring-boot-2.6.3
I'm migrating my MockMvc
tests to WebTestClient
, for having all my tests using the same underlying API.
The following example project shows that authenticating on the /login
page works with MockMvc
, but does not with WebTestClient
.
In real world, I'm testing a ldap security configuration, but the issue is reproducible even with in-memory authentication.
This is a result result of spring-projects/spring-boot#29825
(see the issue also for a full sample project attached)
I assume this is a bug, as authentication with MockMvc
works flawless, and WebTestClient
does not.
Tests:
@SpringBootTest
@AutoConfigureMockMvc
public class PersonControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private WebTestClient webTestClient;
//works
@Test
public void testMockMvc() throws Exception {
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder login = formLogin()
.user("junituser")
.password("junitpw");
mockMvc.perform(login)
.andExpect(authenticated().withUsername("junituser"));
}
//works
@Test
public void testMockMvcUnauthenticated() throws Exception {
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder login = formLogin()
.user("junituser")
.password("invalid");
mockMvc.perform(login)
.andExpect(unauthenticated());
}
//works
@Test
public void testRedirectToLoginPage() {
webTestClient.get().uri("/").exchange().expectStatus().is3xxRedirection();
}
//works
@Test
public void testLoginPageAnonymous() {
webTestClient.get().uri("/login").exchange().expectStatus().isOk();
}
//fails with 403 forbidden
@Test
public void testWebClient() {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("username", "junituser");
formData.add("password", "junitpw");
webTestClient.post()
.uri("/login") //the test would fail the same executed against '/example' @RestController
.body(BodyInserters.fromFormData(formData))
.exchange()
.expectStatus()
.isOk();
}
//throws NPE
@Test
public void testWebClientCsrf() {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("username", "junituser");
formData.add("password", "junitpw");
//there is no FormLoginRequestBuilder for WebTestClient?
webTestClient.mutateWith(csrf())
.post()
.uri("/login")
.body(BodyInserters.fromFormData(formData))
.exchange()
.expectStatus()
.isOk();
}
}
Source:
@RestController
public class PersonController {
@GetMapping("/example")
public String example() {
return "Authorized user";
}
@PostMapping("/example")
public String examplePost() {
return "Authorized user";
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("junituser")
.password("{noop}junitpw")
.roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().permitAll();
}
}
@SpringBootApplication
public class MainApp {
public static void main(String[] args) {
SpringApplication.run(MainApp.class, args);
}
}