Add Request-level CSRF Skip
Fixes gh-7367
This commit is contained in:
@@ -35,6 +35,8 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import static java.lang.Boolean.TRUE;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Applies
|
||||
@@ -63,6 +65,16 @@ public final class CsrfFilter extends OncePerRequestFilter {
|
||||
*/
|
||||
public static final RequestMatcher DEFAULT_CSRF_MATCHER = new DefaultRequiresCsrfMatcher();
|
||||
|
||||
/**
|
||||
* The attribute name to use when marking a given request as one that should not be filtered.
|
||||
*
|
||||
* To use, set the attribute on your {@link HttpServletRequest}:
|
||||
* <pre>
|
||||
* CsrfFilter.skipRequest(request);
|
||||
* </pre>
|
||||
*/
|
||||
private static final String SHOULD_NOT_FILTER = "SHOULD_NOT_FILTER" + CsrfFilter.class.getName();
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
private final CsrfTokenRepository tokenRepository;
|
||||
private RequestMatcher requireCsrfProtectionMatcher = DEFAULT_CSRF_MATCHER;
|
||||
@@ -73,6 +85,11 @@ public final class CsrfFilter extends OncePerRequestFilter {
|
||||
this.tokenRepository = csrfTokenRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
|
||||
return TRUE.equals(request.getAttribute(SHOULD_NOT_FILTER));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
@@ -124,6 +141,10 @@ public final class CsrfFilter extends OncePerRequestFilter {
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
public static void skipRequest(HttpServletRequest request) {
|
||||
request.setAttribute(SHOULD_NOT_FILTER, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a {@link RequestMatcher} that is used to determine if CSRF protection
|
||||
* should be applied. If the {@link RequestMatcher} returns true for a given request,
|
||||
|
||||
@@ -32,6 +32,8 @@ import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
|
||||
import static java.lang.Boolean.TRUE;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Applies
|
||||
@@ -60,6 +62,16 @@ import org.springframework.web.server.WebFilterChain;
|
||||
public class CsrfWebFilter implements WebFilter {
|
||||
public static final ServerWebExchangeMatcher DEFAULT_CSRF_MATCHER = new DefaultRequireCsrfProtectionMatcher();
|
||||
|
||||
/**
|
||||
* The attribute name to use when marking a given request as one that should not be filtered.
|
||||
*
|
||||
* To use, set the attribute on your {@link ServerWebExchange}:
|
||||
* <pre>
|
||||
* CsrfWebFilter.skipExchange(exchange);
|
||||
* </pre>
|
||||
*/
|
||||
private static final String SHOULD_NOT_FILTER = "SHOULD_NOT_FILTER" + CsrfWebFilter.class.getName();
|
||||
|
||||
private ServerWebExchangeMatcher requireCsrfProtectionMatcher = DEFAULT_CSRF_MATCHER;
|
||||
|
||||
private ServerCsrfTokenRepository csrfTokenRepository = new WebSessionServerCsrfTokenRepository();
|
||||
@@ -86,6 +98,10 @@ public class CsrfWebFilter implements WebFilter {
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
if (TRUE.equals(exchange.getAttribute(SHOULD_NOT_FILTER))) {
|
||||
return chain.filter(exchange).then(Mono.empty());
|
||||
}
|
||||
|
||||
return this.requireCsrfProtectionMatcher.matches(exchange)
|
||||
.filter( matchResult -> matchResult.isMatch())
|
||||
.filter( matchResult -> !exchange.getAttributes().containsKey(CsrfToken.class.getName()))
|
||||
@@ -96,6 +112,10 @@ public class CsrfWebFilter implements WebFilter {
|
||||
.handle(exchange, e));
|
||||
}
|
||||
|
||||
public static void skipExchange(ServerWebExchange exchange) {
|
||||
exchange.getAttributes().put(SHOULD_NOT_FILTER, TRUE);
|
||||
}
|
||||
|
||||
private Mono<Void> validateToken(ServerWebExchange exchange) {
|
||||
return this.csrfTokenRepository.loadToken(exchange)
|
||||
.switchIfEmpty(Mono.defer(() -> Mono.error(new CsrfException("CSRF Token has been associated to this client"))))
|
||||
|
||||
Reference in New Issue
Block a user