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.
1515 */
1616package 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+
1823import org .w3c .dom .Element ;
1924
2025import org .springframework .beans .BeanMetadataElement ;
2126import org .springframework .beans .factory .config .BeanDefinition ;
27+ import org .springframework .beans .factory .config .RuntimeBeanReference ;
2228import org .springframework .beans .factory .parsing .BeanComponentDefinition ;
2329import org .springframework .beans .factory .support .BeanDefinitionBuilder ;
30+ import org .springframework .beans .factory .support .ManagedList ;
2431import org .springframework .beans .factory .support .ManagedMap ;
2532import org .springframework .beans .factory .support .RootBeanDefinition ;
2633import org .springframework .beans .factory .xml .BeanDefinitionParser ;
3845import org .springframework .security .web .servlet .support .csrf .CsrfRequestDataValueProcessor ;
3946import org .springframework .security .web .session .InvalidSessionAccessDeniedHandler ;
4047import 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 ;
4152import org .springframework .util .ClassUtils ;
4253import 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}
0 commit comments