SEC-2230: Add Header JavaConfig
Added JavaConfig for Headers. In the process, more HeaderWriter instances were added so that we can reuse logic between the XML and JavaConfig. This also prompted repackaging the writers.
This commit is contained in:
@@ -36,6 +36,7 @@ import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFi
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.www.DigestAuthenticationFilter;
|
||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
|
||||
import org.springframework.security.web.header.HeaderWriterFilter;
|
||||
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
|
||||
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
||||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
||||
@@ -63,6 +64,8 @@ final class FilterComparator implements Comparator<Filter>, Serializable {
|
||||
order += STEP;
|
||||
put(SecurityContextPersistenceFilter.class, order);
|
||||
order += STEP;
|
||||
put(HeaderWriterFilter.class, order);
|
||||
order += STEP;
|
||||
put(LogoutFilter.class, order);
|
||||
order += STEP;
|
||||
put(X509AuthenticationFilter.class, order);
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.springframework.security.config.annotation.web.configurers.ChannelSec
|
||||
import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.HttpBasicConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.JeeConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
|
||||
@@ -239,6 +240,10 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
return getOrApply(new OpenIDLoginConfigurer<HttpSecurity>());
|
||||
}
|
||||
|
||||
public HeadersConfigurer<HttpSecurity> headers() throws Exception {
|
||||
return getOrApply(new HeadersConfigurer<HttpSecurity>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuring of Session Management.
|
||||
*
|
||||
|
||||
@@ -155,6 +155,7 @@ public abstract class WebSecurityConfigurerAdapter implements SecurityConfigurer
|
||||
if(!disableDefaults) {
|
||||
http
|
||||
.exceptionHandling().and()
|
||||
.headers().and()
|
||||
.sessionManagement().and()
|
||||
.securityContext().and()
|
||||
.requestCache().and()
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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
|
||||
*
|
||||
* http://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.annotation.web.configurers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.header.HeaderWriter;
|
||||
import org.springframework.security.web.header.HeaderWriterFilter;
|
||||
import org.springframework.security.web.header.writers.CacheControlHeadersWriter;
|
||||
import org.springframework.security.web.header.writers.HstsHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.XContentTypeOptionsHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.XXssProtectionHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
* @see RememberMeConfigurer
|
||||
*/
|
||||
public final class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<H> {
|
||||
private List<HeaderWriter> headerWriters = new ArrayList<HeaderWriter>();
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#headers()
|
||||
*/
|
||||
public HeadersConfigurer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link HeaderWriter} instance
|
||||
* @param headerWriter the {@link HeaderWriter} instance to add
|
||||
* @return the {@link HeadersConfigurer} for additional customizations
|
||||
*/
|
||||
public HeadersConfigurer<H> addHeaderWriter(HeaderWriter headerWriter) {
|
||||
Assert.notNull(headerWriter, "headerWriter cannot be null");
|
||||
this.headerWriters.add(headerWriter);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H http) throws Exception {
|
||||
HeaderWriterFilter headersFilter = createHeaderWriterFilter();
|
||||
http.addFilter(headersFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link HeaderWriter}
|
||||
* @return the {@link HeaderWriter}
|
||||
*/
|
||||
private HeaderWriterFilter createHeaderWriterFilter() {
|
||||
HeaderWriterFilter headersFilter = new HeaderWriterFilter(getHeaderWriters());
|
||||
headersFilter = postProcess(headersFilter);
|
||||
return headersFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link HeaderWriter} instances and possibly initializes with the defaults.
|
||||
* @return
|
||||
*/
|
||||
private List<HeaderWriter> getHeaderWriters() {
|
||||
if(headerWriters.isEmpty()) {
|
||||
addDefaultHeaderWriters();
|
||||
}
|
||||
return headerWriters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitly adds the default {@link HeaderWriter} instances. If no,
|
||||
* {@link HeaderWriter} instances have been added this is automatically
|
||||
* invoked.
|
||||
*
|
||||
*/
|
||||
private void addDefaultHeaderWriters() {
|
||||
headerWriters.add(new XContentTypeOptionsHeaderWriter());
|
||||
headerWriters.add(new XXssProtectionHeaderWriter());
|
||||
headerWriters.add(new CacheControlHeadersWriter());
|
||||
headerWriters.add(new HstsHeaderWriter());
|
||||
headerWriters.add(new XFrameOptionsHeaderWriter());
|
||||
}
|
||||
}
|
||||
@@ -27,15 +27,17 @@ 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.headers.Header;
|
||||
import org.springframework.security.web.headers.HeadersFilter;
|
||||
import org.springframework.security.web.headers.HstsHeaderWriter;
|
||||
import org.springframework.security.web.headers.StaticHeadersWriter;
|
||||
import org.springframework.security.web.headers.frameoptions.AbstractRequestParameterAllowFromStrategy;
|
||||
import org.springframework.security.web.headers.frameoptions.RegExpAllowFromStrategy;
|
||||
import org.springframework.security.web.headers.frameoptions.StaticAllowFromStrategy;
|
||||
import org.springframework.security.web.headers.frameoptions.WhiteListedAllowFromStrategy;
|
||||
import org.springframework.security.web.headers.frameoptions.XFrameOptionsHeaderWriter;
|
||||
import org.springframework.security.web.header.HeaderWriterFilter;
|
||||
import org.springframework.security.web.header.writers.CacheControlHeadersWriter;
|
||||
import org.springframework.security.web.header.writers.HstsHeaderWriter;
|
||||
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.AbstractRequestParameterAllowFromStrategy;
|
||||
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;
|
||||
import org.w3c.dom.Element;
|
||||
@@ -72,16 +74,13 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private static final String FRAME_OPTIONS_ELEMENT = "frame-options";
|
||||
private static final String GENERIC_HEADER_ELEMENT = "header";
|
||||
|
||||
private static final String XSS_PROTECTION_HEADER = "X-XSS-Protection";
|
||||
private static final String CONTENT_TYPE_OPTIONS_HEADER = "X-Content-Type-Options";
|
||||
|
||||
private static final String ALLOW_FROM = "ALLOW-FROM";
|
||||
|
||||
private ManagedList<BeanMetadataElement> headerWriters;
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
headerWriters = new ManagedList<BeanMetadataElement>();
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(HeadersFilter.class);
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(HeaderWriterFilter.class);
|
||||
|
||||
parseCacheControlElement(element);
|
||||
parseHstsElement(element);
|
||||
@@ -100,9 +99,7 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||
frameOptions.addConstructorArgValue("DENY");
|
||||
headerWriters.add(frameOptions.getBeanDefinition());
|
||||
|
||||
BeanDefinitionBuilder xss = BeanDefinitionBuilder.genericBeanDefinition(StaticHeadersWriter.class);
|
||||
xss.addConstructorArgValue(XSS_PROTECTION_HEADER);
|
||||
xss.addConstructorArgValue("1; mode=block");
|
||||
BeanDefinitionBuilder xss = BeanDefinitionBuilder.genericBeanDefinition(XXssProtectionHeaderWriter.class);
|
||||
headerWriters.add(xss.getBeanDefinition());
|
||||
}
|
||||
builder.addConstructorArgValue(headerWriters);
|
||||
@@ -117,28 +114,7 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
|
||||
private void addCacheControl() {
|
||||
ManagedList<BeanDefinition> headers = new ManagedList<BeanDefinition>();
|
||||
|
||||
BeanDefinitionBuilder pragmaHeader = BeanDefinitionBuilder.genericBeanDefinition(Header.class);
|
||||
pragmaHeader.addConstructorArgValue("Pragma");
|
||||
ManagedList<String> pragmaValues = new ManagedList<String>();
|
||||
pragmaValues.add("no-cache");
|
||||
pragmaHeader.addConstructorArgValue(pragmaValues);
|
||||
headers.add(pragmaHeader.getBeanDefinition());
|
||||
|
||||
BeanDefinitionBuilder cacheControlHeader = BeanDefinitionBuilder.genericBeanDefinition(Header.class);
|
||||
cacheControlHeader.addConstructorArgValue("Cache-Control");
|
||||
ManagedList<String> cacheControlValues = new ManagedList<String>();
|
||||
cacheControlValues.add("no-cache");
|
||||
cacheControlValues.add("no-store");
|
||||
cacheControlValues.add("max-age=0");
|
||||
cacheControlValues.add("must-revalidate");
|
||||
cacheControlHeader.addConstructorArgValue(cacheControlValues);
|
||||
headers.add(cacheControlHeader.getBeanDefinition());
|
||||
|
||||
BeanDefinitionBuilder headersWriter = BeanDefinitionBuilder.genericBeanDefinition(StaticHeadersWriter.class);
|
||||
headersWriter.addConstructorArgValue(headers);
|
||||
|
||||
BeanDefinitionBuilder headersWriter = BeanDefinitionBuilder.genericBeanDefinition(CacheControlHeadersWriter.class);
|
||||
headerWriters.add(headersWriter.getBeanDefinition());
|
||||
}
|
||||
|
||||
@@ -191,9 +167,7 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
|
||||
private void addContentTypeOptions() {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(StaticHeadersWriter.class);
|
||||
builder.addConstructorArgValue(CONTENT_TYPE_OPTIONS_HEADER);
|
||||
builder.addConstructorArgValue("nosniff");
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(XContentTypeOptionsHeaderWriter.class);
|
||||
headerWriters.add(builder.getBeanDefinition());
|
||||
}
|
||||
|
||||
@@ -256,18 +230,16 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private void parseXssElement(Element element, ParserContext parserContext) {
|
||||
Element xssElt = DomUtils.getChildElementByTagName(element, XSS_ELEMENT);
|
||||
if (xssElt != null) {
|
||||
boolean enabled = Boolean.valueOf(getAttribute(xssElt, ATT_ENABLED, "true"));
|
||||
boolean block = Boolean.valueOf(getAttribute(xssElt, ATT_BLOCK, enabled ? "true" : "false"));
|
||||
String enabled = xssElt.getAttribute(ATT_ENABLED);
|
||||
String block = xssElt.getAttribute(ATT_BLOCK);
|
||||
|
||||
String value = enabled ? "1" : "0";
|
||||
if (enabled && block) {
|
||||
value += "; mode=block";
|
||||
} else if (!enabled && block) {
|
||||
parserContext.getReaderContext().error("<xss-protection enabled=\"false\"/> does not allow block=\"true\".", xssElt);
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(XXssProtectionHeaderWriter.class);
|
||||
if(StringUtils.hasText(enabled)) {
|
||||
builder.addPropertyValue("enabled", enabled);
|
||||
}
|
||||
if(StringUtils.hasText(block)) {
|
||||
builder.addPropertyValue("block", block);
|
||||
}
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(StaticHeadersWriter.class);
|
||||
builder.addConstructorArgValue(XSS_PROTECTION_HEADER);
|
||||
builder.addConstructorArgValue(value);
|
||||
headerWriters.add(builder.getBeanDefinition());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user