HeadersBeanDefinitionParser.java
/*
* Copyright 2004-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.http;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.web.header.HeaderWriterFilter;
import org.springframework.security.web.header.writers.CacheControlHeadersWriter;
import org.springframework.security.web.header.writers.ContentSecurityPolicyHeaderWriter;
import org.springframework.security.web.header.writers.CrossOriginEmbedderPolicyHeaderWriter;
import org.springframework.security.web.header.writers.CrossOriginOpenerPolicyHeaderWriter;
import org.springframework.security.web.header.writers.CrossOriginResourcePolicyHeaderWriter;
import org.springframework.security.web.header.writers.FeaturePolicyHeaderWriter;
import org.springframework.security.web.header.writers.HpkpHeaderWriter;
import org.springframework.security.web.header.writers.HstsHeaderWriter;
import org.springframework.security.web.header.writers.PermissionsPolicyHeaderWriter;
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter;
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter.ReferrerPolicy;
import org.springframework.security.web.header.writers.StaticHeadersWriter;
import org.springframework.security.web.header.writers.XContentTypeOptionsHeaderWriter;
import org.springframework.security.web.header.writers.XXssProtectionHeaderWriter;
import org.springframework.security.web.header.writers.frameoptions.RegExpAllowFromStrategy;
import org.springframework.security.web.header.writers.frameoptions.StaticAllowFromStrategy;
import org.springframework.security.web.header.writers.frameoptions.WhiteListedAllowFromStrategy;
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
/**
* Parser for the {@code HeadersFilter}.
*
* @author Marten Deinum
* @author Tim Ysewyn
* @author Edd�� Mel��ndez
* @author Vedran Pavic
* @author Rafiullah Hamedy
* @since 3.2
*/
public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
private static final String ATT_DISABLED = "disabled";
private static final String ATT_POLICY = "policy";
private static final String ATT_STRATEGY = "strategy";
private static final String ATT_FROM_PARAMETER = "from-parameter";
private static final String ATT_NAME = "name";
private static final String ATT_VALUE = "value";
private static final String ATT_REF = "ref";
private static final String ATT_INCLUDE_SUBDOMAINS = "include-subdomains";
private static final String ATT_MAX_AGE_SECONDS = "max-age-seconds";
private static final String ATT_REQUEST_MATCHER_REF = "request-matcher-ref";
private static final String ATT_PRELOAD = "preload";
private static final String ATT_REPORT_ONLY = "report-only";
private static final String ATT_REPORT_URI = "report-uri";
private static final String ATT_ALGORITHM = "algorithm";
private static final String ATT_POLICY_DIRECTIVES = "policy-directives";
private static final String ATT_HEADER_VALUE = "header-value";
private static final String CACHE_CONTROL_ELEMENT = "cache-control";
private static final String HPKP_ELEMENT = "hpkp";
private static final String PINS_ELEMENT = "pins";
private static final String HSTS_ELEMENT = "hsts";
private static final String XSS_ELEMENT = "xss-protection";
private static final String CONTENT_TYPE_ELEMENT = "content-type-options";
private static final String FRAME_OPTIONS_ELEMENT = "frame-options";
private static final String GENERIC_HEADER_ELEMENT = "header";
private static final String CONTENT_SECURITY_POLICY_ELEMENT = "content-security-policy";
private static final String REFERRER_POLICY_ELEMENT = "referrer-policy";
private static final String FEATURE_POLICY_ELEMENT = "feature-policy";
private static final String PERMISSIONS_POLICY_ELEMENT = "permissions-policy";
private static final String CROSS_ORIGIN_OPENER_POLICY_ELEMENT = "cross-origin-opener-policy";
private static final String CROSS_ORIGIN_EMBEDDER_POLICY_ELEMENT = "cross-origin-embedder-policy";
private static final String CROSS_ORIGIN_RESOURCE_POLICY_ELEMENT = "cross-origin-resource-policy";
private static final String ALLOW_FROM = "ALLOW-FROM";
private ManagedList<BeanMetadataElement> headerWriters;
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
this.headerWriters = new ManagedList<>();
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(HeaderWriterFilter.class);
boolean disabled = element != null && "true".equals(resolveAttribute(parserContext, element, "disabled"));
boolean defaultsDisabled = element != null
&& "true".equals(resolveAttribute(parserContext, element, "defaults-disabled"));
boolean addIfNotPresent = element == null || !disabled && !defaultsDisabled;
parseCacheControlElement(addIfNotPresent, element);
parseHstsElement(addIfNotPresent, element, parserContext);
parseXssElement(addIfNotPresent, element, parserContext);
parseFrameOptionsElement(addIfNotPresent, element, parserContext);
parseContentTypeOptionsElement(addIfNotPresent, element);
parseHpkpElement(element == null || !disabled, element, parserContext);
parseContentSecurityPolicyElement(disabled, element, parserContext);
parseReferrerPolicyElement(element, parserContext);
parseFeaturePolicyElement(element, parserContext);
parsePermissionsPolicyElement(element, parserContext);
parseCrossOriginOpenerPolicy(disabled, element);
parseCrossOriginEmbedderPolicy(disabled, element);
parseCrossOriginResourcePolicy(disabled, element);
parseHeaderElements(element);
boolean noWriters = this.headerWriters.isEmpty();
if (disabled && !noWriters) {
parserContext.getReaderContext()
.error("Cannot specify <headers disabled=\"true\"> with child elements.", element);
}
else if (noWriters) {
return null;
}
builder.addConstructorArgValue(this.headerWriters);
return builder.getBeanDefinition();
}
/**
* Resolve the placeholder for a given attribute on a element.
* @param pc
* @param element
* @param attributeName
* @return Resolved value of the placeholder
*/
private String resolveAttribute(ParserContext pc, Element element, String attributeName) {
return pc.getReaderContext().getEnvironment().resolvePlaceholders(element.getAttribute(attributeName));
}
private void parseCacheControlElement(boolean addIfNotPresent, Element element) {
Element cacheControlElement = (element != null)
? DomUtils.getChildElementByTagName(element, CACHE_CONTROL_ELEMENT) : null;
boolean disabled = "true".equals(getAttribute(cacheControlElement, ATT_DISABLED, "false"));
if (disabled) {
return;
}
if (addIfNotPresent || cacheControlElement != null) {
addCacheControl();
}
}
private void addCacheControl() {
BeanDefinitionBuilder headersWriter = BeanDefinitionBuilder
.genericBeanDefinition(CacheControlHeadersWriter.class);
this.headerWriters.add(headersWriter.getBeanDefinition());
}
private void parseHstsElement(boolean addIfNotPresent, Element element, ParserContext context) {
Element hstsElement = (element != null) ? DomUtils.getChildElementByTagName(element, HSTS_ELEMENT) : null;
if (addIfNotPresent || hstsElement != null) {
addHsts(addIfNotPresent, hstsElement, context);
}
}
private void addHsts(boolean addIfNotPresent, Element hstsElement, ParserContext context) {
BeanDefinitionBuilder headersWriter = BeanDefinitionBuilder.genericBeanDefinition(HstsHeaderWriter.class);
if (hstsElement != null) {
boolean disabled = "true".equals(getAttribute(hstsElement, ATT_DISABLED, "false"));
String includeSubDomains = hstsElement.getAttribute(ATT_INCLUDE_SUBDOMAINS);
if (StringUtils.hasText(includeSubDomains)) {
if (disabled) {
attrNotAllowed(context, ATT_INCLUDE_SUBDOMAINS, ATT_DISABLED, hstsElement);
}
headersWriter.addPropertyValue("includeSubDomains", includeSubDomains);
}
String maxAgeSeconds = hstsElement.getAttribute(ATT_MAX_AGE_SECONDS);
if (StringUtils.hasText(maxAgeSeconds)) {
if (disabled) {
attrNotAllowed(context, ATT_MAX_AGE_SECONDS, ATT_DISABLED, hstsElement);
}
headersWriter.addPropertyValue("maxAgeInSeconds", maxAgeSeconds);
}
String requestMatcherRef = hstsElement.getAttribute(ATT_REQUEST_MATCHER_REF);
if (StringUtils.hasText(requestMatcherRef)) {
if (disabled) {
attrNotAllowed(context, ATT_REQUEST_MATCHER_REF, ATT_DISABLED, hstsElement);
}
headersWriter.addPropertyReference("requestMatcher", requestMatcherRef);
}
String preload = hstsElement.getAttribute(ATT_PRELOAD);
if (StringUtils.hasText(preload)) {
if (disabled) {
attrNotAllowed(context, ATT_PRELOAD, ATT_DISABLED, hstsElement);
}
headersWriter.addPropertyValue("preload", preload);
}
if (disabled) {
return;
}
}
if (addIfNotPresent || hstsElement != null) {
this.headerWriters.add(headersWriter.getBeanDefinition());
}
}
private void parseHpkpElement(boolean addIfNotPresent, Element element, ParserContext context) {
Element hpkpElement = (element != null) ? DomUtils.getChildElementByTagName(element, HPKP_ELEMENT) : null;
if (addIfNotPresent || hpkpElement != null) {
addHpkp(addIfNotPresent, hpkpElement, context);
}
}
private void addHpkp(boolean addIfNotPresent, Element hpkpElement, ParserContext context) {
if (hpkpElement != null) {
boolean disabled = "true".equals(getAttribute(hpkpElement, ATT_DISABLED, "false"));
if (disabled) {
return;
}
BeanDefinitionBuilder headersWriter = BeanDefinitionBuilder.genericBeanDefinition(HpkpHeaderWriter.class);
Element pinsElement = DomUtils.getChildElementByTagName(hpkpElement, PINS_ELEMENT);
if (pinsElement != null) {
List<Element> pinElements = DomUtils.getChildElements(pinsElement);
Map<String, String> pins = new LinkedHashMap<>();
for (Element pinElement : pinElements) {
String hash = pinElement.getAttribute(ATT_ALGORITHM);
if (!StringUtils.hasText(hash)) {
hash = "sha256";
}
Node pinValueNode = pinElement.getFirstChild();
if (pinValueNode == null) {
context.getReaderContext().warning("Missing value for pin entry.", hpkpElement);
continue;
}
String fingerprint = pinElement.getFirstChild().getTextContent();
pins.put(fingerprint, hash);
}
headersWriter.addPropertyValue("pins", pins);
}
String includeSubDomains = hpkpElement.getAttribute(ATT_INCLUDE_SUBDOMAINS);
if (StringUtils.hasText(includeSubDomains)) {
headersWriter.addPropertyValue("includeSubDomains", includeSubDomains);
}
String maxAgeSeconds = hpkpElement.getAttribute(ATT_MAX_AGE_SECONDS);
if (StringUtils.hasText(maxAgeSeconds)) {
headersWriter.addPropertyValue("maxAgeInSeconds", maxAgeSeconds);
}
String reportOnly = hpkpElement.getAttribute(ATT_REPORT_ONLY);
if (StringUtils.hasText(reportOnly)) {
headersWriter.addPropertyValue("reportOnly", reportOnly);
}
String reportUri = hpkpElement.getAttribute(ATT_REPORT_URI);
if (StringUtils.hasText(reportUri)) {
headersWriter.addPropertyValue("reportUri", reportUri);
}
if (addIfNotPresent) {
this.headerWriters.add(headersWriter.getBeanDefinition());
}
}
}
private void parseContentSecurityPolicyElement(boolean elementDisabled, Element element, ParserContext context) {
Element contentSecurityPolicyElement = (elementDisabled || element == null) ? null
: DomUtils.getChildElementByTagName(element, CONTENT_SECURITY_POLICY_ELEMENT);
if (contentSecurityPolicyElement != null) {
addContentSecurityPolicy(contentSecurityPolicyElement, context);
}
}
private void addContentSecurityPolicy(Element contentSecurityPolicyElement, ParserContext context) {
BeanDefinitionBuilder headersWriter = BeanDefinitionBuilder
.genericBeanDefinition(ContentSecurityPolicyHeaderWriter.class);
String policyDirectives = contentSecurityPolicyElement.getAttribute(ATT_POLICY_DIRECTIVES);
if (!StringUtils.hasText(policyDirectives)) {
context.getReaderContext()
.error(ATT_POLICY_DIRECTIVES + " requires a 'value' to be set.", contentSecurityPolicyElement);
}
else {
headersWriter.addConstructorArgValue(policyDirectives);
}
String reportOnly = contentSecurityPolicyElement.getAttribute(ATT_REPORT_ONLY);
if (StringUtils.hasText(reportOnly)) {
headersWriter.addPropertyValue("reportOnly", reportOnly);
}
this.headerWriters.add(headersWriter.getBeanDefinition());
}
private void parseReferrerPolicyElement(Element element, ParserContext context) {
Element referrerPolicyElement = (element != null)
? DomUtils.getChildElementByTagName(element, REFERRER_POLICY_ELEMENT) : null;
if (referrerPolicyElement != null) {
addReferrerPolicy(referrerPolicyElement, context);
}
}
private void addReferrerPolicy(Element referrerPolicyElement, ParserContext context) {
BeanDefinitionBuilder headersWriter = BeanDefinitionBuilder
.genericBeanDefinition(ReferrerPolicyHeaderWriter.class);
String policy = referrerPolicyElement.getAttribute(ATT_POLICY);
if (StringUtils.hasLength(policy)) {
headersWriter.addConstructorArgValue(ReferrerPolicy.get(policy));
}
this.headerWriters.add(headersWriter.getBeanDefinition());
}
private void parseFeaturePolicyElement(Element element, ParserContext context) {
Element featurePolicyElement = (element != null)
? DomUtils.getChildElementByTagName(element, FEATURE_POLICY_ELEMENT) : null;
if (featurePolicyElement != null) {
addFeaturePolicy(featurePolicyElement, context);
}
}
private void addFeaturePolicy(Element featurePolicyElement, ParserContext context) {
BeanDefinitionBuilder headersWriter = BeanDefinitionBuilder
.genericBeanDefinition(FeaturePolicyHeaderWriter.class);
String policyDirectives = featurePolicyElement.getAttribute(ATT_POLICY_DIRECTIVES);
if (!StringUtils.hasText(policyDirectives)) {
context.getReaderContext()
.error(ATT_POLICY_DIRECTIVES + " requires a 'value' to be set.", featurePolicyElement);
}
else {
headersWriter.addConstructorArgValue(policyDirectives);
}
this.headerWriters.add(headersWriter.getBeanDefinition());
}
private void parsePermissionsPolicyElement(Element element, ParserContext context) {
Element permissionsPolicyElement = (element != null)
? DomUtils.getChildElementByTagName(element, PERMISSIONS_POLICY_ELEMENT) : null;
if (permissionsPolicyElement != null) {
addPermissionsPolicy(permissionsPolicyElement, context);
}
}
private void addPermissionsPolicy(Element permissionsPolicyElement, ParserContext context) {
BeanDefinitionBuilder headersWriter = BeanDefinitionBuilder
.genericBeanDefinition(PermissionsPolicyHeaderWriter.class);
String policyDirectives = permissionsPolicyElement.getAttribute(ATT_POLICY);
if (!StringUtils.hasText(policyDirectives)) {
context.getReaderContext().error(ATT_POLICY + " requires a 'value' to be set.", permissionsPolicyElement);
}
else {
headersWriter.addConstructorArgValue(policyDirectives);
}
this.headerWriters.add(headersWriter.getBeanDefinition());
}
private void parseCrossOriginOpenerPolicy(boolean elementDisabled, Element element) {
if (elementDisabled || element == null) {
return;
}
CrossOriginOpenerPolicyHeaderWriter writer = new CrossOriginOpenerPolicyHeaderWriter();
Element crossOriginOpenerPolicyElement = DomUtils.getChildElementByTagName(element,
CROSS_ORIGIN_OPENER_POLICY_ELEMENT);
if (crossOriginOpenerPolicyElement != null) {
addCrossOriginOpenerPolicy(crossOriginOpenerPolicyElement, writer);
}
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(CrossOriginOpenerPolicyHeaderWriter.class, () -> writer);
this.headerWriters.add(builder.getBeanDefinition());
}
private void parseCrossOriginEmbedderPolicy(boolean elementDisabled, Element element) {
if (elementDisabled || element == null) {
return;
}
CrossOriginEmbedderPolicyHeaderWriter writer = new CrossOriginEmbedderPolicyHeaderWriter();
Element crossOriginEmbedderPolicyElement = DomUtils.getChildElementByTagName(element,
CROSS_ORIGIN_EMBEDDER_POLICY_ELEMENT);
if (crossOriginEmbedderPolicyElement != null) {
addCrossOriginEmbedderPolicy(crossOriginEmbedderPolicyElement, writer);
}
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(CrossOriginEmbedderPolicyHeaderWriter.class, () -> writer);
this.headerWriters.add(builder.getBeanDefinition());
}
private void parseCrossOriginResourcePolicy(boolean elementDisabled, Element element) {
if (elementDisabled || element == null) {
return;
}
CrossOriginResourcePolicyHeaderWriter writer = new CrossOriginResourcePolicyHeaderWriter();
Element crossOriginResourcePolicyElement = DomUtils.getChildElementByTagName(element,
CROSS_ORIGIN_RESOURCE_POLICY_ELEMENT);
if (crossOriginResourcePolicyElement != null) {
addCrossOriginResourcePolicy(crossOriginResourcePolicyElement, writer);
}
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(CrossOriginResourcePolicyHeaderWriter.class, () -> writer);
this.headerWriters.add(builder.getBeanDefinition());
}
private void addCrossOriginResourcePolicy(Element crossOriginResourcePolicyElement,
CrossOriginResourcePolicyHeaderWriter writer) {
String policy = crossOriginResourcePolicyElement.getAttribute(ATT_POLICY);
if (StringUtils.hasText(policy)) {
writer.setPolicy(CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy.from(policy));
}
}
private void addCrossOriginEmbedderPolicy(Element crossOriginEmbedderPolicyElement,
CrossOriginEmbedderPolicyHeaderWriter writer) {
String policy = crossOriginEmbedderPolicyElement.getAttribute(ATT_POLICY);
if (StringUtils.hasText(policy)) {
writer.setPolicy(CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy.from(policy));
}
}
private void addCrossOriginOpenerPolicy(Element crossOriginOpenerPolicyElement,
CrossOriginOpenerPolicyHeaderWriter writer) {
String policy = crossOriginOpenerPolicyElement.getAttribute(ATT_POLICY);
if (StringUtils.hasText(policy)) {
writer.setPolicy(CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy.from(policy));
}
}
private void attrNotAllowed(ParserContext context, String attrName, String otherAttrName, Element element) {
context.getReaderContext()
.error("Only one of '" + attrName + "' or '" + otherAttrName + "' can be set.", element);
}
private void parseHeaderElements(Element element) {
List<Element> headerElts = (element != null)
? DomUtils.getChildElementsByTagName(element, GENERIC_HEADER_ELEMENT) : Collections.emptyList();
for (Element headerElt : headerElts) {
String headerFactoryRef = headerElt.getAttribute(ATT_REF);
if (StringUtils.hasText(headerFactoryRef)) {
this.headerWriters.add(new RuntimeBeanReference(headerFactoryRef));
}
else {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(StaticHeadersWriter.class);
builder.addConstructorArgValue(headerElt.getAttribute(ATT_NAME));
builder.addConstructorArgValue(headerElt.getAttribute(ATT_VALUE));
this.headerWriters.add(builder.getBeanDefinition());
}
}
}
private void parseContentTypeOptionsElement(boolean addIfNotPresent, Element element) {
Element contentTypeElt = (element != null) ? DomUtils.getChildElementByTagName(element, CONTENT_TYPE_ELEMENT)
: null;
boolean disabled = "true".equals(getAttribute(contentTypeElt, ATT_DISABLED, "false"));
if (disabled) {
return;
}
if (addIfNotPresent || contentTypeElt != null) {
addContentTypeOptions();
}
}
private void addContentTypeOptions() {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(XContentTypeOptionsHeaderWriter.class);
this.headerWriters.add(builder.getBeanDefinition());
}
private void parseFrameOptionsElement(boolean addIfNotPresent, Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(XFrameOptionsHeaderWriter.class);
Element frameElement = (element != null) ? DomUtils.getChildElementByTagName(element, FRAME_OPTIONS_ELEMENT)
: null;
if (frameElement == null) {
if (addIfNotPresent) {
this.headerWriters.add(builder.getBeanDefinition());
}
return;
}
String header = getAttribute(frameElement, ATT_POLICY, null);
boolean disabled = "true".equals(getAttribute(frameElement, ATT_DISABLED, "false"));
if (disabled && header != null) {
this.attrNotAllowed(parserContext, ATT_DISABLED, ATT_POLICY, frameElement);
}
header = StringUtils.hasText(header) ? header : "DENY";
if (ALLOW_FROM.equals(header)) {
parseAllowFromFrameOptionsElement(parserContext, builder, frameElement);
}
else {
builder.addConstructorArgValue(header);
}
if (!disabled) {
this.headerWriters.add(builder.getBeanDefinition());
}
}
private void parseAllowFromFrameOptionsElement(ParserContext parserContext, BeanDefinitionBuilder builder,
Element frameElement) {
String strategyRef = getAttribute(frameElement, ATT_REF, null);
String strategy = getAttribute(frameElement, ATT_STRATEGY, null);
if (StringUtils.hasText(strategy) && StringUtils.hasText(strategyRef)) {
parserContext.getReaderContext()
.error("Only one of 'strategy' or 'strategy-ref' can be set.", frameElement);
return;
}
if (strategyRef != null) {
builder.addConstructorArgReference(strategyRef);
return;
}
if (strategy == null) {
parserContext.getReaderContext().error("One of 'strategy' and 'strategy-ref' must be set.", frameElement);
return;
}
String value = getAttribute(frameElement, ATT_VALUE, null);
if (!StringUtils.hasText(value)) {
parserContext.getReaderContext().error("Strategy requires a 'value' to be set.", frameElement);
return;
}
// static, whitelist, regexp
if ("static".equals(strategy)) {
try {
builder.addConstructorArgValue(new StaticAllowFromStrategy(new URI(value)));
}
catch (URISyntaxException ex) {
parserContext.getReaderContext()
.error("'value' attribute doesn't represent a valid URI.", frameElement, ex);
}
return;
}
BeanDefinitionBuilder allowFromStrategy = getAllowFromStrategy(strategy, value);
String fromParameter = getAttribute(frameElement, ATT_FROM_PARAMETER, "from");
allowFromStrategy.addPropertyValue("allowFromParameterName", fromParameter);
builder.addConstructorArgValue(allowFromStrategy.getBeanDefinition());
}
private BeanDefinitionBuilder getAllowFromStrategy(String strategy, String value) {
if ("whitelist".equals(strategy)) {
BeanDefinitionBuilder allowFromStrategy = BeanDefinitionBuilder
.rootBeanDefinition(WhiteListedAllowFromStrategy.class);
allowFromStrategy.addConstructorArgValue(StringUtils.commaDelimitedListToSet(value));
return allowFromStrategy;
}
BeanDefinitionBuilder allowFromStrategy;
allowFromStrategy = BeanDefinitionBuilder.rootBeanDefinition(RegExpAllowFromStrategy.class);
allowFromStrategy.addConstructorArgValue(value);
return allowFromStrategy;
}
private void parseXssElement(boolean addIfNotPresent, Element element, ParserContext parserContext) {
Element xssElt = (element != null) ? DomUtils.getChildElementByTagName(element, XSS_ELEMENT) : null;
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(XXssProtectionHeaderWriter.class);
if (xssElt != null) {
boolean disabled = "true".equals(getAttribute(xssElt, ATT_DISABLED, "false"));
XXssProtectionHeaderWriter.HeaderValue headerValue = XXssProtectionHeaderWriter.HeaderValue
.from(xssElt.getAttribute(ATT_HEADER_VALUE));
if (headerValue != null) {
if (disabled) {
attrNotAllowed(parserContext, ATT_HEADER_VALUE, ATT_DISABLED, xssElt);
}
builder.addPropertyValue("headerValue", headerValue);
}
if (disabled) {
return;
}
}
if (addIfNotPresent || xssElt != null) {
this.headerWriters.add(builder.getBeanDefinition());
}
}
private String getAttribute(Element element, String name, String defaultValue) {
if (element == null) {
return defaultValue;
}
String value = element.getAttribute(name);
if (StringUtils.hasText(value)) {
return value;
}
return defaultValue;
}
}