Add WebFlux CSRF Protection
Fixes gh-4734
This commit is contained in:
+33
@@ -26,6 +26,10 @@ import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextImpl;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.web.server.csrf.CsrfToken;
|
||||
import org.springframework.security.web.server.csrf.CsrfWebFilter;
|
||||
import org.springframework.security.web.server.csrf.WebSessionServerCsrfTokenRepository;
|
||||
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
|
||||
import org.springframework.test.web.reactive.server.MockServerConfigurer;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.reactive.server.WebTestClientConfigurer;
|
||||
@@ -107,6 +111,35 @@ public class SecurityMockServerConfigurers {
|
||||
return new UserExchangeMutator(username);
|
||||
}
|
||||
|
||||
public static CsrfMutator csrf() {
|
||||
return new CsrfMutator();
|
||||
}
|
||||
|
||||
public static class CsrfMutator implements WebTestClientConfigurer, MockServerConfigurer {
|
||||
|
||||
@Override
|
||||
public void afterConfigurerAdded(WebTestClient.Builder builder,
|
||||
@Nullable WebHttpHandlerBuilder httpHandlerBuilder,
|
||||
@Nullable ClientHttpConnector connector) {
|
||||
CsrfWebFilter filter = new CsrfWebFilter();
|
||||
filter.setRequireCsrfProtectionMatcher( e -> ServerWebExchangeMatcher.MatchResult.notMatch());
|
||||
httpHandlerBuilder.filters( filters -> filters.add(0, filter));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConfigureAdded(
|
||||
WebTestClient.MockServerSpec<?> serverSpec) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeServerCreated(WebHttpHandlerBuilder builder) {
|
||||
|
||||
}
|
||||
|
||||
private CsrfMutator() {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the WebServerExchange using {@code {@link SecurityMockServerConfigurers#mockUser(UserDetails)}. Defaults to use a
|
||||
* password of "password" and granted authorities of "ROLE_USER".
|
||||
|
||||
+37
-1
@@ -18,15 +18,18 @@ package org.springframework.security.test.web.reactive.server;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter;
|
||||
import org.springframework.security.web.server.csrf.CsrfWebFilter;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.*;
|
||||
|
||||
/**
|
||||
@@ -36,7 +39,7 @@ import static org.springframework.security.test.web.reactive.server.SecurityMock
|
||||
public class SecurityMockServerConfigurersTests extends AbstractMockServerConfigurersTests {
|
||||
WebTestClient client = WebTestClient
|
||||
.bindToController(controller)
|
||||
.webFilter(new SecurityContextServerWebExchangeWebFilter())
|
||||
.webFilter( new CsrfWebFilter(), new SecurityContextServerWebExchangeWebFilter())
|
||||
.apply(springSecurity())
|
||||
.configureClient()
|
||||
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
|
||||
@@ -144,4 +147,37 @@ public class SecurityMockServerConfigurersTests extends AbstractMockServerConfig
|
||||
|
||||
assertPrincipalCreatedFromUserDetails(actual, userBuilder.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void csrfWhenMutateWithThenDisablesCsrf() {
|
||||
this.client
|
||||
.post()
|
||||
.exchange()
|
||||
.expectStatus().isEqualTo(HttpStatus.FORBIDDEN)
|
||||
.expectBody().consumeWith( b -> assertThat(new String(b.getResponseBody())).contains("CSRF"));
|
||||
|
||||
this.client
|
||||
.mutateWith(csrf())
|
||||
.post()
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void csrfWhenGlobalThenDisablesCsrf() {
|
||||
this.client = WebTestClient
|
||||
.bindToController(this.controller)
|
||||
.webFilter(new CsrfWebFilter())
|
||||
.apply(springSecurity())
|
||||
.apply(csrf())
|
||||
.configureClient()
|
||||
.build();
|
||||
|
||||
this.client
|
||||
.get()
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user