Add CorsFilter support
This commit is contained in:
parent
c935d857eb
commit
13bc70f693
|
@ -68,6 +68,7 @@ public abstract class Elements {
|
|||
public static final String DEBUG = "debug";
|
||||
public static final String HTTP_FIREWALL = "http-firewall";
|
||||
public static final String HEADERS = "headers";
|
||||
public static final String CORS = "cors";
|
||||
public static final String CSRF = "csrf";
|
||||
|
||||
public static final String WEBSOCKET_MESSAGE_BROKER = "websocket-message-broker";
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
|||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.security.web.session.ConcurrentSessionFilter;
|
||||
import org.springframework.security.web.session.SessionManagementFilter;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
/**
|
||||
* An internal use only {@link Comparator} that sorts the Security {@link Filter}
|
||||
|
@ -70,6 +71,8 @@ final class FilterComparator implements Comparator<Filter>, Serializable {
|
|||
order += STEP;
|
||||
put(HeaderWriterFilter.class, order);
|
||||
order += STEP;
|
||||
put(CorsFilter.class, order);
|
||||
order += STEP;
|
||||
put(CsrfFilter.class, order);
|
||||
order += STEP;
|
||||
put(LogoutFilter.class, order);
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
|
|||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.configurers.AnonymousConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.ChannelSecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.CorsConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
|
||||
|
@ -69,6 +70,9 @@ import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
|||
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
/**
|
||||
* A {@link HttpSecurity} is similar to Spring Security's XML <http> element in the
|
||||
|
@ -317,6 +321,19 @@ public final class HttpSecurity extends
|
|||
return getOrApply(new HeadersConfigurer<HttpSecurity>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link CorsFilter} to be used. If a bean by the name of corsFilter is
|
||||
* provided, that {@link CorsFilter} is used. Else if corsConfigurationSource is
|
||||
* defined, then that {@link CorsConfiguration} is used. Otherwise, if Spring MVC is
|
||||
* on the classpath a {@link HandlerMappingIntrospector} is used.
|
||||
*
|
||||
* @return the {@link CorsConfigurer} for customizations
|
||||
* @throws Exception
|
||||
*/
|
||||
public CorsConfigurer<HttpSecurity> cors() throws Exception {
|
||||
return getOrApply(new CorsConfigurer<HttpSecurity>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuring of Session Management.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright 2002-2016 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 org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
/**
|
||||
* Adds {@link CorsFilter} to the Spring Security filter chain. If a bean by the name of
|
||||
* corsFilter is provided, that {@link CorsFilter} is used. Else if
|
||||
* corsConfigurationSource is defined, then that {@link CorsConfiguration} is used.
|
||||
* Otherwise, if Spring MVC is on the classpath a {@link HandlerMappingIntrospector} is
|
||||
* used.
|
||||
*
|
||||
* @param <H> the builder to return.
|
||||
* @author Rob Winch
|
||||
* @since 4.1.1
|
||||
*/
|
||||
public class CorsConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
extends AbstractHttpConfigurer<CorsConfigurer<H>, H> {
|
||||
|
||||
private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";
|
||||
private static final String CORS_CONFIGURATION_SOURCE_BEAN_NAME = "corsConfigurationSource";
|
||||
private static final String CORS_FILTER_BEAN_NAME = "corsFilter";
|
||||
|
||||
private CorsConfigurationSource configurationSource;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @see HttpSecurity#cors()
|
||||
*/
|
||||
public CorsConfigurer() {
|
||||
}
|
||||
|
||||
public CorsConfigurer<H> configurationSource(
|
||||
CorsConfigurationSource configurationSource) {
|
||||
this.configurationSource = configurationSource;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H http) throws Exception {
|
||||
ApplicationContext context = http.getSharedObject(ApplicationContext.class);
|
||||
|
||||
CorsFilter corsFilter = getCorsFilter(context);
|
||||
if (corsFilter == null) {
|
||||
throw new IllegalStateException(
|
||||
"Please configure either a " + CORS_FILTER_BEAN_NAME + " bean or a "
|
||||
+ CORS_CONFIGURATION_SOURCE_BEAN_NAME + "bean.");
|
||||
}
|
||||
http.addFilter(corsFilter);
|
||||
}
|
||||
|
||||
private CorsFilter getCorsFilter(ApplicationContext context) {
|
||||
if (this.configurationSource != null) {
|
||||
return new CorsFilter(this.configurationSource);
|
||||
}
|
||||
|
||||
boolean containsCorsFilter = context
|
||||
.containsBeanDefinition(CORS_FILTER_BEAN_NAME);
|
||||
if (containsCorsFilter) {
|
||||
return context.getBean(CORS_FILTER_BEAN_NAME, CorsFilter.class);
|
||||
}
|
||||
|
||||
boolean containsCorsSource = context
|
||||
.containsBean(CORS_CONFIGURATION_SOURCE_BEAN_NAME);
|
||||
if (containsCorsSource) {
|
||||
CorsConfigurationSource configurationSource = context.getBean(
|
||||
CORS_CONFIGURATION_SOURCE_BEAN_NAME, CorsConfigurationSource.class);
|
||||
return new CorsFilter(configurationSource);
|
||||
}
|
||||
|
||||
boolean mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR,
|
||||
context.getClassLoader());
|
||||
if (mvcPresent) {
|
||||
return MvcCorsFilter.getMvcCorsFilter(context);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static class MvcCorsFilter {
|
||||
/**
|
||||
* This needs to be isolated into a separate class as Spring MVC is an optional
|
||||
* dependency and will potentially cause ClassLoading issues
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
private static CorsFilter getMvcCorsFilter(ApplicationContext context) {
|
||||
HandlerMappingIntrospector mappingIntrospector = new HandlerMappingIntrospector(
|
||||
context);
|
||||
return new CorsFilter(mappingIntrospector);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright 2002-2016 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.http;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
/**
|
||||
* Parser for the {@code CorsFilter}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 4.1.1
|
||||
*/
|
||||
public class CorsBeanDefinitionParser {
|
||||
private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";
|
||||
|
||||
private static final String ATT_SOURCE = "configuration-source-ref";
|
||||
private static final String ATT_REF = "ref";
|
||||
|
||||
public BeanMetadataElement parse(Element element, ParserContext parserContext) {
|
||||
if(element == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String filterRef = element.getAttribute(ATT_REF);
|
||||
if(StringUtils.hasText(filterRef)) {
|
||||
return new RuntimeBeanReference(filterRef);
|
||||
}
|
||||
|
||||
BeanMetadataElement configurationSource = getSource(element, parserContext);
|
||||
if(configurationSource == null) {
|
||||
throw new BeanCreationException("Could not create CorsFilter");
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder filterBldr = BeanDefinitionBuilder.rootBeanDefinition(CorsFilter.class);
|
||||
filterBldr.addConstructorArgValue(configurationSource);
|
||||
return filterBldr.getBeanDefinition();
|
||||
}
|
||||
|
||||
public BeanMetadataElement getSource(Element element, ParserContext parserContext) {
|
||||
String configurationSourceRef = element.getAttribute(ATT_SOURCE);
|
||||
if (StringUtils.hasText(configurationSourceRef)) {
|
||||
return new RuntimeBeanReference(configurationSourceRef);
|
||||
}
|
||||
|
||||
boolean mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR,
|
||||
getClass().getClassLoader());
|
||||
if(!mvcPresent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder configurationSourceBldr = BeanDefinitionBuilder.rootBeanDefinition(HANDLER_MAPPING_INTROSPECTOR);
|
||||
configurationSourceBldr.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
|
||||
return configurationSourceBldr.getBeanDefinition();
|
||||
}
|
||||
}
|
|
@ -127,6 +127,7 @@ class HttpConfigurationBuilder {
|
|||
private BeanReference fsi;
|
||||
private BeanReference requestCache;
|
||||
private BeanDefinition addHeadersFilter;
|
||||
private BeanMetadataElement corsFilter;
|
||||
private BeanDefinition csrfFilter;
|
||||
private BeanMetadataElement csrfLogoutHandler;
|
||||
private BeanMetadataElement csrfAuthStrategy;
|
||||
|
@ -176,6 +177,7 @@ class HttpConfigurationBuilder {
|
|||
createChannelProcessingFilter();
|
||||
createFilterSecurityInterceptor(authenticationManager);
|
||||
createAddHeadersFilter();
|
||||
createCorsFilter();
|
||||
}
|
||||
|
||||
private SessionCreationPolicy createPolicy(String createSession) {
|
||||
|
@ -737,6 +739,11 @@ class HttpConfigurationBuilder {
|
|||
private void createAddHeadersFilter() {
|
||||
Element elmt = DomUtils.getChildElementByTagName(httpElt, Elements.HEADERS);
|
||||
this.addHeadersFilter = new HeadersBeanDefinitionParser().parse(elmt, pc);
|
||||
}
|
||||
|
||||
private void createCorsFilter() {
|
||||
Element elmt = DomUtils.getChildElementByTagName(this.httpElt, Elements.CORS);
|
||||
this.corsFilter = new CorsBeanDefinitionParser().parse(elmt, this.pc);
|
||||
|
||||
}
|
||||
|
||||
|
@ -808,6 +815,10 @@ class HttpConfigurationBuilder {
|
|||
filters.add(new OrderDecorator(requestCacheAwareFilter, REQUEST_CACHE_FILTER));
|
||||
}
|
||||
|
||||
if (this.corsFilter != null) {
|
||||
filters.add(new OrderDecorator(this.corsFilter, CORS_FILTER));
|
||||
}
|
||||
|
||||
if (addHeadersFilter != null) {
|
||||
filters.add(new OrderDecorator(addHeadersFilter, HEADERS_FILTER));
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.springframework.security.web.context.request.async.WebAsyncManagerInt
|
|||
enum SecurityFilters {
|
||||
FIRST(Integer.MIN_VALUE), CHANNEL_FILTER, SECURITY_CONTEXT_FILTER, CONCURRENT_SESSION_FILTER,
|
||||
/** {@link WebAsyncManagerIntegrationFilter} */
|
||||
WEB_ASYNC_MANAGER_FILTER, HEADERS_FILTER, CSRF_FILTER, LOGOUT_FILTER, X509_FILTER, PRE_AUTH_FILTER, CAS_FILTER, FORM_LOGIN_FILTER, OPENID_FILTER, LOGIN_PAGE_FILTER, DIGEST_AUTH_FILTER, BASIC_AUTH_FILTER, REQUEST_CACHE_FILTER, SERVLET_API_SUPPORT_FILTER, JAAS_API_SUPPORT_FILTER, REMEMBER_ME_FILTER, ANONYMOUS_FILTER, SESSION_MANAGEMENT_FILTER, EXCEPTION_TRANSLATION_FILTER, FILTER_SECURITY_INTERCEPTOR, SWITCH_USER_FILTER, LAST(
|
||||
WEB_ASYNC_MANAGER_FILTER, HEADERS_FILTER, CORS_FILTER, CSRF_FILTER, LOGOUT_FILTER, X509_FILTER, PRE_AUTH_FILTER, CAS_FILTER, FORM_LOGIN_FILTER, OPENID_FILTER, LOGIN_PAGE_FILTER, DIGEST_AUTH_FILTER, BASIC_AUTH_FILTER, REQUEST_CACHE_FILTER, SERVLET_API_SUPPORT_FILTER, JAAS_API_SUPPORT_FILTER, REMEMBER_ME_FILTER, ANONYMOUS_FILTER, SESSION_MANAGEMENT_FILTER, EXCEPTION_TRANSLATION_FILTER, FILTER_SECURITY_INTERCEPTOR, SWITCH_USER_FILTER, LAST(
|
||||
Integer.MAX_VALUE);
|
||||
|
||||
private static final int INTERVAL = 100;
|
||||
|
|
|
@ -303,7 +303,7 @@ http-firewall =
|
|||
|
||||
http =
|
||||
## Container element for HTTP security configuration. Multiple elements can now be defined, each with a specific pattern to which the enclosed security configuration applies. A pattern can also be configured to bypass Spring Security's filters completely by setting the "security" attribute to "none".
|
||||
element http {http.attlist, (intercept-url* & access-denied-handler? & form-login? & openid-login? & x509? & jee? & http-basic? & logout? & session-management & remember-me? & anonymous? & port-mappings & custom-filter* & request-cache? & expression-handler? & headers? & csrf?) }
|
||||
element http {http.attlist, (intercept-url* & access-denied-handler? & form-login? & openid-login? & x509? & jee? & http-basic? & logout? & session-management & remember-me? & anonymous? & port-mappings & custom-filter* & request-cache? & expression-handler? & headers? & csrf? & cors?) }
|
||||
http.attlist &=
|
||||
## The request URL pattern which will be mapped to the filter chain created by this <http> element. If omitted, the filter chain will match all requests.
|
||||
attribute pattern {xsd:token}?
|
||||
|
@ -771,12 +771,21 @@ hsts-options.attlist &=
|
|||
## The RequestMatcher instance to be used to determine if the header should be set. Default is if HttpServletRequest.isSecure() is true.
|
||||
attribute request-matcher-ref { xsd:token }?
|
||||
|
||||
cors =
|
||||
## Element for configuration of CorsFilter. If no CorsFilter or CorsConfigurationSource is specified a HandlerMappingIntrospector is used as the CorsConfigurationSource
|
||||
element cors { cors-options.attlist }
|
||||
cors-options.attlist &=
|
||||
ref?
|
||||
cors-options.attlist &=
|
||||
## Specifies a bean id that is a CorsConfigurationSource used to construct the CorsFilter to use
|
||||
attribute configuration-source-ref {xsd:token}?
|
||||
|
||||
hpkp =
|
||||
## Adds support for HTTP Public Key Pinning (HPKP).
|
||||
element hpkp {hpkp.pins,hpkp.attlist}
|
||||
hpkp.pins =
|
||||
## The list with pins
|
||||
element pins {hpkp.pin+}
|
||||
element pins {hpkp.pin+}
|
||||
hpkp.pin =
|
||||
## A pin is specified using the base64-encoded SPKI fingerprint as value and the cryptographic hash algorithm as attribute
|
||||
element pin {
|
||||
|
@ -895,4 +904,4 @@ position =
|
|||
## The explicit position at which the custom-filter should be placed in the chain. Use if you are replacing a standard filter.
|
||||
attribute position {named-security-filter}
|
||||
|
||||
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "SECURITY_CONTEXT_FILTER" | "CONCURRENT_SESSION_FILTER" | "WEB_ASYNC_MANAGER_FILTER" | "HEADERS_FILTER" | "CSRF_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" | "LOGIN_PAGE_FILTER" | "DIGEST_AUTH_FILTER" | "BASIC_AUTH_FILTER" | "REQUEST_CACHE_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "JAAS_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "SESSION_MANAGEMENT_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
|
||||
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "SECURITY_CONTEXT_FILTER" | "CONCURRENT_SESSION_FILTER" | "WEB_ASYNC_MANAGER_FILTER" | "HEADERS_FILTER" | "CORS_FILTER" | "CSRF_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" | "LOGIN_PAGE_FILTER" | "DIGEST_AUTH_FILTER" | "BASIC_AUTH_FILTER" | "REQUEST_CACHE_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "JAAS_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "SESSION_MANAGEMENT_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
|
||||
|
|
|
@ -1111,6 +1111,7 @@
|
|||
</xs:element>
|
||||
<xs:element ref="security:headers"/>
|
||||
<xs:element ref="security:csrf"/>
|
||||
<xs:element ref="security:cors"/>
|
||||
</xs:choice>
|
||||
<xs:attributeGroup ref="security:http.attlist"/>
|
||||
</xs:complexType>
|
||||
|
@ -2385,6 +2386,31 @@
|
|||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="cors">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Element for configuration of CorsFilter. If no CorsFilter or CorsConfigurationSource is
|
||||
specified a HandlerMappingIntrospector is used as the CorsConfigurationSource
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:cors-options.attlist"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:attributeGroup name="cors-options.attlist">
|
||||
<xs:attribute name="ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Defines a reference to a Spring bean Id.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="configuration-source-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Specifies a bean id that is a CorsConfigurationSource used to construct the CorsFilter to
|
||||
use
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="hpkp">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Adds support for HTTP Public Key Pinning (HPKP).
|
||||
|
@ -2716,6 +2742,7 @@
|
|||
<xs:enumeration value="CONCURRENT_SESSION_FILTER"/>
|
||||
<xs:enumeration value="WEB_ASYNC_MANAGER_FILTER"/>
|
||||
<xs:enumeration value="HEADERS_FILTER"/>
|
||||
<xs:enumeration value="CORS_FILTER"/>
|
||||
<xs:enumeration value="CSRF_FILTER"/>
|
||||
<xs:enumeration value="LOGOUT_FILTER"/>
|
||||
<xs:enumeration value="X509_FILTER"/>
|
||||
|
|
|
@ -17,20 +17,22 @@ package org.springframework.security.config.annotation;
|
|||
|
||||
import javax.servlet.Filter
|
||||
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Specification
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException
|
||||
import org.springframework.context.ConfigurableApplicationContext
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.mock.web.MockFilterChain
|
||||
import org.springframework.mock.web.MockHttpServletRequest
|
||||
import org.springframework.mock.web.MockHttpServletResponse
|
||||
import org.springframework.mock.web.MockServletContext
|
||||
import org.springframework.security.authentication.AuthenticationManager
|
||||
import org.springframework.security.authentication.AuthenticationProvider
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration
|
||||
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.authority.AuthorityUtils
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
|
@ -40,11 +42,9 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
|
|||
import org.springframework.security.web.context.HttpRequestResponseHolder
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
|
||||
import org.springframework.security.web.csrf.CsrfToken
|
||||
import org.springframework.security.web.csrf.DefaultCsrfToken;
|
||||
import org.springframework.security.web.csrf.DefaultCsrfToken
|
||||
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository
|
||||
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Specification
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -88,7 +88,10 @@ abstract class BaseSpringSpec extends Specification {
|
|||
}
|
||||
|
||||
def loadConfig(Class<?>... configs) {
|
||||
context = new AnnotationConfigApplicationContext(configs)
|
||||
context = new AnnotationConfigWebApplicationContext()
|
||||
context.register(configs)
|
||||
context.setServletContext(new MockServletContext())
|
||||
context.refresh()
|
||||
context
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* Copyright 2002-2016 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 javax.servlet.http.HttpServletResponse
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.http.*
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import org.springframework.web.cors.CorsConfiguration
|
||||
import org.springframework.web.cors.CorsConfigurationSource
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource
|
||||
import org.springframework.web.filter.CorsFilter
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class CorsConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def "HandlerMappingIntrospector default"() {
|
||||
setup:
|
||||
loadConfig(DefaultCorsConfig)
|
||||
when:
|
||||
addCors()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Content-Type-Options':'nosniff',
|
||||
'X-Frame-Options':'DENY',
|
||||
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
|
||||
'Expires' : '0',
|
||||
'Pragma':'no-cache',
|
||||
'X-XSS-Protection' : '1; mode=block']
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class DefaultCorsConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.cors()
|
||||
}
|
||||
}
|
||||
|
||||
def "HandlerMappingIntrospector explicit"() {
|
||||
setup:
|
||||
loadConfig(MvcCorsConfig)
|
||||
when:
|
||||
addCors()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
when:
|
||||
setupWeb()
|
||||
addCors(true)
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
static class MvcCorsConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.cors()
|
||||
}
|
||||
|
||||
@RestController
|
||||
@CrossOrigin(methods = [
|
||||
RequestMethod.GET, RequestMethod.POST
|
||||
])
|
||||
static class CorsController {
|
||||
@RequestMapping("/")
|
||||
String hello() {
|
||||
"Hello"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "CorsConfigurationSource"() {
|
||||
setup:
|
||||
loadConfig(ConfigSourceConfig)
|
||||
when:
|
||||
addCors()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
when:
|
||||
setupWeb()
|
||||
addCors(true)
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
|
||||
@EnableWebSecurity
|
||||
static class ConfigSourceConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.cors()
|
||||
}
|
||||
|
||||
@Bean
|
||||
CorsConfigurationSource corsConfigurationSource() {
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource()
|
||||
source.registerCorsConfiguration("/**", new CorsConfiguration(allowedOrigins : ['*'], allowedMethods : [
|
||||
RequestMethod.GET.name(),
|
||||
RequestMethod.POST.name()
|
||||
]))
|
||||
source
|
||||
}
|
||||
}
|
||||
|
||||
def "CorsFilter"() {
|
||||
setup:
|
||||
loadConfig(CorsFilterConfig)
|
||||
when:
|
||||
addCors()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
when:
|
||||
setupWeb()
|
||||
addCors(true)
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CorsFilterConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.cors()
|
||||
}
|
||||
|
||||
@Bean
|
||||
CorsFilter corsFilter() {
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource()
|
||||
source.registerCorsConfiguration("/**", new CorsConfiguration(allowedOrigins : ['*'], allowedMethods : [
|
||||
RequestMethod.GET.name(),
|
||||
RequestMethod.POST.name()
|
||||
]))
|
||||
new CorsFilter(source)
|
||||
}
|
||||
}
|
||||
|
||||
def addCors(boolean isPreflight=false) {
|
||||
request.addHeader(HttpHeaders.ORIGIN,"https://example.com")
|
||||
if(!isPreflight) {
|
||||
return
|
||||
}
|
||||
request.method = HttpMethod.OPTIONS.name()
|
||||
request.addHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Copyright 2002-2016 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.http
|
||||
|
||||
import javax.servlet.http.HttpServletResponse
|
||||
|
||||
import org.springframework.http.*
|
||||
import org.springframework.mock.web.*
|
||||
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import org.springframework.web.filter.CorsFilter
|
||||
import org.springframework.web.cors.CorsConfiguration
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Tim Ysewyn
|
||||
*/
|
||||
class HttpCorsConfigTests extends AbstractHttpConfigTests {
|
||||
MockHttpServletRequest request
|
||||
MockHttpServletResponse response
|
||||
MockFilterChain chain
|
||||
|
||||
def setup() {
|
||||
request = new MockHttpServletRequest(method:"GET")
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
}
|
||||
|
||||
def "HandlerMappingIntrospector default"() {
|
||||
setup:
|
||||
xml.http('entry-point-ref' : 'ep') {
|
||||
'cors'()
|
||||
'intercept-url'(pattern:'/**', access: 'authenticated')
|
||||
}
|
||||
bean('ep', Http403ForbiddenEntryPoint)
|
||||
createAppContext()
|
||||
when:
|
||||
addCors()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Content-Type-Options':'nosniff',
|
||||
'X-Frame-Options':'DENY',
|
||||
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
|
||||
'Expires' : '0',
|
||||
'Pragma':'no-cache',
|
||||
'X-XSS-Protection' : '1; mode=block']
|
||||
}
|
||||
|
||||
def "HandlerMappingIntrospector explicit"() {
|
||||
setup:
|
||||
xml.http('entry-point-ref' : 'ep') {
|
||||
'cors'()
|
||||
'intercept-url'(pattern:'/**', access: 'authenticated')
|
||||
}
|
||||
bean('ep', Http403ForbiddenEntryPoint)
|
||||
bean('controller', CorsController)
|
||||
xml.'mvc:annotation-driven'()
|
||||
createAppContext()
|
||||
when:
|
||||
addCors()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
when:
|
||||
setup()
|
||||
addCors(true)
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
def "CorsConfigurationSource"() {
|
||||
setup:
|
||||
xml.http('entry-point-ref' : 'ep') {
|
||||
'cors'('configuration-source-ref':'ccs')
|
||||
'intercept-url'(pattern:'/**', access: 'authenticated')
|
||||
}
|
||||
bean('ep', Http403ForbiddenEntryPoint)
|
||||
bean('ccs', MyCorsConfigurationSource)
|
||||
createAppContext()
|
||||
when:
|
||||
addCors()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
when:
|
||||
setup()
|
||||
addCors(true)
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
def "CorsFilter"() {
|
||||
setup:
|
||||
xml.http('entry-point-ref' : 'ep') {
|
||||
'cors'('ref' : 'cf')
|
||||
'intercept-url'(pattern:'/**', access: 'authenticated')
|
||||
}
|
||||
xml.'b:bean'(id: 'cf', 'class': CorsFilter.name) {
|
||||
'b:constructor-arg'(ref: 'ccs')
|
||||
}
|
||||
bean('ep', Http403ForbiddenEntryPoint)
|
||||
bean('ccs', MyCorsConfigurationSource)
|
||||
createAppContext()
|
||||
when:
|
||||
addCors()
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
when:
|
||||
setup()
|
||||
addCors(true)
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'Ensure we a CORS response w/ Spring Security headers too'
|
||||
responseHeaders['Access-Control-Allow-Origin']
|
||||
responseHeaders['X-Content-Type-Options']
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
def addCors(boolean isPreflight=false) {
|
||||
request.addHeader(HttpHeaders.ORIGIN,"https://example.com")
|
||||
if(!isPreflight) {
|
||||
return
|
||||
}
|
||||
request.method = HttpMethod.OPTIONS.name()
|
||||
request.addHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
|
||||
}
|
||||
|
||||
def getResponseHeaders() {
|
||||
def headers = [:]
|
||||
response.headerNames.each { name ->
|
||||
headers.put(name, response.getHeaderValues(name).join(','))
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
@RestController
|
||||
@CrossOrigin(methods = [
|
||||
RequestMethod.GET, RequestMethod.POST
|
||||
])
|
||||
static class CorsController {
|
||||
@RequestMapping("/")
|
||||
String hello() {
|
||||
"Hello"
|
||||
}
|
||||
}
|
||||
|
||||
static class MyCorsConfigurationSource extends UrlBasedCorsConfigurationSource {
|
||||
MyCorsConfigurationSource() {
|
||||
registerCorsConfiguration('/**', new CorsConfiguration(allowedOrigins : ['*'], allowedMethods : [
|
||||
RequestMethod.GET.name(),
|
||||
RequestMethod.POST.name()
|
||||
]))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -391,6 +391,7 @@ Here is the list of improvements:
|
|||
=== Web Application Security Improvements
|
||||
* <<headers-csp,Content Security Policy (CSP)>>
|
||||
* <<headers-hpkp,HTTP Public Key Pinning (HPKP)>>
|
||||
* <<cors,CORS>>
|
||||
* <<csrf-cookie,CookieCsrfTokenRepository>> provides simple AngularJS & CSRF integration
|
||||
* Added `ForwardAuthenticationFailureHandler` & `ForwardAuthenticationSuccessHandler`
|
||||
* <<mvc-authentication-principal,AuthenticationPrincipal>> supports expression attribute to support transforming the `Authentication.getPrincipal()` object (i.e. handling immutable custom `User` domain objects)
|
||||
|
@ -3567,6 +3568,83 @@ For example, you can provide a custom CsrfTokenRepository to override the way in
|
|||
|
||||
You can also specify a custom RequestMatcher to determine which requests are protected by CSRF (i.e. perhaps you don't care if log out is exploited). In short, if Spring Security's CSRF protection doesn't behave exactly as you want it, you are able to customize the behavior. Refer to the <<nsa-csrf>> documentation for details on how to make these customizations with XML and the `CsrfConfigurer` javadoc for details on how to make these customizations when using Java configuration.
|
||||
|
||||
[[cors]]
|
||||
== CORS
|
||||
|
||||
Spring Framework provides http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#cors[first class support for CORS].
|
||||
CORS must be processed before Spring Security because the preflight request will not contain any cookies (i.e. the `JSESSIONID`).
|
||||
If the request does not contain any cookies and Spring Security is first, the request will determine the user is not authenticated (since there are no cookies in the request) and reject it.
|
||||
|
||||
The easiest way to ensure that CORS is handled first is to use the `CorsFilter`.
|
||||
Users can integrate the `CorsFilter` with Spring Security by providing a `CorsConfigurationSource` using the following:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@EnableWebSecurity
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
// by default uses a Bean by the name of corsConfigurationSource
|
||||
.cors().and()
|
||||
...
|
||||
}
|
||||
|
||||
@Bean
|
||||
CorsConfigurationSource corsConfigurationSource() {
|
||||
CorsConfiguration configuration = new CorsConfiguration();
|
||||
configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
|
||||
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", configuration);
|
||||
return source;
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
or in XML
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<http>
|
||||
<cors configuration-source-ref="corsSource"/>
|
||||
...
|
||||
</http>
|
||||
<b:bean id="corsSource" class="org.springframework.web.cors.UrlBasedCorsConfigurationSource">
|
||||
...
|
||||
</b:bean>
|
||||
----
|
||||
|
||||
If you are using Spring MVC's CORS support, you can omit specifying the `CorsConfigurationSource` and Spring Security will leverage the CORS configuration provided to Spring MVC.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@EnableWebSecurity
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
// if Spring MVC is on classpath and no CorsConfigurationSource is provided,
|
||||
// Spring Security will use CORS configuration provided to Spring MVC
|
||||
.cors().and()
|
||||
...
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
or in XML
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<http>
|
||||
<!-- Default to Spring MVC's CORS configuraiton -->
|
||||
<cors />
|
||||
...
|
||||
</http>
|
||||
----
|
||||
|
||||
[[headers]]
|
||||
== Security HTTP Response Headers
|
||||
This section discusses Spring Security's support for adding various security headers to the response.
|
||||
|
@ -7357,6 +7435,7 @@ Enables EL-expressions in the `access` attribute, as described in the chapter on
|
|||
===== Child Elements of <http>
|
||||
* <<nsa-access-denied-handler,access-denied-handler>>
|
||||
* <<nsa-anonymous,anonymous>>
|
||||
* <<nsa-cors,cors>>
|
||||
* <<nsa-csrf,csrf>>
|
||||
* <<nsa-custom-filter,custom-filter>>
|
||||
* <<nsa-expression-handler,expression-handler>>
|
||||
|
@ -7398,6 +7477,28 @@ The access denied page that an authenticated user will be redirected to if they
|
|||
Defines a reference to a Spring bean of type `AccessDeniedHandler`.
|
||||
|
||||
|
||||
[[nsa-cors]]
|
||||
==== <cors>
|
||||
This element allows for configuring a `CorsFilter`.
|
||||
If no `CorsFilter` or `CorsConfigurationSource` is specified and Spring MVC is on the classpath, a `HandlerMappingIntrospector` is used as the `CorsConfigurationSource`.
|
||||
|
||||
[[nsa-cors-attributes]]
|
||||
===== <cors> Attributes
|
||||
The attributes on the `<cors>` element control the headers element.
|
||||
|
||||
[[nsa-cors-ref]]
|
||||
* **ref**
|
||||
Optional attribute that specifies the bean name of a `CorsFilter`.
|
||||
|
||||
[[nsa-cors-configuration-source-ref]]
|
||||
* **ref**
|
||||
Optional attribute that specifies the bean name of a `CorsConfigurationSource` to be injected into a `CorsFilter` created by the XML namespace.
|
||||
|
||||
[[nsa-cors-parents]]
|
||||
===== Parent Elements of <cors>
|
||||
|
||||
* <<nsa-http,http>>
|
||||
|
||||
[[nsa-headers]]
|
||||
==== <headers>
|
||||
This element allows for configuring additional (security) headers to be send with the response. It enables easy configuration for several headers and also allows for setting custom headers through the <<nsa-header,header>> element. Additional information, can be found in the <<headers,Security Headers>> section of the reference.
|
||||
|
|
Loading…
Reference in New Issue