mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-05-30 16:52:13 +00:00
SEC-2230: Added Cache Control support
This commit is contained in:
parent
7b164bb5e1
commit
8013cd54d6
@ -15,24 +15,29 @@
|
||||
*/
|
||||
package org.springframework.security.config.http;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
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.headers.Header;
|
||||
import org.springframework.security.web.headers.HeadersFilter;
|
||||
import org.springframework.security.web.headers.StaticHeadersWriter;
|
||||
import org.springframework.security.web.headers.frameoptions.*;
|
||||
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.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
/**
|
||||
* Parser for the {@code HeadersFilter}.
|
||||
*
|
||||
@ -52,6 +57,8 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private static final String ATT_VALUE = "value";
|
||||
private static final String ATT_REF = "ref";
|
||||
|
||||
private static final String CACHE_CONTROL_ELEMENT = "cache-control";
|
||||
|
||||
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";
|
||||
@ -68,6 +75,7 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||
headerWriters = new ManagedList();
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(HeadersFilter.class);
|
||||
|
||||
parseCacheControlElement(element);
|
||||
parseXssElement(element, parserContext);
|
||||
parseFrameOptionsElement(element, parserContext);
|
||||
parseContentTypeOptionsElement(element);
|
||||
@ -82,6 +90,35 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
private void parseCacheControlElement(Element element) {
|
||||
Element cacheControlElement = DomUtils.getChildElementByTagName(element, CACHE_CONTROL_ELEMENT);
|
||||
if (cacheControlElement != null) {
|
||||
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);
|
||||
|
||||
headerWriters.add(headersWriter.getBeanDefinition());
|
||||
}
|
||||
}
|
||||
|
||||
private void parseHeaderElements(Element element) {
|
||||
List<Element> headerElts = DomUtils.getChildElementsByTagName(element, GENERIC_HEADER_ELEMENT);
|
||||
for (Element headerElt : headerElts) {
|
||||
|
@ -720,51 +720,55 @@ jdbc-user-service.attlist &=
|
||||
|
||||
headers =
|
||||
## Element for configuration of the AddHeadersFilter. Enables easy setting for the X-Frame-Options, X-XSS-Protection and X-Content-Type-Options headers.
|
||||
element headers {xss-protection? & frame-options? & content-type-options? & header*}
|
||||
element headers {cache-control? & xss-protection? & frame-options? & content-type-options? & header*}
|
||||
|
||||
cache-control =
|
||||
## Adds Cache-Control no-cache, no-store, must-revalidate and Pragma no-cache every URL
|
||||
element cache-control {empty}
|
||||
|
||||
frame-options =
|
||||
## Enable basic clickjacking support for newer browsers (IE8+), will set the X-Frame-Options header.
|
||||
element frame-options {frame-options.attlist,empty}
|
||||
## Enable basic clickjacking support for newer browsers (IE8+), will set the X-Frame-Options header.
|
||||
element frame-options {frame-options.attlist,empty}
|
||||
frame-options.attlist &=
|
||||
## Specify the policy to use for the X-Frame-Options-Header.
|
||||
attribute policy {"DENY","SAMEORIGIN","ALLOW-FROM"}?
|
||||
## Specify the policy to use for the X-Frame-Options-Header.
|
||||
attribute policy {"DENY","SAMEORIGIN","ALLOW-FROM"}?
|
||||
frame-options.attlist &=
|
||||
## Specify the strategy to use when ALLOW-FROM is chosen.
|
||||
attribute strategy {"static","whitelist","regexp"}?
|
||||
## Specify the strategy to use when ALLOW-FROM is chosen.
|
||||
attribute strategy {"static","whitelist","regexp"}?
|
||||
frame-options.attlist &=
|
||||
## Specify the a reference to the custom AllowFromStrategy to use when ALLOW-FROM is chosen.
|
||||
ref?
|
||||
## Specify the a reference to the custom AllowFromStrategy to use when ALLOW-FROM is chosen.
|
||||
ref?
|
||||
frame-options.attlist &=
|
||||
## Specify the a value to use for the chosen strategy.
|
||||
attribute value {xsd:string}?
|
||||
## Specify the a value to use for the chosen strategy.
|
||||
attribute value {xsd:string}?
|
||||
frame-options.attlist &=
|
||||
## Specify the request parameter to use for the origin when using a 'whitelist' or 'regexp' based strategy. Default is 'from'.
|
||||
attribute from-parameter {xsd:string}?
|
||||
## Specify the request parameter to use for the origin when using a 'whitelist' or 'regexp' based strategy. Default is 'from'.
|
||||
attribute from-parameter {xsd:string}?
|
||||
|
||||
|
||||
xss-protection =
|
||||
## Enable basic XSS browser protection, supported by newer browsers (IE8+), will set the X-XSS-Protection header.
|
||||
element xss-protection {xss-protection.attlist,empty}
|
||||
## Enable basic XSS browser protection, supported by newer browsers (IE8+), will set the X-XSS-Protection header.
|
||||
element xss-protection {xss-protection.attlist,empty}
|
||||
xss-protection.attlist &=
|
||||
## enable or disable the X-XSS-Protection header. Default is 'true' meaning it is enabled.
|
||||
attribute enabled {xsd:boolean}?
|
||||
## enable or disable the X-XSS-Protection header. Default is 'true' meaning it is enabled.
|
||||
attribute enabled {xsd:boolean}?
|
||||
xss-protection.attlist &=
|
||||
## Add mode=block to the header or not, default is on.
|
||||
attribute block {xsd:boolean}?
|
||||
## Add mode=block to the header or not, default is on.
|
||||
attribute block {xsd:boolean}?
|
||||
|
||||
content-type-options =
|
||||
## Add a X-Content-Type-Options header to the resopnse. Value is always 'nosniff'.
|
||||
element content-type-options {empty}
|
||||
## Add a X-Content-Type-Options header to the resopnse. Value is always 'nosniff'.
|
||||
element content-type-options {empty}
|
||||
|
||||
header=
|
||||
## Add additional headers to the response.
|
||||
element header {header.attlist}
|
||||
## Add additional headers to the response.
|
||||
element header {header.attlist}
|
||||
header.attlist &=
|
||||
## The name of the header to add.
|
||||
attribute name {xsd:token}?
|
||||
## The name of the header to add.
|
||||
attribute name {xsd:token}?
|
||||
header.attlist &=
|
||||
## The value for the header.
|
||||
attribute value {xsd:token}?
|
||||
## The value for the header.
|
||||
attribute value {xsd:token}?
|
||||
header.attlist &=
|
||||
## Reference to a custom HeaderFactory implementation.
|
||||
ref?
|
||||
|
@ -2240,6 +2240,7 @@
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="security:cache-control"/>
|
||||
<xs:element ref="security:xss-protection"/>
|
||||
<xs:element ref="security:frame-options"/>
|
||||
<xs:element ref="security:content-type-options"/>
|
||||
@ -2247,6 +2248,13 @@
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="cache-control">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Adds Cache-Control no-cache, no-store, must-revalidate and Pragma no-cache every URL
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType/>
|
||||
</xs:element>
|
||||
<xs:element name="frame-options">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Enable basic clickjacking support for newer browsers (IE8+), will set the X-Frame-Options
|
||||
|
@ -28,6 +28,7 @@ import org.springframework.security.openid.OpenIDAuthenticationFilter
|
||||
import org.springframework.security.openid.OpenIDAuthenticationToken
|
||||
import org.springframework.security.openid.OpenIDConsumer
|
||||
import org.springframework.security.openid.OpenIDConsumerException
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter
|
||||
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter
|
||||
@ -324,10 +325,26 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
|
||||
e.message.contains '<xss-protection enabled="false"/> does not allow block="true".'
|
||||
}
|
||||
|
||||
def 'http headers cache-control'() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'headers'() {
|
||||
'cache-control'()
|
||||
}
|
||||
}
|
||||
createAppContext()
|
||||
def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
|
||||
then:
|
||||
assertHeaders(response, ['Cache-Control': 'no-cache,no-store,max-age=0,must-revalidate','Pragma':'no-cache'])
|
||||
}
|
||||
|
||||
def assertHeaders(MockHttpServletResponse response, Map<String,String> expected) {
|
||||
assert response.headerNames == expected.keySet()
|
||||
expected.each { headerName, value ->
|
||||
assert response.getHeaderValues(headerName) == [value]
|
||||
assert response.getHeaderValues(headerName) == value.split(',')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -264,6 +264,9 @@
|
||||
It enables easy configuration for several headers and also allows for setting custom headers through
|
||||
the <link xlink:href="#nsa-header">header</link> element.
|
||||
<itemizedlist>
|
||||
<listitem><literal>Cache-Control</literal> and <literal>Pragma</literal> - Can be set using the
|
||||
<link xlink:href="#nsa-cache-control">cache-control</link> element. This ensures that the
|
||||
browser does not cache your secured pages.</listitem>
|
||||
<listitem><literal>X-Frame-Options</literal> - Can be set using the
|
||||
<link xlink:href="#nsa-frame-options">frame-options</link> element. The
|
||||
<link xlink:href="http://en.wikipedia.org/wiki/Clickjacking#X-Frame-Options">X-Frame-Options
|
||||
@ -288,6 +291,7 @@
|
||||
<section xml:id="nsa-headers-children">
|
||||
<title>Child Elements of <literal><headers></literal></title>
|
||||
<itemizedlist>
|
||||
<listitem><link xlink:href="#nsa-cache-control">cache-control</link></listitem>
|
||||
<listitem><link xlink:href="#nsa-content-type-options">content-type-options</link></listitem>
|
||||
<listitem><link xlink:href="#nsa-frame-options">frame-options</link></listitem>
|
||||
<listitem><link xlink:href="#nsa-header">header</link></listitem>
|
||||
@ -295,6 +299,17 @@
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="nsa-cache-control">
|
||||
<title><literal><cache-control></literal></title>
|
||||
<para>Adds <literal>Cache-Control</literal> and <literal>Pragma</literal> headers to ensure that the
|
||||
browser does not cache your secured pages.</para>
|
||||
<section xml:id="nsa-cache-control-parents">
|
||||
<title>Parent Elements of <literal><cache-control></literal></title>
|
||||
<itemizedlist>
|
||||
<listitem><link xlink:href="#nsa-headers">headers</link></listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="nsa-frame-options">
|
||||
<title><literal><frame-options></literal></title>
|
||||
<para>When enabled adds the <link xlink:href="http://tools.ietf.org/html/draft-ietf-websec-x-frame-options-01">X-Frame-Options header</link> to the response, this allows newer browsers to do some security
|
||||
|
@ -617,6 +617,8 @@ List<OpenIDAttribute> attributes = token.getAttributes();</programlisting>The
|
||||
<progamlisting language="xml">
|
||||
<![CDATA[
|
||||
<headers>
|
||||
<!-- Add Cache-Control and Pragma headers -->
|
||||
<cache-control/>
|
||||
<!-- Adds X-XSS-Protection with value of 1 -->
|
||||
<xss-protection/>
|
||||
<!-- Add X-Frame-Options with a value of DENY -->
|
||||
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.web.headers;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.web.util.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Delegates to the provided {@link HeaderWriter} when
|
||||
* {@link RequestMatcher#matches(HttpServletRequest)} returns true.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public class DelegatingRequestMatcherHeaderWriter implements HeaderWriter {
|
||||
private final RequestMatcher requestMatcher;
|
||||
|
||||
private final HeaderWriter delegateHeaderWriter;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param requestMatcher
|
||||
* the {@link RequestMatcher} to use. If returns true, the
|
||||
* delegateHeaderWriter will be invoked.
|
||||
* @param delegateHeaderWriter
|
||||
* the {@link HeaderWriter} to invoke if the
|
||||
* {@link RequestMatcher} returns true.
|
||||
*/
|
||||
public DelegatingRequestMatcherHeaderWriter(RequestMatcher requestMatcher,
|
||||
HeaderWriter delegateHeaderWriter) {
|
||||
Assert.notNull(requestMatcher, "requestMatcher cannot be null");
|
||||
Assert.notNull(delegateHeaderWriter, "delegateHeaderWriter cannot be null");
|
||||
this.requestMatcher = requestMatcher;
|
||||
this.delegateHeaderWriter = delegateHeaderWriter;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.web.headers.HeaderWriter#writeHeaders(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
|
||||
*/
|
||||
@Override
|
||||
public void writeHeaders(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
if(requestMatcher.matches(request)) {
|
||||
delegateHeaderWriter.writeHeaders(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName()+ " [requestMatcher="
|
||||
+ requestMatcher + ", delegateHeaderWriter="
|
||||
+ delegateHeaderWriter + "]";
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* Represents a Header to be added to the {@link HttpServletResponse}
|
||||
*/
|
||||
final class Header {
|
||||
public final class Header {
|
||||
|
||||
private final String headerName;
|
||||
private final List<String> headerValues;
|
||||
|
@ -1,30 +1,52 @@
|
||||
package org.springframework.security.web.headers;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@code HeaderWriter} implementation which writes the same {@code Header} instance.
|
||||
*
|
||||
* @author Marten Deinum
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public class StaticHeadersWriter implements HeaderWriter {
|
||||
|
||||
private final Header header;
|
||||
private final List<Header> headers;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param headers the {@link Header} instances to use
|
||||
*/
|
||||
public StaticHeadersWriter(List<Header> headers) {
|
||||
Assert.notEmpty(headers,"headers cannot be null or empty");
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance with a single header
|
||||
* @param headerName the name of the header
|
||||
* @param headerValues the values for the header
|
||||
*/
|
||||
public StaticHeadersWriter(String headerName, String... headerValues) {
|
||||
header = new Header(headerName, headerValues);
|
||||
this(Collections.singletonList(new Header(headerName, headerValues)));
|
||||
}
|
||||
|
||||
public void writeHeaders(HttpServletRequest request, HttpServletResponse response) {
|
||||
for(String value : header.getValues()) {
|
||||
response.addHeader(header.getName(), value);
|
||||
for(Header header : headers) {
|
||||
for(String value : header.getValues()) {
|
||||
response.addHeader(header.getName(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + " [headers=" + headers + "]";
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.web.headers;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.web.util.RequestMatcher;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class DelegatingRequestMatcherHeaderWriterTests {
|
||||
@Mock
|
||||
private RequestMatcher matcher;
|
||||
|
||||
@Mock
|
||||
private HeaderWriter delegate;
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
|
||||
private MockHttpServletResponse response;
|
||||
|
||||
private DelegatingRequestMatcherHeaderWriter headerWriter;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
headerWriter = new DelegatingRequestMatcherHeaderWriter(matcher, delegate);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorNullRequestMatcher() {
|
||||
new DelegatingRequestMatcherHeaderWriter(null, delegate);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorNullDelegate() {
|
||||
new DelegatingRequestMatcherHeaderWriter(matcher, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeHeadersOnMatch() {
|
||||
when(matcher.matches(request)).thenReturn(true);
|
||||
|
||||
headerWriter.writeHeaders(request, response);
|
||||
|
||||
verify(delegate).writeHeaders(request, response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeHeadersOnNoMatch() {
|
||||
when(matcher.matches(request)).thenReturn(false);
|
||||
|
||||
headerWriter.writeHeaders(request, response);
|
||||
|
||||
verify(delegate, times(0)).writeHeaders(request, response);
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ package org.springframework.security.web.headers;
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -41,6 +42,16 @@ public class StaticHeaderWriterTests {
|
||||
response = new MockHttpServletResponse();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorNullHeaders() {
|
||||
new StaticHeadersWriter(null);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorEmptyHeaders() {
|
||||
new StaticHeadersWriter(Collections.<Header>emptyList());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorNullHeaderName() {
|
||||
new StaticHeadersWriter(null, "value1");
|
||||
@ -65,4 +76,17 @@ public class StaticHeaderWriterTests {
|
||||
factory.writeHeaders(request, response);
|
||||
assertThat(response.getHeaderValues(headerName)).isEqualTo(Arrays.asList(headerValue));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeHeadersMulti() {
|
||||
Header pragma = new Header("Pragma","no-cache");
|
||||
Header cacheControl= new Header("Cache-Control","no-cache","no-store","must-revalidate");
|
||||
StaticHeadersWriter factory = new StaticHeadersWriter(Arrays.asList(pragma, cacheControl));
|
||||
|
||||
factory.writeHeaders(request, response);
|
||||
|
||||
assertThat(response.getHeaderNames().size()).isEqualTo(2);
|
||||
assertThat(response.getHeaderValues(pragma.getName())).isEqualTo(pragma.getValues());
|
||||
assertThat(response.getHeaderValues(cacheControl.getName())).isEqualTo(cacheControl.getValues());
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user