SEC-792: Filters should only be added to the default stack if they are labelled using custom-filter.

http://jira.springframework.org/browse/SEC-792. The filters are now maintained as a list in the context and have to be stored there explicitly on registration.
This commit is contained in:
Luke Taylor 2008-04-23 16:06:54 +00:00
parent 80cd7f4acc
commit 38774ec94f
12 changed files with 134 additions and 106 deletions

View File

@ -3,6 +3,7 @@ package org.springframework.security.config;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition;
@ -70,6 +71,7 @@ public class AnonymousBeanDefinitionParser implements BeanDefinitionParser {
authMgrProviderList.add(provider); authMgrProviderList.add(provider);
parserContext.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_PROCESSING_FILTER, filter); parserContext.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_PROCESSING_FILTER, filter);
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.ANONYMOUS_PROCESSING_FILTER));
parserContext.registerComponent(new BeanComponentDefinition(filter, BeanIds.ANONYMOUS_PROCESSING_FILTER)); parserContext.registerComponent(new BeanComponentDefinition(filter, BeanIds.ANONYMOUS_PROCESSING_FILTER));
return null; return null;

View File

@ -41,6 +41,7 @@ public class BasicAuthenticationBeanDefinitionParser implements BeanDefinitionPa
parserContext.getRegistry().registerBeanDefinition(BeanIds.BASIC_AUTHENTICATION_FILTER, parserContext.getRegistry().registerBeanDefinition(BeanIds.BASIC_AUTHENTICATION_FILTER,
filterBuilder.getBeanDefinition()); filterBuilder.getBeanDefinition());
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.BASIC_AUTHENTICATION_FILTER));
parserContext.registerComponent(new BeanComponentDefinition(filterBuilder.getBeanDefinition(), parserContext.registerComponent(new BeanComponentDefinition(filterBuilder.getBeanDefinition(),
BeanIds.BASIC_AUTHENTICATION_FILTER)); BeanIds.BASIC_AUTHENTICATION_FILTER));
return null; return null;

View File

@ -18,6 +18,7 @@ public abstract class BeanIds {
static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = "_contextSettingPostProcessor"; static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = "_contextSettingPostProcessor";
static final String HTTP_POST_PROCESSOR = "_httpConfigBeanFactoryPostProcessor"; static final String HTTP_POST_PROCESSOR = "_httpConfigBeanFactoryPostProcessor";
static final String FILTER_CHAIN_POST_PROCESSOR = "_filterChainProxyPostProcessor"; static final String FILTER_CHAIN_POST_PROCESSOR = "_filterChainProxyPostProcessor";
static final String FILTER_LIST = "_filterChainList";
public static final String JDBC_USER_DETAILS_MANAGER = "_jdbcUserDetailsManager"; public static final String JDBC_USER_DETAILS_MANAGER = "_jdbcUserDetailsManager";
public static final String USER_DETAILS_SERVICE = "_userDetailsService"; public static final String USER_DETAILS_SERVICE = "_userDetailsService";

View File

@ -83,6 +83,7 @@ public class ConcurrentSessionsBeanDefinitionParser implements BeanDefinitionPar
parserContext.registerComponent(new BeanComponentDefinition(controller, BeanIds.CONCURRENT_SESSION_CONTROLLER)); parserContext.registerComponent(new BeanComponentDefinition(controller, BeanIds.CONCURRENT_SESSION_CONTROLLER));
beanRegistry.registerBeanDefinition(BeanIds.CONCURRENT_SESSION_FILTER, filterBuilder.getBeanDefinition()); beanRegistry.registerBeanDefinition(BeanIds.CONCURRENT_SESSION_FILTER, filterBuilder.getBeanDefinition());
parserContext.registerComponent(new BeanComponentDefinition(filterBuilder.getBeanDefinition(), BeanIds.CONCURRENT_SESSION_FILTER)); parserContext.registerComponent(new BeanComponentDefinition(filterBuilder.getBeanDefinition(), BeanIds.CONCURRENT_SESSION_FILTER));
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.CONCURRENT_SESSION_FILTER));
BeanDefinition providerManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext); BeanDefinition providerManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);

View File

@ -1,7 +1,11 @@
package org.springframework.security.config; package org.springframework.security.config;
import java.util.List;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.config.RuntimeBeanReference;
@ -83,7 +87,6 @@ public abstract class ConfigUtils {
return authManager; return authManager;
} }
/** /**
* Obtains a user details service for use in RememberMeServices etc. Will return a caching version * Obtains a user details service for use in RememberMeServices etc. Will return a caching version
* if available so should not be used for beans which need to separate the two. * if available so should not be used for beans which need to separate the two.
@ -110,4 +113,50 @@ public abstract class ConfigUtils {
BeanDefinition authManager = registerProviderManagerIfNecessary(parserContext); BeanDefinition authManager = registerProviderManagerIfNecessary(parserContext);
return (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue(); return (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
} }
private static void registerFilterChainPostProcessorIfNecessary(ParserContext pc) {
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR)) {
return;
}
// Post processor specifically to assemble and order the filter chain immediately before the FilterChainProxy is initialized.
RootBeanDefinition filterChainPostProcessor = new RootBeanDefinition(FilterChainProxyPostProcessor.class);
filterChainPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR, filterChainPostProcessor);
RootBeanDefinition filterList = new RootBeanDefinition(FilterChainList.class);
filterList.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_LIST, filterList);
}
static void addHttpFilter(ParserContext pc, BeanMetadataElement filter) {
registerFilterChainPostProcessorIfNecessary(pc);
RootBeanDefinition filterList = (RootBeanDefinition) pc.getRegistry().getBeanDefinition(BeanIds.FILTER_LIST);
ManagedList filters;
MutablePropertyValues pvs = filterList.getPropertyValues();
if (pvs.contains("filters")) {
filters = (ManagedList) pvs.getPropertyValue("filters").getValue();
} else {
filters = new ManagedList();
pvs.addPropertyValue("filters", filters);
}
filters.add(filter);
}
/**
* Bean which holds the list of filters which are maintained in the context and modified by calls to
* addHttpFilter. The post processor retrieves these before injecting the list into the FilterChainProxy.
*/
public static class FilterChainList {
List filters;
public List getFilters() {
return filters;
}
public void setFilters(List filters) {
this.filters = filters;
}
}
} }

View File

@ -2,12 +2,9 @@ package org.springframework.security.config;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.servlet.Filter;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
@ -16,9 +13,8 @@ import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.OrderComparator; import org.springframework.core.OrderComparator;
import org.springframework.core.Ordered; import org.springframework.security.config.ConfigUtils.FilterChainList;
import org.springframework.security.util.FilterChainProxy; import org.springframework.security.util.FilterChainProxy;
import org.springframework.util.Assert;
/** /**
* *
@ -29,70 +25,33 @@ import org.springframework.util.Assert;
public class FilterChainProxyPostProcessor implements BeanPostProcessor, BeanFactoryAware { public class FilterChainProxyPostProcessor implements BeanPostProcessor, BeanFactoryAware {
private Log logger = LogFactory.getLog(getClass()); private Log logger = LogFactory.getLog(getClass());
private ListableBeanFactory beanFactory; private ListableBeanFactory beanFactory;
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(!beanName.equals(BeanIds.FILTER_CHAIN_PROXY)) { if(!beanName.equals(BeanIds.FILTER_CHAIN_PROXY)) {
return bean; return bean;
} }
FilterChainProxy filterChainProxy = (FilterChainProxy) bean; FilterChainProxy filterChainProxy = (FilterChainProxy) bean;
// Set the default match FilterChainList filterList = (FilterChainList) beanFactory.getBean(BeanIds.FILTER_LIST);
List defaultFilterChain = orderFilters(beanFactory);
List filters = new ArrayList(filterList.getFilters());
Collections.sort(filters, new OrderComparator());
// Note that this returns a copy // Note that this returns a copy
Map filterMap = filterChainProxy.getFilterChainMap(); Map filterMap = filterChainProxy.getFilterChainMap();
String allUrlsMatch = filterChainProxy.getMatcher().getUniversalMatchPattern(); filterMap.put(filterChainProxy.getMatcher().getUniversalMatchPattern(), filters);
filterMap.put(allUrlsMatch, defaultFilterChain);
filterChainProxy.setFilterChainMap(filterMap); filterChainProxy.setFilterChainMap(filterMap);
logger.info("Configured filter chain(s): " + filterChainProxy); logger.info("FilterChainProxy: " + filterChainProxy);
return bean; return bean;
} }
private List orderFilters(ListableBeanFactory beanFactory) {
Map filters = beanFactory.getBeansOfType(Filter.class);
Assert.notEmpty(filters, "No filters found in app context!");
Iterator ids = filters.keySet().iterator();
List orderedFilters = new ArrayList();
while (ids.hasNext()) {
String id = (String) ids.next();
Filter filter = (Filter) filters.get(id);
if (filter instanceof FilterChainProxy) {
continue;
}
// Filters must be Spring security filters or wrapped using <custom-filter>
if (!filter.getClass().getName().startsWith("org.springframework.security")) {
continue;
}
if (!(filter instanceof Ordered)) {
logger.info("Filter " + id + " doesn't implement the Ordered interface, skipping it.");
continue;
}
orderedFilters.add(filter);
}
Collections.sort(orderedFilters, new OrderComparator());
return orderedFilters;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean; return bean;
} }
public void setBeanFactory(BeanFactory beanFactory) throws BeansException { public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ListableBeanFactory) beanFactory; this.beanFactory = (ListableBeanFactory) beanFactory;
} }
} }

View File

@ -97,7 +97,6 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
static final String ATT_ENTRY_POINT_REF = "entry-point-ref"; static final String ATT_ENTRY_POINT_REF = "entry-point-ref";
static final String ATT_ONCE_PER_REQUEST = "once-per-request"; static final String ATT_ONCE_PER_REQUEST = "once-per-request";
static final String ATT_ACCESS_DENIED_PAGE = "access-denied-page"; static final String ATT_ACCESS_DENIED_PAGE = "access-denied-page";
public BeanDefinition parse(Element element, ParserContext parserContext) { public BeanDefinition parse(Element element, ParserContext parserContext) {
ConfigUtils.registerProviderManagerIfNecessary(parserContext); ConfigUtils.registerProviderManagerIfNecessary(parserContext);
@ -117,9 +116,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
parseInterceptUrlsForChannelSecurityAndFilterChain(interceptUrlElts, filterChainMap, channelRequestMap, parseInterceptUrlsForChannelSecurityAndFilterChain(interceptUrlElts, filterChainMap, channelRequestMap,
convertPathsToLowerCase, parserContext); convertPathsToLowerCase, parserContext);
registerHttpSessionIntegrationFilter(element, registry); registerHttpSessionIntegrationFilter(element, parserContext);
registerServletApiFilter(element, registry); registerServletApiFilter(element, parserContext);
// Set up the access manager reference for http // Set up the access manager reference for http
String accessManagerId = element.getAttribute(ATT_ACCESS_MGR); String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
@ -134,15 +133,15 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
DomUtils.getChildElementByTagName(element, Elements.PORT_MAPPINGS), parserContext); DomUtils.getChildElementByTagName(element, Elements.PORT_MAPPINGS), parserContext);
registry.registerBeanDefinition(BeanIds.PORT_MAPPER, portMapper); registry.registerBeanDefinition(BeanIds.PORT_MAPPER, portMapper);
registerExceptionTranslationFilter(element.getAttribute(ATT_ACCESS_DENIED_PAGE), registry); registerExceptionTranslationFilter(element.getAttribute(ATT_ACCESS_DENIED_PAGE), parserContext);
if (channelRequestMap.size() > 0) { if (channelRequestMap.size() > 0) {
// At least one channel requirement has been specified // At least one channel requirement has been specified
registerChannelProcessingBeans(parserContext.getRegistry(), matcher, channelRequestMap); registerChannelProcessingBeans(parserContext, matcher, channelRequestMap);
} }
registerFilterSecurityInterceptor(element, registry, matcher, accessManagerId, registerFilterSecurityInterceptor(element, parserContext, matcher, accessManagerId,
parseInterceptUrlsForFilterInvocationRequestMap(interceptUrlElts, convertPathsToLowerCase, parserContext)); parseInterceptUrlsForFilterInvocationRequestMap(interceptUrlElts, convertPathsToLowerCase, parserContext));
boolean sessionControlEnabled = registerConcurrentSessionControlBeansIfRequired(element, parserContext); boolean sessionControlEnabled = registerConcurrentSessionControlBeansIfRequired(element, parserContext);
@ -200,15 +199,10 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
filterChainProxy.getPropertyValues().addPropertyValue("matcher", matcher); filterChainProxy.getPropertyValues().addPropertyValue("matcher", matcher);
filterChainProxy.getPropertyValues().addPropertyValue("filterChainMap", filterChainMap); filterChainProxy.getPropertyValues().addPropertyValue("filterChainMap", filterChainMap);
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_PROXY, filterChainProxy); pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_PROXY, filterChainProxy);
pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN); pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
// Post processor specifically to assemble and order the filter chain immediately before the FilterChainProxy is initialized.
RootBeanDefinition filterChainPostProcessor = new RootBeanDefinition(FilterChainProxyPostProcessor.class);
filterChainPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR, filterChainPostProcessor);
} }
private void registerHttpSessionIntegrationFilter(Element element, BeanDefinitionRegistry registry) { private void registerHttpSessionIntegrationFilter(Element element, ParserContext pc) {
RootBeanDefinition httpScif = new RootBeanDefinition(HttpSessionContextIntegrationFilter.class); RootBeanDefinition httpScif = new RootBeanDefinition(HttpSessionContextIntegrationFilter.class);
String createSession = element.getAttribute(ATT_CREATE_SESSION); String createSession = element.getAttribute(ATT_CREATE_SESSION);
@ -224,19 +218,21 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.FALSE); httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
} }
registry.registerBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER, httpScif); pc.getRegistry().registerBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER, httpScif);
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER));
} }
// Adds the servlet-api integration filter if required // Adds the servlet-api integration filter if required
private void registerServletApiFilter(Element element, BeanDefinitionRegistry registry) { private void registerServletApiFilter(Element element, ParserContext pc) {
String provideServletApi = element.getAttribute(ATT_SERVLET_API_PROVISION); String provideServletApi = element.getAttribute(ATT_SERVLET_API_PROVISION);
if (!StringUtils.hasText(provideServletApi)) { if (!StringUtils.hasText(provideServletApi)) {
provideServletApi = DEF_SERVLET_API_PROVISION; provideServletApi = DEF_SERVLET_API_PROVISION;
} }
if ("true".equals(provideServletApi)) { if ("true".equals(provideServletApi)) {
registry.registerBeanDefinition(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER, pc.getRegistry().registerBeanDefinition(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER,
new RootBeanDefinition(SecurityContextHolderAwareRequestFilter.class)); new RootBeanDefinition(SecurityContextHolderAwareRequestFilter.class));
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER));
} }
} }
@ -253,7 +249,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
return true; return true;
} }
private void registerExceptionTranslationFilter(String accessDeniedPage, BeanDefinitionRegistry registry) { private void registerExceptionTranslationFilter(String accessDeniedPage, ParserContext pc) {
BeanDefinitionBuilder exceptionTranslationFilterBuilder BeanDefinitionBuilder exceptionTranslationFilterBuilder
= BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class); = BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
@ -263,10 +259,11 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
exceptionTranslationFilterBuilder.addPropertyValue("accessDeniedHandler", accessDeniedHandler); exceptionTranslationFilterBuilder.addPropertyValue("accessDeniedHandler", accessDeniedHandler);
} }
registry.registerBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER, exceptionTranslationFilterBuilder.getBeanDefinition()); pc.getRegistry().registerBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER, exceptionTranslationFilterBuilder.getBeanDefinition());
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.EXCEPTION_TRANSLATION_FILTER));
} }
private void registerFilterSecurityInterceptor(Element element, BeanDefinitionRegistry registry, UrlMatcher matcher, private void registerFilterSecurityInterceptor(Element element, ParserContext pc, UrlMatcher matcher,
String accessManagerId, LinkedHashMap filterInvocationDefinitionMap) { String accessManagerId, LinkedHashMap filterInvocationDefinitionMap) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class); BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class);
@ -279,10 +276,11 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
builder.addPropertyValue("objectDefinitionSource", builder.addPropertyValue("objectDefinitionSource",
new DefaultFilterInvocationDefinitionSource(matcher, filterInvocationDefinitionMap)); new DefaultFilterInvocationDefinitionSource(matcher, filterInvocationDefinitionMap));
registry.registerBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR, builder.getBeanDefinition()); pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR, builder.getBeanDefinition());
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FILTER_SECURITY_INTERCEPTOR));
} }
private void registerChannelProcessingBeans(BeanDefinitionRegistry registry, UrlMatcher matcher, LinkedHashMap channelRequestMap) { private void registerChannelProcessingBeans(ParserContext pc, UrlMatcher matcher, LinkedHashMap channelRequestMap) {
RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class); RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class);
channelFilter.getPropertyValues().addPropertyValue("channelDecisionManager", channelFilter.getPropertyValues().addPropertyValue("channelDecisionManager",
new RuntimeBeanReference(BeanIds.CHANNEL_DECISION_MANAGER)); new RuntimeBeanReference(BeanIds.CHANNEL_DECISION_MANAGER));
@ -307,11 +305,13 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
channelProcessors.add(inSecureChannelProcessor); channelProcessors.add(inSecureChannelProcessor);
channelDecisionManager.getPropertyValues().addPropertyValue("channelProcessors", channelProcessors); channelDecisionManager.getPropertyValues().addPropertyValue("channelProcessors", channelProcessors);
registry.registerBeanDefinition(BeanIds.CHANNEL_PROCESSING_FILTER, channelFilter); pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_PROCESSING_FILTER, channelFilter);
registry.registerBeanDefinition(BeanIds.CHANNEL_DECISION_MANAGER, channelDecisionManager); ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.CHANNEL_PROCESSING_FILTER));
pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_DECISION_MANAGER, channelDecisionManager);
} }
private void registerSessionFixationProtectionFilter(ParserContext parserContext, String sessionFixationAttribute, boolean sessionControlEnabled) { private void registerSessionFixationProtectionFilter(ParserContext pc, String sessionFixationAttribute, boolean sessionControlEnabled) {
if(!StringUtils.hasText(sessionFixationAttribute)) { if(!StringUtils.hasText(sessionFixationAttribute)) {
sessionFixationAttribute = OPT_SESSION_FIXATION_MIGRATE_SESSION; sessionFixationAttribute = OPT_SESSION_FIXATION_MIGRATE_SESSION;
} }
@ -324,13 +324,14 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
if (sessionControlEnabled) { if (sessionControlEnabled) {
sessionFixationFilter.addPropertyReference("sessionRegistry", BeanIds.SESSION_REGISTRY); sessionFixationFilter.addPropertyReference("sessionRegistry", BeanIds.SESSION_REGISTRY);
} }
parserContext.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER, pc.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER,
sessionFixationFilter.getBeanDefinition()); sessionFixationFilter.getBeanDefinition());
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SESSION_FIXATION_PROTECTION_FILTER));
} }
} }
private void parseBasicFormLoginAndOpenID(Element element, ParserContext parserContext, boolean autoConfig) { private void parseBasicFormLoginAndOpenID(Element element, ParserContext pc, boolean autoConfig) {
RootBeanDefinition formLoginFilter = null; RootBeanDefinition formLoginFilter = null;
RootBeanDefinition formLoginEntryPoint = null; RootBeanDefinition formLoginEntryPoint = null;
String formLoginPage = null; String formLoginPage = null;
@ -345,7 +346,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
Element basicAuthElt = DomUtils.getChildElementByTagName(element, Elements.BASIC_AUTH); Element basicAuthElt = DomUtils.getChildElementByTagName(element, Elements.BASIC_AUTH);
if (basicAuthElt != null || autoConfig) { if (basicAuthElt != null || autoConfig) {
new BasicAuthenticationBeanDefinitionParser(realm).parse(basicAuthElt, parserContext); new BasicAuthenticationBeanDefinitionParser(realm).parse(basicAuthElt, pc);
} }
Element formLoginElt = DomUtils.getChildElementByTagName(element, Elements.FORM_LOGIN); Element formLoginElt = DomUtils.getChildElementByTagName(element, Elements.FORM_LOGIN);
@ -354,7 +355,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check", FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
"org.springframework.security.ui.webapp.AuthenticationProcessingFilter"); "org.springframework.security.ui.webapp.AuthenticationProcessingFilter");
parser.parse(formLoginElt, parserContext); parser.parse(formLoginElt, pc);
formLoginFilter = parser.getFilterBean(); formLoginFilter = parser.getFilterBean();
formLoginEntryPoint = parser.getEntryPointBean(); formLoginEntryPoint = parser.getEntryPointBean();
formLoginPage = parser.getLoginPage(); formLoginPage = parser.getLoginPage();
@ -366,7 +367,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check", FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
"org.springframework.security.ui.openid.OpenIDAuthenticationProcessingFilter"); "org.springframework.security.ui.openid.OpenIDAuthenticationProcessingFilter");
parser.parse(openIDLoginElt, parserContext); parser.parse(openIDLoginElt, pc);
openIDFilter = parser.getFilterBean(); openIDFilter = parser.getFilterBean();
openIDEntryPoint = parser.getEntryPointBean(); openIDEntryPoint = parser.getEntryPointBean();
openIDLoginPage = parser.getLoginPage(); openIDLoginPage = parser.getLoginPage();
@ -381,23 +382,25 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
} }
BeanDefinition openIDProvider = openIDProviderBuilder.getBeanDefinition(); BeanDefinition openIDProvider = openIDProviderBuilder.getBeanDefinition();
ConfigUtils.getRegisteredProviders(parserContext).add(openIDProvider); ConfigUtils.getRegisteredProviders(pc).add(openIDProvider);
parserContext.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_PROVIDER, openIDProvider); pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_PROVIDER, openIDProvider);
} }
boolean needLoginPage = false; boolean needLoginPage = false;
if (formLoginFilter != null) { if (formLoginFilter != null) {
needLoginPage = true; needLoginPage = true;
parserContext.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, formLoginFilter); pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, formLoginFilter);
parserContext.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, formLoginEntryPoint); ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, formLoginEntryPoint);
} }
if (openIDFilter != null) { if (openIDFilter != null) {
needLoginPage = true; needLoginPage = true;
parserContext.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openIDFilter); pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openIDFilter);
parserContext.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openIDEntryPoint); ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openIDEntryPoint);
} }
// If no login page has been defined, add in the default page generator. // If no login page has been defined, add in the default page generator.
@ -415,8 +418,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER)); loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
} }
parserContext.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER, pc.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER,
loginPageFilter.getBeanDefinition()); loginPageFilter.getBeanDefinition());
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER));
} }
// We need to establish the main entry point. // We need to establish the main entry point.
@ -424,39 +428,39 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
String customEntryPoint = element.getAttribute(ATT_ENTRY_POINT_REF); String customEntryPoint = element.getAttribute(ATT_ENTRY_POINT_REF);
if (StringUtils.hasText(customEntryPoint)) { if (StringUtils.hasText(customEntryPoint)) {
parserContext.getRegistry().registerAlias(customEntryPoint, BeanIds.MAIN_ENTRY_POINT); pc.getRegistry().registerAlias(customEntryPoint, BeanIds.MAIN_ENTRY_POINT);
return; return;
} }
// Basic takes precedence if explicit element is used and no others are configured // Basic takes precedence if explicit element is used and no others are configured
if (basicAuthElt != null && formLoginElt == null && openIDLoginElt == null) { if (basicAuthElt != null && formLoginElt == null && openIDLoginElt == null) {
parserContext.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT); pc.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
return; return;
} }
// If formLogin has been enabled either through an element or auto-config, then it is used if no openID login page // If formLogin has been enabled either through an element or auto-config, then it is used if no openID login page
// has been set // has been set
if (formLoginFilter != null && openIDLoginPage == null) { if (formLoginFilter != null && openIDLoginPage == null) {
parserContext.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT); pc.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
return; return;
} }
// Otherwise use OpenID if enabled // Otherwise use OpenID if enabled
if (openIDFilter != null && formLoginFilter == null) { if (openIDFilter != null && formLoginFilter == null) {
parserContext.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT); pc.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
return; return;
} }
// If X.509 has been enabled, use the preauth entry point. // If X.509 has been enabled, use the preauth entry point.
if (DomUtils.getChildElementByTagName(element, Elements.X509) != null) { if (DomUtils.getChildElementByTagName(element, Elements.X509) != null) {
parserContext.getRegistry().registerAlias(BeanIds.PRE_AUTH_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT); pc.getRegistry().registerAlias(BeanIds.PRE_AUTH_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
return; return;
} }
parserContext.getReaderContext().error("No AuthenticationEntryPoint could be established. Please " + pc.getReaderContext().error("No AuthenticationEntryPoint could be established. Please " +
"make sure you have a login mechanism configured through the namespace (such as form-login) or " + "make sure you have a login mechanism configured through the namespace (such as form-login) or " +
"specify a custom AuthenticationEntryPoint with the custom-entry-point-ref attribute ", "specify a custom AuthenticationEntryPoint with the custom-entry-point-ref attribute ",
parserContext.extractSource(element)); pc.extractSource(element));
} }
static UrlMatcher createUrlMatcher(Element element) { static UrlMatcher createUrlMatcher(Element element) {

View File

@ -70,7 +70,8 @@ public class LogoutBeanDefinitionParser implements BeanDefinitionParser {
builder.addConstructorArg(handlers); builder.addConstructorArg(handlers);
parserContext.getRegistry().registerBeanDefinition(BeanIds.LOGOUT_FILTER, builder.getBeanDefinition()); parserContext.getRegistry().registerBeanDefinition(BeanIds.LOGOUT_FILTER, builder.getBeanDefinition());
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.LOGOUT_FILTER));
return null; return null;
} }
} }

View File

@ -9,8 +9,8 @@ import javax.servlet.ServletException;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.BeanDefinitionDecorator; import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
import org.springframework.beans.factory.xml.ParserContext; import org.springframework.beans.factory.xml.ParserContext;
@ -22,8 +22,8 @@ import org.w3c.dom.Element;
import org.w3c.dom.Node; import org.w3c.dom.Node;
/** /**
* Replaces a Spring bean of type "Filter" with a wrapper class which implements the <tt>Ordered</tt> * Adds the decorated "Filter" bean into the standard filter chain maintained by the FilterChainProxy.
* interface. This allows user to add their own filter to the security chain. If the user's filter * This allows user to add their own custom filters to the security chain. If the user's filter
* already implements Ordered, and no "order" attribute is specified, the filter's default order will be used. * already implements Ordered, and no "order" attribute is specified, the filter's default order will be used.
* *
* @author Luke Taylor * @author Luke Taylor
@ -39,16 +39,17 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
Element elt = (Element)node; Element elt = (Element)node;
String order = getOrder(elt, parserContext); String order = getOrder(elt, parserContext);
BeanDefinition filter = holder.getBeanDefinition();
BeanDefinitionBuilder wrapper = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.config.OrderedFilterBeanDefinitionDecorator$OrderedFilterDecorator"); BeanDefinitionBuilder wrapper = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.config.OrderedFilterBeanDefinitionDecorator$OrderedFilterDecorator");
wrapper.addConstructorArg(holder.getBeanName()); wrapper.addConstructorArg(holder.getBeanName());
wrapper.addConstructorArg(filter); wrapper.addConstructorArg(new RuntimeBeanReference(holder.getBeanName()));
if (StringUtils.hasText(order)) { if (StringUtils.hasText(order)) {
wrapper.addPropertyValue("order", order); wrapper.addPropertyValue("order", order);
} }
return new BeanDefinitionHolder(wrapper.getBeanDefinition(), holder.getBeanName()); ConfigUtils.addHttpFilter(parserContext, wrapper.getBeanDefinition());
return holder;
} }
/** /**
@ -123,5 +124,9 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
public String toString() { public String toString() {
return "OrderedFilterDecorator[ delegate=" + delegate + "; order=" + getOrder() + "]"; return "OrderedFilterDecorator[ delegate=" + delegate + "; order=" + getOrder() + "]";
} }
Filter getDelegate() {
return delegate;
}
} }
} }

View File

@ -103,6 +103,7 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services); parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services);
parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_FILTER, filter); parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_FILTER, filter);
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.REMEMBER_ME_FILTER));
return null; return null;
} }

View File

@ -62,6 +62,7 @@ public class X509BeanDefinitionParser implements BeanDefinitionParser {
filterBuilder.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER)); filterBuilder.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
parserContext.getRegistry().registerBeanDefinition(BeanIds.X509_FILTER, filterBuilder.getBeanDefinition()); parserContext.getRegistry().registerBeanDefinition(BeanIds.X509_FILTER, filterBuilder.getBeanDefinition());
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.X509_FILTER));
return null; return null;
} }

View File

@ -259,7 +259,8 @@ public class HttpSecurityBeanDefinitionParserTests {
@Test @Test
public void externalFiltersAreTreatedCorrectly() throws Exception { public void externalFiltersAreTreatedCorrectly() throws Exception {
// Decorated user-filter should be added to stack. The other one should be ignored // Decorated user-filter should be added to stack. The other MockFilter and the un-decorated standard filter
// should be ignored
setContext( setContext(
"<http auto-config='true'/>" + AUTH_PROVIDER_XML + "<http auto-config='true'/>" + AUTH_PROVIDER_XML +
"<b:bean id='userFilter' class='org.springframework.security.util.MockFilter'>" + "<b:bean id='userFilter' class='org.springframework.security.util.MockFilter'>" +
@ -268,7 +269,9 @@ public class HttpSecurityBeanDefinitionParserTests {
"<b:bean id='userFilter2' class='org.springframework.security.util.MockFilter'>" + "<b:bean id='userFilter2' class='org.springframework.security.util.MockFilter'>" +
" <custom-filter position='FIRST'/>" + " <custom-filter position='FIRST'/>" +
"</b:bean>" + "</b:bean>" +
"<b:bean id='userFilter3' class='org.springframework.security.util.MockFilter'/>"); "<b:bean id='userFilter3' class='org.springframework.security.util.MockFilter'/>" +
"<b:bean id='userFilter4' class='org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter'/>"
);
List filters = getFilters("/someurl"); List filters = getFilters("/someurl");
assertEquals(13, filters.size()); assertEquals(13, filters.size());