Skip to content

Commit 98a2ca3

Browse files
committed
Add Csrf Ignore Configurability
Issue gh-5185
1 parent 0ba3ff6 commit 98a2ca3

File tree

4 files changed

+89
-20
lines changed

4 files changed

+89
-20
lines changed

config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,18 @@
1515
*/
1616
package org.springframework.security.config.http;
1717

18+
import java.security.SecureRandom;
19+
import java.util.ArrayList;
20+
import java.util.Collections;
21+
import java.util.List;
22+
import java.util.Map;
23+
import java.util.function.Function;
24+
import javax.servlet.http.HttpServletRequest;
25+
1826
import org.apache.commons.logging.Log;
1927
import org.apache.commons.logging.LogFactory;
28+
import org.w3c.dom.Element;
29+
2030
import org.springframework.beans.BeanMetadataElement;
2131
import org.springframework.beans.factory.config.BeanDefinition;
2232
import org.springframework.beans.factory.config.BeanReference;
@@ -53,15 +63,6 @@
5363
import org.springframework.util.Assert;
5464
import org.springframework.util.StringUtils;
5565
import org.springframework.util.xml.DomUtils;
56-
import org.w3c.dom.Element;
57-
58-
import javax.servlet.http.HttpServletRequest;
59-
import java.security.SecureRandom;
60-
import java.util.ArrayList;
61-
import java.util.Collections;
62-
import java.util.List;
63-
import java.util.Map;
64-
import java.util.function.Function;
6566

6667
import static org.springframework.security.config.http.SecurityFilters.ANONYMOUS_FILTER;
6768
import static org.springframework.security.config.http.SecurityFilters.BASIC_AUTH_FILTER;
@@ -160,11 +161,12 @@ final class AuthenticationConfigBuilder {
160161
private BeanReference oauth2LoginAuthenticationProviderRef;
161162
private BeanReference oauth2LoginOidcAuthenticationProviderRef;
162163
private BeanDefinition oauth2LoginLinks;
163-
164164
private BeanDefinition authorizationRequestRedirectFilter;
165165
private BeanDefinition authorizationCodeGrantFilter;
166166
private BeanReference authorizationCodeAuthenticationProviderRef;
167167

168+
private final List<BeanDefinition> csrfIgnoreRequestMatchers = new ManagedList<>();
169+
168170
AuthenticationConfigBuilder(Element element, boolean forceAutoConfig,
169171
ParserContext pc, SessionCreationPolicy sessionPolicy,
170172
BeanReference requestCache, BeanReference authenticationManager,
@@ -194,7 +196,6 @@ final class AuthenticationConfigBuilder {
194196
createLoginPageFilterIfNeeded();
195197
createUserDetailsServiceFactory();
196198
createExceptionTranslationFilter();
197-
198199
}
199200

200201
void createRememberMeFilter(BeanReference authenticationManager) {
@@ -708,6 +709,10 @@ BeanMetadataElement getAccessDeniedHandlerBean() {
708709
return accessDeniedHandler;
709710
}
710711

712+
List<BeanDefinition> getCsrfIgnoreRequestMatchers() {
713+
return csrfIgnoreRequestMatchers;
714+
}
715+
711716
void createAnonymousFilter() {
712717
Element anonymousElt = DomUtils.getChildElementByTagName(httpElt,
713718
Elements.ANONYMOUS);

config/src/main/java/org/springframework/security/config/http/CsrfBeanDefinitionParser.java

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,12 +15,19 @@
1515
*/
1616
package org.springframework.security.config.http;
1717

18+
import java.util.Arrays;
19+
import java.util.HashSet;
20+
import java.util.List;
21+
import javax.servlet.http.HttpServletRequest;
22+
1823
import org.w3c.dom.Element;
1924

2025
import org.springframework.beans.BeanMetadataElement;
2126
import org.springframework.beans.factory.config.BeanDefinition;
27+
import org.springframework.beans.factory.config.RuntimeBeanReference;
2228
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
2329
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
30+
import org.springframework.beans.factory.support.ManagedList;
2431
import org.springframework.beans.factory.support.ManagedMap;
2532
import org.springframework.beans.factory.support.RootBeanDefinition;
2633
import org.springframework.beans.factory.xml.BeanDefinitionParser;
@@ -38,6 +45,10 @@
3845
import org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor;
3946
import org.springframework.security.web.session.InvalidSessionAccessDeniedHandler;
4047
import org.springframework.security.web.session.InvalidSessionStrategy;
48+
import org.springframework.security.web.util.matcher.AndRequestMatcher;
49+
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
50+
import org.springframework.security.web.util.matcher.OrRequestMatcher;
51+
import org.springframework.security.web.util.matcher.RequestMatcher;
4152
import org.springframework.util.ClassUtils;
4253
import org.springframework.util.StringUtils;
4354

@@ -58,6 +69,8 @@ public class CsrfBeanDefinitionParser implements BeanDefinitionParser {
5869
private String csrfRepositoryRef;
5970
private BeanDefinition csrfFilter;
6071

72+
private String requestMatcherRef;
73+
6174
@Override
6275
public BeanDefinition parse(Element element, ParserContext pc) {
6376
boolean disabled = element != null
@@ -77,10 +90,9 @@ public BeanDefinition parse(Element element, ParserContext pc) {
7790
}
7891
}
7992

80-
String matcherRef = null;
8193
if (element != null) {
8294
this.csrfRepositoryRef = element.getAttribute(ATT_REPOSITORY);
83-
matcherRef = element.getAttribute(ATT_MATCHER);
95+
this.requestMatcherRef = element.getAttribute(ATT_MATCHER);
8496
}
8597

8698
if (!StringUtils.hasText(this.csrfRepositoryRef)) {
@@ -100,8 +112,8 @@ public BeanDefinition parse(Element element, ParserContext pc) {
100112
.rootBeanDefinition(CsrfFilter.class);
101113
builder.addConstructorArgReference(this.csrfRepositoryRef);
102114

103-
if (StringUtils.hasText(matcherRef)) {
104-
builder.addPropertyReference("requireCsrfProtectionMatcher", matcherRef);
115+
if (StringUtils.hasText(this.requestMatcherRef)) {
116+
builder.addPropertyReference("requireCsrfProtectionMatcher", this.requestMatcherRef);
105117
}
106118

107119
this.csrfFilter = builder.getBeanDefinition();
@@ -172,4 +184,46 @@ BeanDefinition getCsrfLogoutHandler() {
172184
csrfAuthenticationStrategy.addConstructorArgReference(this.csrfRepositoryRef);
173185
return csrfAuthenticationStrategy.getBeanDefinition();
174186
}
187+
188+
void setIgnoreCsrfRequestMatchers(List<BeanDefinition> requestMatchers) {
189+
if (!requestMatchers.isEmpty()) {
190+
BeanMetadataElement requestMatcher;
191+
if (StringUtils.hasText(this.requestMatcherRef)) {
192+
requestMatcher = new RuntimeBeanReference(this.requestMatcherRef);
193+
} else {
194+
requestMatcher = new RootBeanDefinition(DefaultRequiresCsrfMatcher.class);
195+
}
196+
BeanDefinitionBuilder and = BeanDefinitionBuilder
197+
.rootBeanDefinition(AndRequestMatcher.class);
198+
BeanDefinitionBuilder negated = BeanDefinitionBuilder
199+
.rootBeanDefinition(NegatedRequestMatcher.class);
200+
BeanDefinitionBuilder or = BeanDefinitionBuilder
201+
.rootBeanDefinition(OrRequestMatcher.class);
202+
or.addConstructorArgValue(requestMatchers);
203+
negated.addConstructorArgValue(or.getBeanDefinition());
204+
List<BeanMetadataElement> ands = new ManagedList<>();
205+
ands.add(requestMatcher);
206+
ands.add(negated.getBeanDefinition());
207+
and.addConstructorArgValue(ands);
208+
this.csrfFilter.getPropertyValues()
209+
.add("requireCsrfProtectionMatcher", and.getBeanDefinition());
210+
}
211+
}
212+
213+
private static final class DefaultRequiresCsrfMatcher implements RequestMatcher {
214+
private final HashSet<String> allowedMethods = new HashSet<>(
215+
Arrays.asList("GET", "HEAD", "TRACE", "OPTIONS"));
216+
217+
/*
218+
* (non-Javadoc)
219+
*
220+
* @see
221+
* org.springframework.security.web.util.matcher.RequestMatcher#matches(javax.
222+
* servlet.http.HttpServletRequest)
223+
*/
224+
@Override
225+
public boolean matches(HttpServletRequest request) {
226+
return !this.allowedMethods.contains(request.getMethod());
227+
}
228+
}
175229
}

config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -238,6 +238,12 @@ void setAccessDeniedHandler(BeanMetadataElement accessDeniedHandler) {
238238
}
239239
}
240240

241+
void setCsrfIgnoreRequestMatchers(List<BeanDefinition> requestMatchers) {
242+
if (csrfParser != null) {
243+
csrfParser.setIgnoreCsrfRequestMatchers(requestMatchers);
244+
}
245+
}
246+
241247
// Needed to account for placeholders
242248
static String createPath(String path, boolean lowerCase) {
243249
return lowerCase ? path.toLowerCase() : path;

config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,14 @@
1515
*/
1616
package org.springframework.security.config.http;
1717

18+
import java.util.ArrayList;
19+
import java.util.Collections;
20+
import java.util.List;
21+
1822
import org.apache.commons.logging.Log;
1923
import org.apache.commons.logging.LogFactory;
24+
import org.w3c.dom.Element;
25+
2026
import org.springframework.beans.BeanMetadataElement;
2127
import org.springframework.beans.factory.config.BeanDefinition;
2228
import org.springframework.beans.factory.config.BeanReference;
@@ -44,9 +50,6 @@
4450
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
4551
import org.springframework.util.StringUtils;
4652
import org.springframework.util.xml.DomUtils;
47-
import org.w3c.dom.Element;
48-
49-
import java.util.*;
5053

5154
/**
5255
* Sets up HTTP security: filter stack and protected URLs.
@@ -156,6 +159,7 @@ private BeanReference createFilterChain(Element element, ParserContext pc) {
156159
httpBldr.setLogoutHandlers(authBldr.getLogoutHandlers());
157160
httpBldr.setEntryPoint(authBldr.getEntryPointBean());
158161
httpBldr.setAccessDeniedHandler(authBldr.getAccessDeniedHandlerBean());
162+
httpBldr.setCsrfIgnoreRequestMatchers(authBldr.getCsrfIgnoreRequestMatchers());
159163

160164
authenticationProviders.addAll(authBldr.getProviders());
161165

0 commit comments

Comments
 (0)