8

Why am I receiving a 403 FORBIDDEN for the following test?

@RestController
public class MyServlet {
    @PostMapping("/")
    public Mono<String> accept(Authentication authentication) {}
}


@WebFluxTest(MyServlet.class)
@WithMockUser
public class MyServletTest {
    @Autowired
    private WebTestClient webClient;

    @Test
    public void test() {
        webClient.post().url("/")
            .exchange()
            .expectStatus().isOk();
    }
}

Result:

java.lang.AssertionError: Status expected:<200 OK> but was:<403 FORBIDDEN>

> POST /
> WebTestClient-Request-Id: [1]
> Content-Type: [application/json]

No content

< 403 FORBIDDEN Forbidden
< Content-Type: [text/plain]
< Cache-Control: [no-cache, no-store, max-age=0, must-revalidate]
< Pragma: [no-cache]
< Expires: [0]
< X-Content-Type-Options: [nosniff]
< X-Frame-Options: [DENY]
< X-XSS-Protection: [1 ; mode=block]
< Referrer-Policy: [no-referrer]

CSRF Token has been associated to this client

As far as I know, @WebFluxTest disables csrf. So why is it complaining?

membersound
  • 81,582
  • 193
  • 585
  • 1,120

4 Answers4

12
webClient.mutateWith(SecurityMockServerConfigurers.csrf()).post()...;
membersound
  • 81,582
  • 193
  • 585
  • 1,120
11

This is happening because you probably have spring-boot-starter-security in your classpath. You need to create a config:

@Configuration
@EnableWebFluxSecurity
public class WebFluxSecurityConfig {
  @Bean
  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
    return http.csrf().disable().build();
  }
}

and import it into your test with

@Import(WebFluxSecurityConfig.class)

Apparently the SecurityConfig is not loaded by default in @WebFluxTest.

I found the solution here: https://github.com/spring-projects/spring-boot/issues/16088

tomasulo
  • 1,252
  • 8
  • 9
  • ah thank-you, it wasn't imported the config when i had the @Profile({"local", "test" ... }) – ASH Jul 22 '21 at 15:11
0

You can load the default configuration using @SpringBootTest together with @AutoConfigureWebTestClient to have the test client configured and injected. Put both annotations on your test class.

aix
  • 1,063
  • 2
  • 13
  • 24
0

The root cause of this is because you have got spring-security dependency in your classpath.

In my case, it was Spring Reactive application, and the Security Configs is applied by creating a bean and annotate it with @EnableWebFluxSecurity

  @Configuration
   @EnableWebFluxSecurity
   public class SecurityConfig {
   
@Bean
  public SecurityWebFilterChain securityWebFilterChain(final ServerHttpSecurity http) {
    http.oauth2Client();
    return http.authorizeExchange().anyExchange().permitAll().and().build();
  }
}

So, by default the nature of SpringSecurity config, CSRF will be enabled. Now we have to decide the solution based on the question "Do you need CSRF enabled for your application?" If the answer is yes then your test should also use csrf which can be done by webClient.mutateWith(csrf()).post() If csrf is not required to be enabled, then disable it by http.authorizeExchange().anyExchange().permitAll().and().csrf().disable().build();

That should help you with the issue.

Sanjay Bharwani
  • 3,317
  • 34
  • 31