From 8ddd96af2b7a0ba6aa8cdd9f05bffde38b051f63 Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Fri, 26 Jun 2009 12:44:46 +0000 Subject: [PATCH] SEC-1186: intermediate commit of namespace changes for improved tooling support --- .../config/AnonymousBeanDefinitionParser.java | 2 - ...enticationManagerBeanDefinitionParser.java | 17 +- .../security/config/BeanIds.java | 30 +- .../security/config/ConfigUtils.java | 82 +- .../EntryPointInjectionBeanPostProcessor.java | 44 +- .../security/config}/FilterChainOrder.java | 2 +- .../config/FilterChainProxyPostProcessor.java | 196 +- .../config/FormLoginBeanDefinitionParser.java | 48 +- ...balMethodSecurityBeanDefinitionParser.java | 33 +- .../HttpSecurityBeanDefinitionParser.java | 662 ++++-- ...terceptMethodsBeanDefinitionDecorator.java | 2 +- .../NamespaceAuthenticationManager.java | 4 +- .../OrderedFilterBeanDefinitionDecorator.java | 3 +- .../RememberMeBeanDefinitionParser.java | 48 +- ...rMeServicesInjectionBeanPostProcessor.java | 34 +- .../config/X509BeanDefinitionParser.java | 9 +- .../security/config/spring-security-3.0.rnc | 12 +- .../security/config/spring-security-3.0.xsd | 1958 +++++++++++++---- ...HttpSecurityBeanDefinitionParserTests.java | 98 +- ...ptMethodsBeanDefinitionDecoratorTests.java | 11 +- .../security/config/TestBusinessBeanImpl.java | 11 +- .../util/InMemoryXmlApplicationContext.java | 2 + .../security/web/FilterChainProxy.java | 22 +- .../security/web/SpringSecurityFilter.java | 11 +- .../access/ExceptionTranslationFilter.java | 5 - .../channel/ChannelProcessingFilter.java | 5 - .../intercept/FilterSecurityInterceptor.java | 7 +- .../AnonymousProcessingFilter.java | 24 +- ...asswordAuthenticationProcessingFilter.java | 14 +- .../concurrent/ConcurrentSessionFilter.java | 28 +- .../authentication/logout/LogoutFilter.java | 5 - ...eaderPreAuthenticatedProcessingFilter.java | 37 +- .../J2eePreAuthenticatedProcessingFilter.java | 4 - ...pherePreAuthenticatedProcessingFilter.java | 4 - .../X509PreAuthenticatedProcessingFilter.java | 10 +- .../RememberMeProcessingFilter.java | 32 +- .../SwitchUserProcessingFilter.java | 5 - .../ui/DefaultLoginPageGeneratingFilter.java | 5 - .../www/BasicProcessingFilter.java | 19 +- .../www/DigestProcessingFilter.java | 5 - .../HttpSessionContextIntegrationFilter.java | 7 - .../SecurityContextPersistenceFilter.java | 5 - .../SessionFixationProtectionFilter.java | 5 - ...curityContextHolderAwareRequestFilter.java | 5 - .../AbstractProcessingFilterTests.java | 4 - ...DefaultLoginPageGeneratingFilterTests.java | 5 - ...PreAuthenticatedProcessingFilterTests.java | 4 - ...PreAuthenticatedProcessingFilterTests.java | 11 +- ...SecurityContextPersistenceFilterTests.java | 14 +- 49 files changed, 2398 insertions(+), 1212 deletions(-) rename {web/src/main/java/org/springframework/security/web => config/src/main/java/org/springframework/security/config}/FilterChainOrder.java (99%) diff --git a/config/src/main/java/org/springframework/security/config/AnonymousBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/AnonymousBeanDefinitionParser.java index 8256a28618..66e9c0957a 100644 --- a/config/src/main/java/org/springframework/security/config/AnonymousBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/AnonymousBeanDefinitionParser.java @@ -3,8 +3,6 @@ package org.springframework.security.config; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; 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.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; diff --git a/config/src/main/java/org/springframework/security/config/AuthenticationManagerBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/AuthenticationManagerBeanDefinitionParser.java index d0fe957de3..5d129ba2c2 100644 --- a/config/src/main/java/org/springframework/security/config/AuthenticationManagerBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/AuthenticationManagerBeanDefinitionParser.java @@ -22,31 +22,32 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition private static final String ATT_ALIAS = "alias"; public BeanDefinition parse(Element element, ParserContext parserContext) { - ConfigUtils.registerProviderManagerIfNecessary(parserContext); - + ConfigUtils.registerProviderManagerIfNecessary(parserContext, element); + String alias = element.getAttribute(ATT_ALIAS); if (!StringUtils.hasText(alias)) { parserContext.getReaderContext().error(ATT_ALIAS + " is required.", element ); } - + String sessionControllerRef = element.getAttribute(ATT_SESSION_CONTROLLER_REF); - + if (StringUtils.hasText(sessionControllerRef)) { BeanDefinition authManager = parserContext.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER); - ConfigUtils.setSessionControllerOnAuthenticationManager(parserContext, + ConfigUtils.setSessionControllerOnAuthenticationManager(parserContext, BeanIds.CONCURRENT_SESSION_CONTROLLER, element); - authManager.getPropertyValues().addPropertyValue("sessionController", + authManager.getPropertyValues().addPropertyValue("sessionController", new RuntimeBeanReference(sessionControllerRef)); RootBeanDefinition sessionRegistryInjector = new RootBeanDefinition(SessionRegistryInjectionBeanPostProcessor.class); sessionRegistryInjector.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); sessionRegistryInjector.getConstructorArgumentValues().addGenericArgumentValue(sessionControllerRef); - + parserContext.getRegistry().registerBeanDefinition(BeanIds.SESSION_REGISTRY_INJECTION_POST_PROCESSOR, sessionRegistryInjector); } parserContext.getRegistry().registerAlias(BeanIds.AUTHENTICATION_MANAGER, alias); + parserContext.getReaderContext().fireAliasRegistered(BeanIds.AUTHENTICATION_MANAGER, alias, parserContext.extractSource(element)); return null; - } + } } diff --git a/config/src/main/java/org/springframework/security/config/BeanIds.java b/config/src/main/java/org/springframework/security/config/BeanIds.java index cea5494121..8f0622c126 100644 --- a/config/src/main/java/org/springframework/security/config/BeanIds.java +++ b/config/src/main/java/org/springframework/security/config/BeanIds.java @@ -16,20 +16,20 @@ public abstract class BeanIds { /** Package protected as end users shouldn't really be using this BFPP directly */ static final String INTERCEPT_METHODS_BEAN_FACTORY_POST_PROCESSOR = "_interceptMethodsBeanfactoryPP"; static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = "_contextSettingPostProcessor"; - static final String ENTRY_POINT_INJECTION_POST_PROCESSOR = "_entryPointInjectionBeanPostProcessor"; +// static final String ENTRY_POINT_INJECTION_POST_PROCESSOR = "_entryPointInjectionBeanPostProcessor"; static final String USER_DETAILS_SERVICE_INJECTION_POST_PROCESSOR = "_userServiceInjectionPostProcessor"; static final String SESSION_REGISTRY_INJECTION_POST_PROCESSOR = "_sessionRegistryInjectionPostProcessor"; - static final String FILTER_CHAIN_POST_PROCESSOR = "_filterChainProxyPostProcessor"; - static final String FILTER_LIST = "_filterChainList"; +// 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 USER_DETAILS_SERVICE = "_userDetailsService"; - public static final String ANONYMOUS_PROCESSING_FILTER = "_anonymousProcessingFilter"; +// public static final String ANONYMOUS_PROCESSING_FILTER = "_anonymousProcessingFilter"; public static final String ANONYMOUS_AUTHENTICATION_PROVIDER = "_anonymousAuthenticationProvider"; - public static final String BASIC_AUTHENTICATION_FILTER = "_basicAuthenticationFilter"; +// public static final String BASIC_AUTHENTICATION_FILTER = "_basicAuthenticationFilter"; public static final String BASIC_AUTHENTICATION_ENTRY_POINT = "_basicAuthenticationEntryPoint"; public static final String SESSION_REGISTRY = "_sessionRegistry"; - public static final String CONCURRENT_SESSION_FILTER = "_concurrentSessionFilter"; +// public static final String CONCURRENT_SESSION_FILTER = "_concurrentSessionFilter"; public static final String CONCURRENT_SESSION_CONTROLLER = "_concurrentSessionController"; public static final String METHOD_ACCESS_MANAGER = "_defaultMethodAccessManager"; public static final String WEB_ACCESS_MANAGER = "_webAccessManager"; @@ -42,18 +42,18 @@ public abstract class BeanIds { public static final String OPEN_ID_PROVIDER = "_openIDAuthenticationProvider"; public static final String MAIN_ENTRY_POINT = "_mainEntryPoint"; public static final String FILTER_CHAIN_PROXY = "_filterChainProxy"; - public static final String SECURITY_CONTEXT_PERSISTENCE_FILTER = "_securityContextPersistenceFilter"; +// public static final String SECURITY_CONTEXT_PERSISTENCE_FILTER = "_securityContextPersistenceFilter"; public static final String LDAP_AUTHENTICATION_PROVIDER = "_ldapAuthenticationProvider"; - public static final String LOGOUT_FILTER = "_logoutFilter"; - public static final String EXCEPTION_TRANSLATION_FILTER = "_exceptionTranslationFilter"; - public static final String FILTER_SECURITY_INTERCEPTOR = "_filterSecurityInterceptor"; - public static final String CHANNEL_PROCESSING_FILTER = "_channelProcessingFilter"; +// public static final String LOGOUT_FILTER = "_logoutFilter"; +// public static final String EXCEPTION_TRANSLATION_FILTER = "_exceptionTranslationFilter"; +// public static final String FILTER_SECURITY_INTERCEPTOR = "_filterSecurityInterceptor"; +// public static final String CHANNEL_PROCESSING_FILTER = "_channelProcessingFilter"; public static final String CHANNEL_DECISION_MANAGER = "_channelDecisionManager"; - public static final String REMEMBER_ME_FILTER = "_rememberMeFilter"; +// public static final String REMEMBER_ME_FILTER = "_rememberMeFilter"; public static final String REMEMBER_ME_SERVICES = "_rememberMeServices"; public static final String REMEMBER_ME_AUTHENTICATION_PROVIDER = "_rememberMeAuthenticationProvider"; - public static final String DEFAULT_LOGIN_PAGE_GENERATING_FILTER = "_defaultLoginPageFilter"; - public static final String SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER = "_securityContextHolderAwareRequestFilter"; +// public static final String DEFAULT_LOGIN_PAGE_GENERATING_FILTER = "_defaultLoginPageFilter"; +// public static final String SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER = "_securityContextHolderAwareRequestFilter"; public static final String SESSION_FIXATION_PROTECTION_FILTER = "_sessionFixationProtectionFilter"; public static final String METHOD_SECURITY_METADATA_SOURCE_ADVISOR = "_methodSecurityMetadataSourceAdvisor"; public static final String PROTECT_POINTCUT_POST_PROCESSOR = "_protectPointcutPostProcessor"; @@ -62,7 +62,7 @@ public abstract class BeanIds { public static final String EMBEDDED_APACHE_DS = "_apacheDirectoryServerContainer"; public static final String CONTEXT_SOURCE = "_securityContextSource"; public static final String PORT_MAPPER = "_portMapper"; - public static final String X509_FILTER = "_x509ProcessingFilter"; +// public static final String X509_FILTER = "_x509ProcessingFilter"; public static final String X509_AUTH_PROVIDER = "_x509AuthenticationProvider"; public static final String PRE_AUTH_ENTRY_POINT = "_preAuthenticatedProcessingFilterEntryPoint"; public static final String REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR = "_rememberMeServicesInjectionBeanPostProcessor"; diff --git a/config/src/main/java/org/springframework/security/config/ConfigUtils.java b/config/src/main/java/org/springframework/security/config/ConfigUtils.java index 7b21d84197..796bcb5e40 100644 --- a/config/src/main/java/org/springframework/security/config/ConfigUtils.java +++ b/config/src/main/java/org/springframework/security/config/ConfigUtils.java @@ -3,8 +3,6 @@ package org.springframework.security.config; import java.util.ArrayList; import java.util.List; -import org.springframework.beans.BeanMetadataElement; -import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.PropertyValue; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.RuntimeBeanReference; @@ -20,6 +18,7 @@ import org.springframework.security.access.vote.AuthenticatedVoter; import org.springframework.security.access.vote.RoleVoter; import org.springframework.security.web.util.UrlUtils; import org.springframework.util.StringUtils; +import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; /** @@ -40,7 +39,7 @@ abstract class ConfigUtils { } @SuppressWarnings("unchecked") - static BeanDefinition createAccessManagerBean(Class... voters) { + static RootBeanDefinition createAccessManagerBean(Class... voters) { ManagedList defaultVoters = new ManagedList(voters.length); for(Class voter : voters) { @@ -49,7 +48,7 @@ abstract class ConfigUtils { BeanDefinitionBuilder accessMgrBuilder = BeanDefinitionBuilder.rootBeanDefinition(AffirmativeBased.class); accessMgrBuilder.addPropertyValue("decisionVoters", defaultVoters); - return accessMgrBuilder.getBeanDefinition(); + return (RootBeanDefinition) accessMgrBuilder.getBeanDefinition(); } public static int countNonEmpty(String[] objects) { @@ -69,20 +68,24 @@ abstract class ConfigUtils { * the BeanDefinition for it. This method will typically be called when registering authentication providers * using the <security:provider /> tag or by other beans which have a dependency on the * authentication manager. + * @param element the source element under which this bean should be registered. */ - static void registerProviderManagerIfNecessary(ParserContext parserContext) { - if(parserContext.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER)) { + static void registerProviderManagerIfNecessary(ParserContext pc, Element element) { + + if(pc.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER)) { return; } - BeanDefinition authManager = new RootBeanDefinition(NamespaceAuthenticationManager.class); + RootBeanDefinition authManager = new RootBeanDefinition(NamespaceAuthenticationManager.class); authManager.getPropertyValues().addPropertyValue("providerBeanNames", new ArrayList()); - parserContext.getRegistry().registerBeanDefinition(BeanIds.AUTHENTICATION_MANAGER, authManager); + authManager.setSource(pc.extractSource(element.getOwnerDocument().getFirstChild())); + pc.getRegistry().registerBeanDefinition(BeanIds.AUTHENTICATION_MANAGER, authManager); + pc.registerBeanComponent(new BeanComponentDefinition(authManager, BeanIds.AUTHENTICATION_MANAGER)); } @SuppressWarnings("unchecked") static void addAuthenticationProvider(ParserContext parserContext, String beanName) { - registerProviderManagerIfNecessary(parserContext); + registerProviderManagerIfNecessary(parserContext, null); BeanDefinition authManager = parserContext.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER); ((ArrayList) authManager.getPropertyValues().getPropertyValue("providerBeanNames").getValue()).add(beanName); } @@ -106,37 +109,37 @@ abstract class ConfigUtils { return manager; } - 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); - pc.registerBeanComponent(new BeanComponentDefinition(filterList, BeanIds.FILTER_LIST)); - } +// 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); +// pc.registerBeanComponent(new BeanComponentDefinition(filterList, BeanIds.FILTER_LIST)); +// } - @SuppressWarnings("unchecked") - 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); - } + // @SuppressWarnings("unchecked") +// 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 @@ -167,7 +170,6 @@ abstract class ConfigUtils { } static void setSessionControllerOnAuthenticationManager(ParserContext pc, String beanName, Element sourceElt) { - registerProviderManagerIfNecessary(pc); BeanDefinition authManager = pc.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER); PropertyValue pv = authManager.getPropertyValues().getPropertyValue("sessionController"); diff --git a/config/src/main/java/org/springframework/security/config/EntryPointInjectionBeanPostProcessor.java b/config/src/main/java/org/springframework/security/config/EntryPointInjectionBeanPostProcessor.java index 8a489f2351..6b0986acc9 100644 --- a/config/src/main/java/org/springframework/security/config/EntryPointInjectionBeanPostProcessor.java +++ b/config/src/main/java/org/springframework/security/config/EntryPointInjectionBeanPostProcessor.java @@ -24,28 +24,28 @@ public class EntryPointInjectionBeanPostProcessor implements BeanPostProcessor, @SuppressWarnings("unchecked") public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - if (!BeanIds.EXCEPTION_TRANSLATION_FILTER.equals(beanName)) { - return bean; - } - - logger.info("Selecting AuthenticationEntryPoint for use in ExceptionTranslationFilter"); - - ExceptionTranslationFilter etf = (ExceptionTranslationFilter) beanFactory.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER); - - Object entryPoint = null; - - if (beanFactory.containsBean(BeanIds.MAIN_ENTRY_POINT)) { - entryPoint = beanFactory.getBean(BeanIds.MAIN_ENTRY_POINT); - logger.info("Using main configured AuthenticationEntryPoint."); - } else { - Map entryPoints = beanFactory.getBeansOfType(AuthenticationEntryPoint.class); - Assert.isTrue(entryPoints.size() != 0, "No AuthenticationEntryPoint instances defined"); - Assert.isTrue(entryPoints.size() == 1, "More than one AuthenticationEntryPoint defined in context"); - entryPoint = entryPoints.values().toArray()[0]; - } - - logger.info("Using bean '" + entryPoint + "' as the entry point."); - etf.setAuthenticationEntryPoint((AuthenticationEntryPoint) entryPoint); +// if (!BeanIds.EXCEPTION_TRANSLATION_FILTER.equals(beanName)) { +// return bean; +// } +// +// logger.info("Selecting AuthenticationEntryPoint for use in ExceptionTranslationFilter"); +// +// ExceptionTranslationFilter etf = (ExceptionTranslationFilter) beanFactory.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER); +// +// Object entryPoint = null; +// +// if (beanFactory.containsBean(BeanIds.MAIN_ENTRY_POINT)) { +// entryPoint = beanFactory.getBean(BeanIds.MAIN_ENTRY_POINT); +// logger.info("Using main configured AuthenticationEntryPoint."); +// } else { +// Map entryPoints = beanFactory.getBeansOfType(AuthenticationEntryPoint.class); +// Assert.isTrue(entryPoints.size() != 0, "No AuthenticationEntryPoint instances defined"); +// Assert.isTrue(entryPoints.size() == 1, "More than one AuthenticationEntryPoint defined in context"); +// entryPoint = entryPoints.values().toArray()[0]; +// } +// +// logger.info("Using bean '" + entryPoint + "' as the entry point."); +// etf.setAuthenticationEntryPoint((AuthenticationEntryPoint) entryPoint); return bean; } diff --git a/web/src/main/java/org/springframework/security/web/FilterChainOrder.java b/config/src/main/java/org/springframework/security/config/FilterChainOrder.java similarity index 99% rename from web/src/main/java/org/springframework/security/web/FilterChainOrder.java rename to config/src/main/java/org/springframework/security/config/FilterChainOrder.java index 58f0c01a17..ab47fbc5c2 100644 --- a/web/src/main/java/org/springframework/security/web/FilterChainOrder.java +++ b/config/src/main/java/org/springframework/security/config/FilterChainOrder.java @@ -1,4 +1,4 @@ -package org.springframework.security.web; +package org.springframework.security.config; import org.springframework.util.Assert; diff --git a/config/src/main/java/org/springframework/security/config/FilterChainProxyPostProcessor.java b/config/src/main/java/org/springframework/security/config/FilterChainProxyPostProcessor.java index 1a1ee3e9f7..fdf5060984 100644 --- a/config/src/main/java/org/springframework/security/config/FilterChainProxyPostProcessor.java +++ b/config/src/main/java/org/springframework/security/config/FilterChainProxyPostProcessor.java @@ -45,51 +45,51 @@ public class FilterChainProxyPostProcessor implements BeanPostProcessor, BeanFac @SuppressWarnings("unchecked") public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - if(!BeanIds.FILTER_CHAIN_PROXY.equals(beanName)) { - return bean; - } - - FilterChainProxy filterChainProxy = (FilterChainProxy) bean; - FilterChainList filterList = (FilterChainList) beanFactory.getBean(BeanIds.FILTER_LIST); - - List filters = new ArrayList(filterList.getFilters()); - Collections.sort(filters, new OrderComparator()); - - logger.info("Checking sorted filter chain: " + filters); - - for(int i=0; i < filters.size(); i++) { - Ordered filter = (Ordered)filters.get(i); - - if (i > 0) { - Ordered previous = (Ordered)filters.get(i-1); - if (filter.getOrder() == previous.getOrder()) { - throw new SecurityConfigurationException("Filters '" + unwrapFilter(filter) + "' and '" + - unwrapFilter(previous) + "' have the same 'order' value. When using custom filters, " + - "please make sure the positions do not conflict with default filters. " + - "Alternatively you can disable the default filters by removing the corresponding " + - "child elements from and avoiding the use of ."); - } - } - } - - logger.info("Filter chain..."); - for (int i=0; i < filters.size(); i++) { - // Remove the ordered wrapper from the filter and put it back in the chain at the same position. - Filter filter = unwrapFilter(filters.get(i)); - logger.info("[" + i + "] - " + filter); - filters.set(i, filter); - } - - checkFilterStack(filters); - - // Note that this returns a copy - Map> filterMap = filterChainProxy.getFilterChainMap(); - filterMap.put(filterChainProxy.getMatcher().getUniversalMatchPattern(), filters); - filterChainProxy.setFilterChainMap(filterMap); - - checkLoginPageIsntProtected(filterChainProxy); - - logger.info("FilterChainProxy: " + filterChainProxy); +// if(!BeanIds.FILTER_CHAIN_PROXY.equals(beanName)) { +// return bean; +// } +// +// FilterChainProxy filterChainProxy = (FilterChainProxy) bean; +// FilterChainList filterList = (FilterChainList) beanFactory.getBean(BeanIds.FILTER_LIST); +// +// List filters = new ArrayList(filterList.getFilters()); +// Collections.sort(filters, new OrderComparator()); +// +// logger.info("Checking sorted filter chain: " + filters); +// +// for(int i=0; i < filters.size(); i++) { +// Ordered filter = (Ordered)filters.get(i); +// +// if (i > 0) { +// Ordered previous = (Ordered)filters.get(i-1); +// if (filter.getOrder() == previous.getOrder()) { +// throw new SecurityConfigurationException("Filters '" + unwrapFilter(filter) + "' and '" + +// unwrapFilter(previous) + "' have the same 'order' value. When using custom filters, " + +// "please make sure the positions do not conflict with default filters. " + +// "Alternatively you can disable the default filters by removing the corresponding " + +// "child elements from and avoiding the use of ."); +// } +// } +// } +// +// logger.info("Filter chain..."); +// for (int i=0; i < filters.size(); i++) { +// // Remove the ordered wrapper from the filter and put it back in the chain at the same position. +// Filter filter = unwrapFilter(filters.get(i)); +// logger.info("[" + i + "] - " + filter); +// filters.set(i, filter); +// } +// +// checkFilterStack(filters); +// +// // Note that this returns a copy +// Map> filterMap = filterChainProxy.getFilterChainMap(); +// filterMap.put(filterChainProxy.getMatcher().getUniversalMatchPattern(), filters); +// filterChainProxy.setFilterChainMap(filterMap); +// +// checkLoginPageIsntProtected(filterChainProxy); +// +// logger.info("FilterChainProxy: " + filterChainProxy); return bean; } @@ -126,59 +126,59 @@ public class FilterChainProxyPostProcessor implements BeanPostProcessor, BeanFac /* Checks for the common error of having a login page URL protected by the security interceptor */ private void checkLoginPageIsntProtected(FilterChainProxy fcp) { - ExceptionTranslationFilter etf = (ExceptionTranslationFilter) beanFactory.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER); - - if (etf.getAuthenticationEntryPoint() instanceof LoginUrlAuthenticationEntryPoint) { - String loginPage = - ((LoginUrlAuthenticationEntryPoint)etf.getAuthenticationEntryPoint()).getLoginFormUrl(); - List filters = fcp.getFilters(loginPage); - logger.info("Checking whether login URL '" + loginPage + "' is accessible with your configuration"); - - if (filters == null || filters.isEmpty()) { - logger.debug("Filter chain is empty for the login page"); - return; - } - - if (loginPage.equals(DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL) && - beanFactory.containsBean(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER)) { - logger.debug("Default generated login page is in use"); - return; - } - - FilterSecurityInterceptor fsi = - ((FilterSecurityInterceptor)beanFactory.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR)); - DefaultFilterInvocationSecurityMetadataSource fids = - (DefaultFilterInvocationSecurityMetadataSource) fsi.getSecurityMetadataSource(); - List attributes = fids.lookupAttributes(loginPage, "POST"); - - if (attributes == null) { - logger.debug("No access attributes defined for login page URL"); - if (fsi.isRejectPublicInvocations()) { - logger.warn("FilterSecurityInterceptor is configured to reject public invocations." + - " Your login page may not be accessible."); - } - return; - } - - if (!beanFactory.containsBean(BeanIds.ANONYMOUS_PROCESSING_FILTER)) { - logger.warn("The login page is being protected by the filter chain, but you don't appear to have" + - " anonymous authentication enabled. This is almost certainly an error."); - return; - } - - // Simulate an anonymous access with the supplied attributes. - AnonymousProcessingFilter anonPF = (AnonymousProcessingFilter) beanFactory.getBean(BeanIds.ANONYMOUS_PROCESSING_FILTER); - AnonymousAuthenticationToken token = - new AnonymousAuthenticationToken("key", anonPF.getUserAttribute().getPassword(), - anonPF.getUserAttribute().getAuthorities()); - try { - fsi.getAccessDecisionManager().decide(token, new Object(), fids.lookupAttributes(loginPage, "POST")); - } catch (Exception e) { - logger.warn("Anonymous access to the login page doesn't appear to be enabled. This is almost certainly " + - "an error. Please check your configuration allows unauthenticated access to the configured " + - "login page. (Simulated access was rejected: " + e + ")"); - } - } +// ExceptionTranslationFilter etf = (ExceptionTranslationFilter) beanFactory.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER); +// +// if (etf.getAuthenticationEntryPoint() instanceof LoginUrlAuthenticationEntryPoint) { +// String loginPage = +// ((LoginUrlAuthenticationEntryPoint)etf.getAuthenticationEntryPoint()).getLoginFormUrl(); +// List filters = fcp.getFilters(loginPage); +// logger.info("Checking whether login URL '" + loginPage + "' is accessible with your configuration"); +// +// if (filters == null || filters.isEmpty()) { +// logger.debug("Filter chain is empty for the login page"); +// return; +// } +// +// if (loginPage.equals(DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL) && +// beanFactory.containsBean(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER)) { +// logger.debug("Default generated login page is in use"); +// return; +// } +// +// FilterSecurityInterceptor fsi = +// ((FilterSecurityInterceptor)beanFactory.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR)); +// DefaultFilterInvocationSecurityMetadataSource fids = +// (DefaultFilterInvocationSecurityMetadataSource) fsi.getSecurityMetadataSource(); +// List attributes = fids.lookupAttributes(loginPage, "POST"); +// +// if (attributes == null) { +// logger.debug("No access attributes defined for login page URL"); +// if (fsi.isRejectPublicInvocations()) { +// logger.warn("FilterSecurityInterceptor is configured to reject public invocations." + +// " Your login page may not be accessible."); +// } +// return; +// } +// +// if (!beanFactory.containsBean(BeanIds.ANONYMOUS_PROCESSING_FILTER)) { +// logger.warn("The login page is being protected by the filter chain, but you don't appear to have" + +// " anonymous authentication enabled. This is almost certainly an error."); +// return; +// } +// +// // Simulate an anonymous access with the supplied attributes. +// AnonymousProcessingFilter anonPF = (AnonymousProcessingFilter) beanFactory.getBean(BeanIds.ANONYMOUS_PROCESSING_FILTER); +// AnonymousAuthenticationToken token = +// new AnonymousAuthenticationToken("key", anonPF.getUserAttribute().getPassword(), +// anonPF.getUserAttribute().getAuthorities()); +// try { +// fsi.getAccessDecisionManager().decide(token, new Object(), fids.lookupAttributes(loginPage, "POST")); +// } catch (Exception e) { +// logger.warn("Anonymous access to the login page doesn't appear to be enabled. This is almost certainly " + +// "an error. Please check your configuration allows unauthenticated access to the configured " + +// "login page. (Simulated access was rejected: " + e + ")"); +// } +// } } /** diff --git a/config/src/main/java/org/springframework/security/config/FormLoginBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/FormLoginBeanDefinitionParser.java index ef8311e6e8..2184df16dc 100644 --- a/config/src/main/java/org/springframework/security/config/FormLoginBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/FormLoginBeanDefinitionParser.java @@ -1,28 +1,25 @@ package org.springframework.security.config; -import org.springframework.beans.PropertyValue; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; 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.RootBeanDefinition; -import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; import org.springframework.util.StringUtils; - import org.w3c.dom.Element; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; /** * @author Luke Taylor * @author Ben Alex * @version $Id$ */ -public class FormLoginBeanDefinitionParser implements BeanDefinitionParser { +public class FormLoginBeanDefinitionParser { protected final Log logger = LogFactory.getLog(getClass()); private static final String ATT_LOGIN_URL = "login-processing-url"; @@ -52,7 +49,7 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser { this.filterClassName = filterClassName; } - public BeanDefinition parse(Element elt, ParserContext pc) { + public BeanDefinition parse(Element elt, ParserContext pc, RootBeanDefinition sfpf) { String loginUrl = null; String defaultTargetUrl = null; String authenticationFailureUrl = null; @@ -62,17 +59,16 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser { Object source = null; - // Copy values from the session fixation protection filter - final Boolean sessionFixationProtectionEnabled = - new Boolean(pc.getRegistry().containsBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER)); - Boolean migrateSessionAttributes = Boolean.FALSE; - - if (sessionFixationProtectionEnabled.booleanValue()) { - PropertyValue pv = - pc.getRegistry().getBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER) - .getPropertyValues().getPropertyValue("migrateSessionAttributes"); - migrateSessionAttributes = (Boolean)pv.getValue(); - } +// final Boolean sessionFixationProtectionEnabled = +// new Boolean(pc.getRegistry().containsBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER)); +// Boolean migrateSessionAttributes = Boolean.FALSE; +// +// if (sessionFixationProtectionEnabled.booleanValue()) { +// PropertyValue pv = +// pc.getRegistry().getBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER) +// .getPropertyValues().getPropertyValue("migrateSessionAttributes"); +// migrateSessionAttributes = (Boolean)pv.getValue(); +// } if (elt != null) { source = pc.extractSource(elt); @@ -93,18 +89,22 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser { ConfigUtils.validateHttpRedirect(loginPage, pc, source); } - ConfigUtils.registerProviderManagerIfNecessary(pc); - filterBean = createFilterBean(loginUrl, defaultTargetUrl, alwaysUseDefault, loginPage, authenticationFailureUrl, successHandlerRef, failureHandlerRef); filterBean.setSource(source); filterBean.getPropertyValues().addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER)); - filterBean.getPropertyValues().addPropertyValue("invalidateSessionOnSuccessfulAuthentication", - sessionFixationProtectionEnabled); - filterBean.getPropertyValues().addPropertyValue("migrateInvalidatedSessionAttributes", - migrateSessionAttributes); + // Copy session migration values from the session fixation protection filter + if (sfpf != null) { + filterBean.getPropertyValues().addPropertyValue("migrateInvalidatedSessionAttributes", sfpf.getPropertyValues().getPropertyValue("migrateSessionAttributes").getValue()); + filterBean.getPropertyValues().addPropertyValue("invalidateSessionOnSuccessfulAuthentication", Boolean.TRUE); + } + +// filterBean.getPropertyValues().addPropertyValue("invalidateSessionOnSuccessfulAuthentication", +// sessionFixationProtectionEnabled); +// filterBean.getPropertyValues().addPropertyValue("migrateInvalidatedSessionAttributes", +// migrateSessionAttributes); if (pc.getRegistry().containsBeanDefinition(BeanIds.REMEMBER_ME_SERVICES)) { filterBean.getPropertyValues().addPropertyValue("rememberMeServices", diff --git a/config/src/main/java/org/springframework/security/config/GlobalMethodSecurityBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/GlobalMethodSecurityBeanDefinitionParser.java index 47a28e0e3b..45faaac04a 100644 --- a/config/src/main/java/org/springframework/security/config/GlobalMethodSecurityBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/GlobalMethodSecurityBeanDefinitionParser.java @@ -13,6 +13,7 @@ import org.springframework.aop.config.AopNamespaceUtils; 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.CompositeComponentDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.support.RootBeanDefinition; @@ -71,9 +72,13 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser { private static final String ATT_USE_PREPOST = "pre-post-annotations"; @SuppressWarnings("unchecked") - public BeanDefinition parse(Element element, ParserContext parserContext) { - ConfigUtils.registerProviderManagerIfNecessary(parserContext); - Object source = parserContext.extractSource(element); + public BeanDefinition parse(Element element, ParserContext pc) { + ConfigUtils.registerProviderManagerIfNecessary(pc, element); + CompositeComponentDefinition compositeDef = + new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element)); + pc.pushContainingComponent(compositeDef); + + Object source = pc.extractSource(element); // The list of method metadata delegates ManagedList delegates = new ManagedList(); @@ -87,7 +92,7 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser { Element expressionHandlerElt = DomUtils.getChildElementByTagName(element, EXPRESSION_HANDLER); if (prePostElt != null && expressionHandlerElt != null) { - parserContext.getReaderContext().error(INVOCATION_HANDLING + " and " + + pc.getReaderContext().error(INVOCATION_HANDLING + " and " + EXPRESSION_HANDLER + " cannot be used together ", source); } @@ -116,7 +121,7 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser { if (StringUtils.hasText(expressionHandlerRef)) { logger.info("Using bean '" + expressionHandlerRef + "' as method ExpressionHandler implementation"); } else { - parserContext.getRegistry().registerBeanDefinition(EXPRESSION_HANDLER_ID, new RootBeanDefinition(DefaultMethodSecurityExpressionHandler.class)); + pc.getRegistry().registerBeanDefinition(EXPRESSION_HANDLER_ID, new RootBeanDefinition(DefaultMethodSecurityExpressionHandler.class)); logger.warn("Expressions were enabled for method security but no SecurityExpressionHandler was configured. " + "All hasPermision() expressions will evaluate to false."); expressionHandlerRef = EXPRESSION_HANDLER_ID; @@ -136,7 +141,7 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser { } preInvocationVoter = preInvocationVoterBldr.getBeanDefinition(); - ConfigUtils.getRegisteredAfterInvocationProviders(parserContext).add(afterInvocationBldr.getBeanDefinition()); + ConfigUtils.getRegisteredAfterInvocationProviders(pc).add(afterInvocationBldr.getBeanDefinition()); delegates.add(mds.getBeanDefinition()); } @@ -149,33 +154,33 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser { } // Now create a Map for each sub-element - Map> pointcutMap = parseProtectPointcuts(parserContext, + Map> pointcutMap = parseProtectPointcuts(pc, DomUtils.getChildElementsByTagName(element, PROTECT_POINTCUT)); if (pointcutMap.size() > 0) { // Only add it if there are actually any pointcuts defined. MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource = new MapBasedMethodSecurityMetadataSource(); delegates.add(mapBasedMethodSecurityMetadataSource); - registerProtectPointcutPostProcessor(parserContext, pointcutMap, mapBasedMethodSecurityMetadataSource, source); + registerProtectPointcutPostProcessor(pc, pointcutMap, mapBasedMethodSecurityMetadataSource, source); } - registerDelegatingMethodSecurityMetadataSource(parserContext, delegates, source); + registerDelegatingMethodSecurityMetadataSource(pc, delegates, source); String accessManagerId = element.getAttribute(ATT_ACCESS_MGR); if (!StringUtils.hasText(accessManagerId)) { - registerAccessManager(parserContext, jsr250Enabled, preInvocationVoter); + registerAccessManager(pc, jsr250Enabled, preInvocationVoter); accessManagerId = ACCESS_MANAGER_ID; } String runAsManagerId = element.getAttribute(ATT_RUN_AS_MGR); - registerMethodSecurityInterceptor(parserContext, accessManagerId, runAsManagerId, source); + registerMethodSecurityInterceptor(pc, accessManagerId, runAsManagerId, source); - registerAdvisor(parserContext, source); - - AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element); + registerAdvisor(pc, source); + AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(pc, element); + pc.popAndRegisterContainingComponent(); return null; } diff --git a/config/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java index 5998f97834..107adfa545 100644 --- a/config/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java @@ -1,5 +1,7 @@ package org.springframework.security.config; +import static org.springframework.security.config.FilterChainOrder.*; + import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; @@ -14,6 +16,7 @@ import org.springframework.beans.PropertyValues; 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.CompositeComponentDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.ManagedList; @@ -21,9 +24,9 @@ import org.springframework.beans.factory.support.ManagedMap; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.security.access.AccessDecisionVoter; +import org.springframework.core.OrderComparator; +import org.springframework.core.Ordered; import org.springframework.security.access.ConfigAttribute; -import org.springframework.security.access.ConfigAttributeEditor; import org.springframework.security.access.SecurityConfig; import org.springframework.security.access.vote.AuthenticatedVoter; import org.springframework.security.access.vote.RoleVoter; @@ -40,7 +43,10 @@ import org.springframework.security.web.access.expression.WebExpressionVoter; import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource; import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; import org.springframework.security.web.access.intercept.RequestKey; +import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint; import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; +import org.springframework.security.web.authentication.www.BasicProcessingFilter; +import org.springframework.security.web.authentication.www.BasicProcessingFilterEntryPoint; import org.springframework.security.web.context.HttpSessionSecurityContextRepository; import org.springframework.security.web.context.SecurityContextPersistenceFilter; import org.springframework.security.web.session.SessionFixationProtectionFilter; @@ -120,9 +126,20 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { static final String EXPRESSION_HANDLER_CLASS = "org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler"; private static final String EXPRESSION_HANDLER_ID = "_webExpressionHandler"; - @SuppressWarnings("unchecked") + /** + * The aim of this method is to build the list of filters which have been defined by the namespace elements + * and attributes within the <http> configuration, along with any custom-filter's linked to user-defined + * filter beans. + *

+ * By the end of this method, the default FilterChainProxy bean should have been registered and will have + * the map of filter chains defined, with the "universal" match pattern mapped to the list of beans which have been parsed here. + */ public BeanDefinition parse(Element element, ParserContext pc) { - ConfigUtils.registerProviderManagerIfNecessary(pc); + ConfigUtils.registerProviderManagerIfNecessary(pc, element); + CompositeComponentDefinition compositeDef = + new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element)); + pc.pushContainingComponent(compositeDef); + final BeanDefinitionRegistry registry = pc.getRegistry(); final UrlMatcher matcher = createUrlMatcher(element); final Object source = pc.extractSource(element); @@ -130,203 +147,385 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { // true if Ant path and using lower case final boolean convertPathsToLowerCase = (matcher instanceof AntUrlPathMatcher) && matcher.requiresLowerCaseUrl(); final boolean allowSessionCreation = !OPT_CREATE_SESSION_NEVER.equals(element.getAttribute(ATT_CREATE_SESSION)); - - final List interceptUrlElts = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL); - final Map filterChainMap = new ManagedMap(); - final LinkedHashMap channelRequestMap = new LinkedHashMap(); - - registerFilterChainProxy(pc, filterChainMap, matcher, source); + final boolean autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG)); + final Map> filterChainMap = new ManagedMap>(); + final LinkedHashMap> channelRequestMap = new LinkedHashMap>(); // filterChainMap and channelRequestMap are populated by this call - parseInterceptUrlsForChannelSecurityAndEmptyFilterChains(interceptUrlElts, filterChainMap, channelRequestMap, - convertPathsToLowerCase, pc); + parseInterceptUrlsForChannelSecurityAndEmptyFilterChains(DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL), + filterChainMap, channelRequestMap, convertPathsToLowerCase, pc); - // Add the default filter list - List filterList = new ManagedList(); - filterChainMap.put(matcher.getUniversalMatchPattern(), filterList); + BeanDefinition cpf = null; + BeanDefinition concurrentSessionFilter = createConcurrentSessionFilterAndRelatedBeansIfRequired(element, pc); + boolean sessionControlEnabled = concurrentSessionFilter != null; BeanDefinition scpf = createSecurityContextPersistenceFilter(element, pc); - pc.getRegistry().registerBeanDefinition(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER, scpf); - ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER)); + + if (sessionControlEnabled) { + logger.info("Concurrent session filter in use, setting 'forceEagerSessionCreation' to true"); + scpf.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.TRUE); + + } BeanDefinition servApiFilter = createServletApiFilter(element, pc); - if (servApiFilter != null) { - pc.getRegistry().registerBeanDefinition(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER,servApiFilter); - ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER)); - } // Register the portMapper. A default will always be created, even if no element exists. BeanDefinition portMapper = new PortMappingsBeanDefinitionParser().parse( DomUtils.getChildElementByTagName(element, Elements.PORT_MAPPINGS), pc); - registry.registerBeanDefinition(BeanIds.PORT_MAPPER, portMapper); + RootBeanDefinition rememberMeFilter = createRememberMeFilter(element, pc); + BeanDefinition anonFilter = createAnonymousFilter(element, pc); BeanDefinition etf = createExceptionTranslationFilter(element, pc, allowSessionCreation); - pc.getRegistry().registerBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER, etf); - ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.EXCEPTION_TRANSLATION_FILTER)); + RootBeanDefinition sfpf = createSessionFixationProtectionFilter(pc, element.getAttribute(ATT_SESSION_FIXATION_PROTECTION), + sessionControlEnabled); + BeanDefinition fsi = createFilterSecurityInterceptor(element, pc, matcher, convertPathsToLowerCase); + registry.registerBeanDefinition(BeanIds.PORT_MAPPER, portMapper); if (channelRequestMap.size() > 0) { // At least one channel requirement has been specified - BeanDefinition cpf = createChannelProcessingFilter(pc, matcher, channelRequestMap); - pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_PROCESSING_FILTER, cpf); - ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.CHANNEL_PROCESSING_FILTER)); - + cpf = createChannelProcessingFilter(pc, matcher, channelRequestMap); } - boolean useExpressions = "true".equals(element.getAttribute(ATT_USE_EXPRESSIONS)); +// if (cpf != null) { +// pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_PROCESSING_FILTER, cpf); +// ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.CHANNEL_PROCESSING_FILTER)); +// } - LinkedHashMap> requestToAttributesMap = - parseInterceptUrlsForFilterInvocationRequestMap(interceptUrlElts, convertPathsToLowerCase, useExpressions, pc); +// pc.getRegistry().registerBeanDefinition(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER, scpf); +// ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER)); - BeanDefinitionBuilder fidsBuilder; - Class[] voters; +// if (anonFilter != null) { +// pc.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_PROCESSING_FILTER, anonFilter); +// ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.ANONYMOUS_PROCESSING_FILTER)); +// } +// +// if (servApiFilter != null) { +// pc.getRegistry().registerBeanDefinition(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER,servApiFilter); +// ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER)); +// } - if (useExpressions) { - Element expressionHandlerElt = DomUtils.getChildElementByTagName(element, Elements.EXPRESSION_HANDLER); - String expressionHandlerRef = expressionHandlerElt == null ? null : expressionHandlerElt.getAttribute("ref"); +// pc.getRegistry().registerBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER, etf); +// ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.EXCEPTION_TRANSLATION_FILTER)); +// - if (StringUtils.hasText(expressionHandlerRef)) { - logger.info("Using bean '" + expressionHandlerRef + "' as web SecurityExpressionHandler implementation"); - } else { - pc.getRegistry().registerBeanDefinition(EXPRESSION_HANDLER_ID, - BeanDefinitionBuilder.rootBeanDefinition(EXPRESSION_HANDLER_CLASS).getBeanDefinition()); - expressionHandlerRef = EXPRESSION_HANDLER_ID; - } +// pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR, fsi); +// ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FILTER_SECURITY_INTERCEPTOR)); - fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(EXPRESSION_FIMDS_CLASS); - fidsBuilder.addConstructorArgValue(matcher); - fidsBuilder.addConstructorArgValue(requestToAttributesMap); - fidsBuilder.addConstructorArgReference(expressionHandlerRef); - voters = new Class[] {WebExpressionVoter.class}; - } else { - fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(DefaultFilterInvocationSecurityMetadataSource.class); - fidsBuilder.addConstructorArgValue(matcher); - fidsBuilder.addConstructorArgValue(requestToAttributesMap); - voters = new Class[] {RoleVoter.class, AuthenticatedVoter.class}; - } - fidsBuilder.addPropertyValue("stripQueryStringFromUrls", matcher instanceof AntUrlPathMatcher); +// if (sessionControlEnabled) { +// pc.getRegistry().registerBeanDefinition(BeanIds.CONCURRENT_SESSION_FILTER, concurrentSessionFilter); +// ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.CONCURRENT_SESSION_FILTER)); +// } - // Set up the access manager reference for http - String accessManagerId = element.getAttribute(ATT_ACCESS_MGR); - - if (!StringUtils.hasText(accessManagerId)) { - pc.getRegistry().registerBeanDefinition(BeanIds.WEB_ACCESS_MANAGER, - ConfigUtils.createAccessManagerBean(voters)); - accessManagerId = BeanIds.WEB_ACCESS_MANAGER; - } - - BeanDefinition fsi = createFilterSecurityInterceptor(element, pc, accessManagerId, fidsBuilder.getBeanDefinition()); - pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR, fsi); - ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FILTER_SECURITY_INTERCEPTOR)); - - boolean sessionControlEnabled = false; - - BeanDefinition concurrentSessionFilter = createConcurrentSessionFilterAndRelatedBeansIfRequired(element, pc); - if (concurrentSessionFilter != null) { - sessionControlEnabled = true; - pc.getRegistry().registerBeanDefinition(BeanIds.CONCURRENT_SESSION_FILTER, concurrentSessionFilter); - ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.CONCURRENT_SESSION_FILTER)); - } - - BeanDefinition sfpf = createSessionFixationProtectionFilter(pc, element.getAttribute(ATT_SESSION_FIXATION_PROTECTION), - sessionControlEnabled); if (sfpf != null) { - pc.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER, sfpf); - ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SESSION_FIXATION_PROTECTION_FILTER)); - } - boolean autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG)); - - Element anonymousElt = DomUtils.getChildElementByTagName(element, Elements.ANONYMOUS); - - if (anonymousElt == null || !"false".equals(anonymousElt.getAttribute("enabled"))) { - BeanDefinition anonFilter = new AnonymousBeanDefinitionParser().parse(anonymousElt, pc); - pc.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_PROCESSING_FILTER, anonFilter); - ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.ANONYMOUS_PROCESSING_FILTER)); + // Used by SessionRegistrynjectionPP + pc.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER, sfpf); +// ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SESSION_FIXATION_PROTECTION_FILTER)); } - parseRememberMeAndLogout(element, autoConfig, pc); + final FilterAndEntryPoint basic = createBasicFilter(element, pc, autoConfig); + final FilterAndEntryPoint form = createFormLoginFilter(element, pc, autoConfig, allowSessionCreation, sfpf); + final FilterAndEntryPoint openID = createOpenIDLoginFilter(element, pc, autoConfig, allowSessionCreation, sfpf); - String realm = element.getAttribute(ATT_REALM); - if (!StringUtils.hasText(realm)) { - realm = DEF_REALM; - } - - final FilterAndEntryPoint form = createFormLoginFilter(element, pc, autoConfig, allowSessionCreation); - - if (form.filter != null) { - pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, form.filter); - ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER)); - pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, form.entryPoint); - } - - Element basicAuthElt = DomUtils.getChildElementByTagName(element, Elements.BASIC_AUTH); - if (basicAuthElt != null || autoConfig) { - BeanDefinition basicFilter = new BasicAuthenticationBeanDefinitionParser(realm).parse(basicAuthElt, pc); - pc.getRegistry().registerBeanDefinition(BeanIds.BASIC_AUTHENTICATION_FILTER, basicFilter); - ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.BASIC_AUTHENTICATION_FILTER)); - } - - FilterAndEntryPoint openID = createOpenIDLoginFilter(element, pc, autoConfig, allowSessionCreation); - - if (openID.filter != null) { - pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openID.filter); - ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER)); - pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openID.entryPoint); - } - - BeanDefinition loginPageGenerationFilter = createLoginPageFilterIfNeeded(form, openID); - - if (loginPageGenerationFilter != null) { - pc.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER, loginPageGenerationFilter); - ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER)); - } - - Element x509Elt = DomUtils.getChildElementByTagName(element, Elements.X509); - if (x509Elt != null) { - BeanDefinition x509Filter = new X509BeanDefinitionParser().parse(x509Elt, pc); - pc.getRegistry().registerBeanDefinition(BeanIds.X509_FILTER, x509Filter); - ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.X509_FILTER)); - } - - selectEntryPoint(element, pc, form, openID); - - // Register the post processors which will tie up the loose ends in the configuration once the app context has been created and all beans are available. - RootBeanDefinition postProcessor = new RootBeanDefinition(EntryPointInjectionBeanPostProcessor.class); - postProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - registry.registerBeanDefinition(BeanIds.ENTRY_POINT_INJECTION_POST_PROCESSOR, postProcessor); - RootBeanDefinition postProcessor2 = new RootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class); - postProcessor2.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - registry.registerBeanDefinition(BeanIds.USER_DETAILS_SERVICE_INJECTION_POST_PROCESSOR, postProcessor2); - - return null; - } - - private void parseRememberMeAndLogout(Element elt, boolean autoConfig, ParserContext pc) { - // Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation. - Element rememberMeElt = DomUtils.getChildElementByTagName(elt, Elements.REMEMBER_ME); - String rememberMeServices = null; - - if (rememberMeElt != null) { - RememberMeBeanDefinitionParser rmbdp = new RememberMeBeanDefinitionParser(); - BeanDefinition filter = rmbdp.parse(rememberMeElt, pc); - pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_FILTER, filter); - ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.REMEMBER_ME_FILTER)); - rememberMeServices = rmbdp.getServicesName(); + String rememberMeServicesId = null; + if (rememberMeFilter != null) { + //pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_FILTER, rememberMeFilter); + rememberMeServicesId = ((RuntimeBeanReference) rememberMeFilter.getPropertyValues().getPropertyValue("rememberMeServices").getValue()).getBeanName(); + //ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.REMEMBER_ME_FILTER)); // Post processor to inject RememberMeServices into filters which need it + RootBeanDefinition rememberMeInjectionPostProcessor = new RootBeanDefinition(RememberMeServicesInjectionBeanPostProcessor.class); rememberMeInjectionPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR, rememberMeInjectionPostProcessor); } - Element logoutElt = DomUtils.getChildElementByTagName(elt, Elements.LOGOUT); - if (logoutElt != null || autoConfig) { - BeanDefinition logoutFilter = new LogoutBeanDefinitionParser(rememberMeServices).parse(logoutElt, pc); + final BeanDefinition logoutFilter = createLogoutFilter(element, autoConfig, pc, rememberMeServicesId); - pc.getRegistry().registerBeanDefinition(BeanIds.LOGOUT_FILTER, logoutFilter); - ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.LOGOUT_FILTER)); +// if (logoutFilter != null) { +// pc.getRegistry().registerBeanDefinition(BeanIds.LOGOUT_FILTER, logoutFilter); +// ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.LOGOUT_FILTER)); +// } + + BeanDefinition loginPageGenerationFilter = createLoginPageFilterIfNeeded(form, openID); + +// if (basic.filter != null) { +// pc.getRegistry().registerBeanDefinition(BeanIds.BASIC_AUTHENTICATION_FILTER, basic.filter); +// ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.BASIC_AUTHENTICATION_FILTER)); +// } + + if (form.filter != null) { + // Required by login page filter + pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, form.filter); + if (rememberMeServicesId != null) { + form.filter.getPropertyValues().addPropertyValue("rememberMeServices", new RuntimeBeanReference(rememberMeServicesId)); + } +// ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER)); +// pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, form.entryPoint); + } + + if (openID.filter != null) { + // Required by login page filter + pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openID.filter); + if (rememberMeServicesId != null) { + openID.filter.getPropertyValues().addPropertyValue("rememberMeServices", new RuntimeBeanReference(rememberMeServicesId)); + } +// ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER)); +// pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openID.entryPoint); + } +// +// if (loginPageGenerationFilter != null) { +// pc.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER, loginPageGenerationFilter); +// ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER)); +// } + + FilterAndEntryPoint x509 = createX509Filter(element, pc); +// if (x509.filter != null) { +// pc.getRegistry().registerBeanDefinition(BeanIds.X509_FILTER, x509.filter); +// pc.getRegistry().registerBeanDefinition(BeanIds.PRE_AUTH_ENTRY_POINT, x509.entryPoint); +// ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.X509_FILTER)); +// } + + BeanMetadataElement entryPoint = selectEntryPoint(element, pc, basic, form, openID, x509); + etf.getPropertyValues().addPropertyValue("authenticationEntryPoint", entryPoint); + + // Now build the filter chain and add it to the map + List unorderedFilterChain = new ArrayList(); +// List filterChain = new ManagedList(); + + if (cpf != null) { + unorderedFilterChain.add(new OrderDecorator(cpf, CHANNEL_FILTER)); + } + + if (concurrentSessionFilter != null) { + unorderedFilterChain.add(new OrderDecorator(concurrentSessionFilter, CONCURRENT_SESSION_FILTER)); + } + + unorderedFilterChain.add(new OrderDecorator(scpf, SECURITY_CONTEXT_FILTER)); + + if (logoutFilter != null) { + unorderedFilterChain.add(new OrderDecorator(logoutFilter, LOGOUT_FILTER)); + } + + if (x509.filter != null) { + unorderedFilterChain.add(new OrderDecorator(x509.filter, X509_FILTER)); + } + + if (form.filter != null) { + unorderedFilterChain.add(new OrderDecorator(form.filter, AUTHENTICATION_PROCESSING_FILTER)); + } + + if (openID.filter != null) { + unorderedFilterChain.add(new OrderDecorator(openID.filter, OPENID_PROCESSING_FILTER)); + } + + if (loginPageGenerationFilter != null) { + unorderedFilterChain.add(new OrderDecorator(loginPageGenerationFilter, LOGIN_PAGE_FILTER)); + } + + if (basic.filter != null) { + unorderedFilterChain.add(new OrderDecorator(basic.filter, BASIC_PROCESSING_FILTER)); + } + + if (servApiFilter != null) { + unorderedFilterChain.add(new OrderDecorator(servApiFilter, SERVLET_API_SUPPORT_FILTER)); + } + + if (rememberMeFilter != null) { + unorderedFilterChain.add(new OrderDecorator(rememberMeFilter, REMEMBER_ME_FILTER)); + } + + if (anonFilter != null) { + unorderedFilterChain.add(new OrderDecorator(anonFilter, ANONYMOUS_FILTER)); + } + + unorderedFilterChain.add(new OrderDecorator(etf, EXCEPTION_TRANSLATION_FILTER)); + + if (sfpf != null) { + unorderedFilterChain.add(new OrderDecorator(sfpf, SESSION_FIXATION_FILTER)); + } + + unorderedFilterChain.add(new OrderDecorator(fsi, FILTER_SECURITY_INTERCEPTOR)); + + + List customFilters = buildCustomFilterList(element, pc); + + unorderedFilterChain.addAll(customFilters); + + Collections.sort(unorderedFilterChain, new OrderComparator()); + checkFilterChainOrder(unorderedFilterChain, pc, source); + + List filterChain = new ManagedList(); + + for (OrderDecorator od : unorderedFilterChain) { + filterChain.add(od.bean); + } + + filterChainMap.put(matcher.getUniversalMatchPattern(), filterChain); + + registerFilterChainProxy(pc, filterChainMap, matcher, source); + + + // Register the post processors which will tie up the loose ends in the configuration once the app context has been created and all beans are available. +// RootBeanDefinition postProcessor = new RootBeanDefinition(EntryPointInjectionBeanPostProcessor.class); +// postProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); +// registry.registerBeanDefinition(BeanIds.ENTRY_POINT_INJECTION_POST_PROCESSOR, postProcessor); + RootBeanDefinition postProcessor2 = new RootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class); + postProcessor2.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + registry.registerBeanDefinition(BeanIds.USER_DETAILS_SERVICE_INJECTION_POST_PROCESSOR, postProcessor2); + + pc.popAndRegisterContainingComponent(); + return null; + } + + private void checkFilterChainOrder(List filters, ParserContext pc, Object source) { + logger.info("Checking sorted filter chain: " + filters); + + for(int i=0; i < filters.size(); i++) { + OrderDecorator filter = (OrderDecorator)filters.get(i); + + if (i > 0) { + OrderDecorator previous = (OrderDecorator)filters.get(i-1); + if (filter.getOrder() == previous.getOrder()) { + pc.getReaderContext().error("Filter beans '" + filter.bean + "' and '" + + previous.bean + "' have the same 'order' value. When using custom filters, " + + "please make sure the positions do not conflict with default filters. " + + "Alternatively you can disable the default filters by removing the corresponding " + + "child elements from and avoiding the use of .", source); + } + } } } - @SuppressWarnings("unchecked") - private void registerFilterChainProxy(ParserContext pc, Map filterChainMap, UrlMatcher matcher, Object source) { + private class OrderDecorator implements Ordered { + BeanMetadataElement bean; + int order; + + public OrderDecorator(BeanMetadataElement bean, int order) { + super(); + this.bean = bean; + this.order = order; + } + + public int getOrder() { + return order; + } + } + + List buildCustomFilterList(Element element, ParserContext pc) { + List customFilterElts = DomUtils.getChildElementsByTagName(element, Elements.CUSTOM_FILTER); + List customFilters = new ArrayList(); + + final String ATT_AFTER = "after"; + final String ATT_BEFORE = "before"; + final String ATT_POSITION = "position"; + final String REF = "ref"; + + + for (Element elt: customFilterElts) { + String after = elt.getAttribute(ATT_AFTER); + String before = elt.getAttribute(ATT_BEFORE); + String position = elt.getAttribute(ATT_POSITION); + + String ref = elt.getAttribute(REF); + + if (!StringUtils.hasText(ref)) { + pc.getReaderContext().error("The '" + REF + "' attribute must be supplied", pc.extractSource(elt)); + } + + RuntimeBeanReference bean = new RuntimeBeanReference(ref); + + if(ConfigUtils.countNonEmpty(new String[] {after, before, position}) != 1) { + pc.getReaderContext().error("A single '" + ATT_AFTER + "', '" + ATT_BEFORE + "', or '" + + ATT_POSITION + "' attribute must be supplied", pc.extractSource(elt)); + } + + if (StringUtils.hasText(position)) { + customFilters.add(new OrderDecorator(bean, FilterChainOrder.getOrder(position))); + } else if (StringUtils.hasText(after)) { + int order = FilterChainOrder.getOrder(after); + customFilters.add(new OrderDecorator(bean, order == Integer.MAX_VALUE ? order : order + 1)); + } else if (StringUtils.hasText(before)) { + int order = FilterChainOrder.getOrder(before); + customFilters.add(new OrderDecorator(bean, order == Integer.MIN_VALUE ? order : order - 1)); + } + } + + return customFilters; + } + + private BeanDefinition createAnonymousFilter(Element element, ParserContext pc) { + Element anonymousElt = DomUtils.getChildElementByTagName(element, Elements.ANONYMOUS); + + if (anonymousElt == null || !"false".equals(anonymousElt.getAttribute("enabled"))) { + return new AnonymousBeanDefinitionParser().parse(anonymousElt, pc); + } + + return null; + + } + + private FilterAndEntryPoint createBasicFilter(Element elt, ParserContext pc, boolean autoConfig) { + Element basicAuthElt = DomUtils.getChildElementByTagName(elt, Elements.BASIC_AUTH); + + String realm = elt.getAttribute(ATT_REALM); + if (!StringUtils.hasText(realm)) { + realm = DEF_REALM; + } + + RootBeanDefinition filter = null; + RootBeanDefinition entryPoint = null; + + if (basicAuthElt != null || autoConfig) { + BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicProcessingFilter.class); + entryPoint = new RootBeanDefinition(BasicProcessingFilterEntryPoint.class); + entryPoint.setSource(pc.extractSource(elt)); + + entryPoint.getPropertyValues().addPropertyValue("realmName", realm); + + pc.getRegistry().registerBeanDefinition(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, entryPoint); + + filterBuilder.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER)); + filterBuilder.addPropertyValue("authenticationEntryPoint", new RuntimeBeanReference(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT)); + filter = (RootBeanDefinition) filterBuilder.getBeanDefinition(); + } + + return new FilterAndEntryPoint(filter, entryPoint); + } + + private FilterAndEntryPoint createX509Filter(Element elt, ParserContext pc) { + Element x509Elt = DomUtils.getChildElementByTagName(elt, Elements.X509); + RootBeanDefinition filter = null; + RootBeanDefinition entryPoint = null; + + if (x509Elt != null) { + filter = new X509BeanDefinitionParser().parse(x509Elt, pc); + entryPoint = new RootBeanDefinition(Http403ForbiddenEntryPoint.class); + entryPoint.setSource(pc.extractSource(x509Elt)); + } + + return new FilterAndEntryPoint(filter, entryPoint); + } + + private BeanDefinition createLogoutFilter(Element elt, boolean autoConfig, ParserContext pc, String rememberMeServicesId) { + Element logoutElt = DomUtils.getChildElementByTagName(elt, Elements.LOGOUT); + if (logoutElt != null || autoConfig) { + BeanDefinition logoutFilter = new LogoutBeanDefinitionParser(rememberMeServicesId).parse(logoutElt, pc); + + return logoutFilter; + } + return null; + } + + private RootBeanDefinition createRememberMeFilter(Element elt, ParserContext pc) { + // Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation. + Element rememberMeElt = DomUtils.getChildElementByTagName(elt, Elements.REMEMBER_ME); + + if (rememberMeElt != null) { + return (RootBeanDefinition) new RememberMeBeanDefinitionParser().parse(rememberMeElt, pc); + } + + return null; + } + + private void registerFilterChainProxy(ParserContext pc, Map> filterChainMap, UrlMatcher matcher, Object source) { if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) { pc.getReaderContext().error("Duplicate element detected", source); } @@ -339,7 +538,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { BeanDefinition fcpBean = fcpBldr.getBeanDefinition(); pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_PROXY, fcpBean); pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN); - pc.registerBeanComponent(new BeanComponentDefinition(fcpBean,BeanIds.FILTER_CHAIN_PROXY)); + pc.registerBeanComponent(new BeanComponentDefinition(fcpBean, BeanIds.FILTER_CHAIN_PROXY)); } private BeanDefinition createSecurityContextPersistenceFilter(Element element, ParserContext pc) { @@ -391,7 +590,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { } if ("true".equals(provideServletApi)) { - return new RootBeanDefinition(SecurityContextHolderAwareRequestFilter.class); + return new RootBeanDefinition(SecurityContextHolderAwareRequestFilter.class); } return null; } @@ -403,9 +602,6 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { } BeanDefinition sessionControlFilter = new ConcurrentSessionsBeanDefinitionParser().parse(sessionControlElt, parserContext); - logger.info("Concurrent session filter in use, setting 'forceEagerSessionCreation' to true"); - BeanDefinition sessionIntegrationFilter = parserContext.getRegistry().getBeanDefinition(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER); - sessionIntegrationFilter.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.TRUE); return sessionControlFilter; } @@ -455,8 +651,54 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { return accessDeniedHandler.getBeanDefinition(); } - private BeanDefinition createFilterSecurityInterceptor(Element element, ParserContext pc, String accessManagerId, - BeanDefinition fids) { + @SuppressWarnings("unchecked") + private BeanDefinition createFilterSecurityInterceptor(Element element, ParserContext pc, UrlMatcher matcher, boolean convertPathsToLowerCase) { + BeanDefinitionBuilder fidsBuilder; + + boolean useExpressions = "true".equals(element.getAttribute(ATT_USE_EXPRESSIONS)); + + LinkedHashMap> requestToAttributesMap = + parseInterceptUrlsForFilterInvocationRequestMap(DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL), + convertPathsToLowerCase, useExpressions, pc); + + + RootBeanDefinition accessDecisionMgr; + + if (useExpressions) { + Element expressionHandlerElt = DomUtils.getChildElementByTagName(element, Elements.EXPRESSION_HANDLER); + String expressionHandlerRef = expressionHandlerElt == null ? null : expressionHandlerElt.getAttribute("ref"); + + if (StringUtils.hasText(expressionHandlerRef)) { + logger.info("Using bean '" + expressionHandlerRef + "' as web SecurityExpressionHandler implementation"); + } else { + pc.getRegistry().registerBeanDefinition(EXPRESSION_HANDLER_ID, + BeanDefinitionBuilder.rootBeanDefinition(EXPRESSION_HANDLER_CLASS).getBeanDefinition()); + expressionHandlerRef = EXPRESSION_HANDLER_ID; + } + + fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(EXPRESSION_FIMDS_CLASS); + fidsBuilder.addConstructorArgValue(matcher); + fidsBuilder.addConstructorArgValue(requestToAttributesMap); + fidsBuilder.addConstructorArgReference(expressionHandlerRef); + accessDecisionMgr = ConfigUtils.createAccessManagerBean(WebExpressionVoter.class); + } else { + fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(DefaultFilterInvocationSecurityMetadataSource.class); + fidsBuilder.addConstructorArgValue(matcher); + fidsBuilder.addConstructorArgValue(requestToAttributesMap); + accessDecisionMgr = ConfigUtils.createAccessManagerBean(RoleVoter.class, AuthenticatedVoter.class); + } + accessDecisionMgr.setSource(pc.extractSource(element)); + fidsBuilder.addPropertyValue("stripQueryStringFromUrls", matcher instanceof AntUrlPathMatcher); + + // Set up the access manager reference for http + String accessManagerId = element.getAttribute(ATT_ACCESS_MGR); + + if (!StringUtils.hasText(accessManagerId)) { + pc.getRegistry().registerBeanDefinition(BeanIds.WEB_ACCESS_MANAGER, accessDecisionMgr); + pc.registerBeanComponent(new BeanComponentDefinition(accessDecisionMgr, BeanIds.WEB_ACCESS_MANAGER)); + accessManagerId = BeanIds.WEB_ACCESS_MANAGER; + } + BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class); builder.addPropertyReference("accessDecisionManager", accessManagerId); @@ -466,12 +708,11 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { builder.addPropertyValue("observeOncePerRequest", Boolean.FALSE); } - builder.addPropertyValue("securityMetadataSource", fids); + builder.addPropertyValue("securityMetadataSource", fidsBuilder.getBeanDefinition()); return builder.getBeanDefinition(); } - @SuppressWarnings("unchecked") - private BeanDefinition createChannelProcessingFilter(ParserContext pc, UrlMatcher matcher, LinkedHashMap channelRequestMap) { + private BeanDefinition createChannelProcessingFilter(ParserContext pc, UrlMatcher matcher, LinkedHashMap> channelRequestMap) { RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class); channelFilter.getPropertyValues().addPropertyValue("channelDecisionManager", new RuntimeBeanReference(BeanIds.CHANNEL_DECISION_MANAGER)); @@ -481,7 +722,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { channelFilter.getPropertyValues().addPropertyValue("securityMetadataSource", channelFilterInvDefSource); RootBeanDefinition channelDecisionManager = new RootBeanDefinition(ChannelDecisionManagerImpl.class); - ManagedList channelProcessors = new ManagedList(3); + ManagedList channelProcessors = new ManagedList(3); RootBeanDefinition secureChannelProcessor = new RootBeanDefinition(SecureChannelProcessor.class); RootBeanDefinition retryWithHttp = new RootBeanDefinition(RetryWithHttpEntryPoint.class); RootBeanDefinition retryWithHttps = new RootBeanDefinition(RetryWithHttpsEntryPoint.class); @@ -499,7 +740,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { return channelFilter; } - private BeanDefinition createSessionFixationProtectionFilter(ParserContext pc, String sessionFixationAttribute, boolean sessionControlEnabled) { + private RootBeanDefinition createSessionFixationProtectionFilter(ParserContext pc, String sessionFixationAttribute, boolean sessionControlEnabled) { if(!StringUtils.hasText(sessionFixationAttribute)) { sessionFixationAttribute = OPT_SESSION_FIXATION_MIGRATE_SESSION; } @@ -512,12 +753,12 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { if (sessionControlEnabled) { sessionFixationFilter.addPropertyReference("sessionRegistry", BeanIds.SESSION_REGISTRY); } - return sessionFixationFilter.getBeanDefinition(); + return (RootBeanDefinition) sessionFixationFilter.getBeanDefinition(); } return null; } - private FilterAndEntryPoint createFormLoginFilter(Element element, ParserContext pc, boolean autoConfig, boolean allowSessionCreation) { + private FilterAndEntryPoint createFormLoginFilter(Element element, ParserContext pc, boolean autoConfig, boolean allowSessionCreation, RootBeanDefinition sfpf) { RootBeanDefinition formLoginFilter = null; RootBeanDefinition formLoginEntryPoint = null; @@ -527,7 +768,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check", AUTHENTICATION_PROCESSING_FILTER_CLASS); - parser.parse(formLoginElt, pc); + parser.parse(formLoginElt, pc, sfpf); formLoginFilter = parser.getFilterBean(); formLoginEntryPoint = parser.getEntryPointBean(); } @@ -539,7 +780,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { return new FilterAndEntryPoint(formLoginFilter, formLoginEntryPoint); } - private FilterAndEntryPoint createOpenIDLoginFilter(Element element, ParserContext pc, boolean autoConfig, boolean allowSessionCreation) { + private FilterAndEntryPoint createOpenIDLoginFilter(Element element, ParserContext pc, boolean autoConfig, boolean allowSessionCreation, RootBeanDefinition sfpf) { Element openIDLoginElt = DomUtils.getChildElementByTagName(element, Elements.OPENID_LOGIN); RootBeanDefinition openIDFilter = null; RootBeanDefinition openIDEntryPoint = null; @@ -548,7 +789,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check", OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS); - parser.parse(openIDLoginElt, pc); + parser.parse(openIDLoginElt, pc, sfpf); openIDFilter = parser.getFilterBean(); openIDEntryPoint = parser.getEntryPointBean(); @@ -575,22 +816,22 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { class FilterAndEntryPoint { RootBeanDefinition filter; - RootBeanDefinition entryPoint; + RootBeanDefinition entryPoint; - public FilterAndEntryPoint(RootBeanDefinition filter, RootBeanDefinition entryPoint) { - this.filter = filter; - this.entryPoint = entryPoint; - } + public FilterAndEntryPoint(RootBeanDefinition filter, RootBeanDefinition entryPoint) { + this.filter = filter; + this.entryPoint = entryPoint; + } } - private void selectEntryPoint(Element element, ParserContext pc, FilterAndEntryPoint form, FilterAndEntryPoint openID) { + private BeanMetadataElement selectEntryPoint(Element element, ParserContext pc, FilterAndEntryPoint basic, FilterAndEntryPoint form, FilterAndEntryPoint openID, FilterAndEntryPoint x509) { // We need to establish the main entry point. // First check if a custom entry point bean is set String customEntryPoint = element.getAttribute(ATT_ENTRY_POINT_REF); if (StringUtils.hasText(customEntryPoint)) { - pc.getRegistry().registerAlias(customEntryPoint, BeanIds.MAIN_ENTRY_POINT); - return; +// pc.getRegistry().registerAlias(customEntryPoint, BeanIds.MAIN_ENTRY_POINT); + return new RuntimeBeanReference(customEntryPoint); } Element basicAuthElt = DomUtils.getChildElementByTagName(element, Elements.BASIC_AUTH); @@ -598,8 +839,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { Element openIDLoginElt = DomUtils.getChildElementByTagName(element, Elements.OPENID_LOGIN); // Basic takes precedence if explicit element is used and no others are configured if (basicAuthElt != null && formLoginElt == null && openIDLoginElt == null) { - pc.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT); - return; + //pc.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT); + return basic.entryPoint; } // If formLogin has been enabled either through an element or auto-config, then it is used if no openID login page @@ -607,37 +848,38 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { String openIDLoginPage = getLoginFormUrl(openID.entryPoint); if (form.filter != null && openIDLoginPage == null) { - pc.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT); - return; + //pc.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT); + return form.entryPoint; } // Otherwise use OpenID if enabled if (openID.filter != null && form.filter == null) { - pc.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT); - return; + //pc.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT); + return openID.entryPoint; } // If X.509 has been enabled, use the preauth entry point. if (DomUtils.getChildElementByTagName(element, Elements.X509) != null) { - pc.getRegistry().registerAlias(BeanIds.PRE_AUTH_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT); - return; + //pc.getRegistry().registerAlias(BeanIds.PRE_AUTH_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT); + return x509.entryPoint; } 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 " + "specify a custom AuthenticationEntryPoint with the '" + ATT_ENTRY_POINT_REF+ "' attribute ", pc.extractSource(element)); + return null; } private String getLoginFormUrl(RootBeanDefinition entryPoint) { - if (entryPoint == null) { - return null; - } + if (entryPoint == null) { + return null; + } - PropertyValues pvs = entryPoint.getPropertyValues(); - PropertyValue pv = pvs.getPropertyValue("loginFormUrl"); + PropertyValues pvs = entryPoint.getPropertyValues(); + PropertyValue pv = pvs.getPropertyValue("loginFormUrl"); if (pv == null) { - return null; + return null; } return (String) pv.getValue(); @@ -649,7 +891,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { String formLoginPage = getLoginFormUrl(form.entryPoint); // If the login URL is the default one, then it is assumed not to have been set explicitly if (DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL == formLoginPage) { - formLoginPage = null; + formLoginPage = null; } String openIDLoginPage = getLoginFormUrl(openID.entryPoint); @@ -714,12 +956,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { * Parses the intercept-url elements and populates the FilterChainProxy's filter chain Map and the * map used to create the FilterInvocationDefintionSource for the FilterSecurityInterceptor. */ - @SuppressWarnings("unchecked") - void parseInterceptUrlsForChannelSecurityAndEmptyFilterChains(List urlElts, Map filterChainMap, Map channelRequestMap, + void parseInterceptUrlsForChannelSecurityAndEmptyFilterChains(List urlElts, Map> filterChainMap, Map> channelRequestMap, boolean useLowerCasePaths, ParserContext parserContext) { - ConfigAttributeEditor editor = new ConfigAttributeEditor(); - for (Element urlElt : urlElts) { String path = urlElt.getAttribute(ATT_PATH_PATTERN); @@ -746,8 +985,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { parserContext.getReaderContext().error("Unsupported channel " + requiredChannel, urlElt); } - editor.setAsText(channelConfigAttribute); - channelRequestMap.put(new RequestKey(path), editor.getValue()); + channelRequestMap.put(new RequestKey(path), + SecurityConfig.createList((StringUtils.commaDelimitedListToStringArray(channelConfigAttribute)))); } String filters = urlElt.getAttribute(ATT_FILTERS); @@ -758,7 +997,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { "filters attribute", urlElt); } - filterChainMap.put(path, Collections.EMPTY_LIST); + List noFilters = Collections.emptyList(); + filterChainMap.put(path, noFilters); } } } diff --git a/config/src/main/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecorator.java b/config/src/main/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecorator.java index af97159a78..9026599f16 100644 --- a/config/src/main/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecorator.java +++ b/config/src/main/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecorator.java @@ -31,7 +31,7 @@ public class InterceptMethodsBeanDefinitionDecorator implements BeanDefinitionDe private BeanDefinitionDecorator delegate = new InternalInterceptMethodsBeanDefinitionDecorator(); public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) { - ConfigUtils.registerProviderManagerIfNecessary(parserContext); + ConfigUtils.registerProviderManagerIfNecessary(parserContext, (Element) node); ConfigUtils.registerDefaultMethodAccessManagerIfNecessary(parserContext); return delegate.decorate(node, definition, parserContext); diff --git a/config/src/main/java/org/springframework/security/config/NamespaceAuthenticationManager.java b/config/src/main/java/org/springframework/security/config/NamespaceAuthenticationManager.java index 9490a0b8fc..5fe2473aa4 100644 --- a/config/src/main/java/org/springframework/security/config/NamespaceAuthenticationManager.java +++ b/config/src/main/java/org/springframework/security/config/NamespaceAuthenticationManager.java @@ -20,8 +20,8 @@ import org.springframework.util.Assert; * @since 2.0.4 */ public class NamespaceAuthenticationManager extends ProviderManager implements BeanFactoryAware { - BeanFactory beanFactory; - List providerBeanNames; + private BeanFactory beanFactory; + private List providerBeanNames; public void setBeanFactory(BeanFactory beanFactory) { this.beanFactory = beanFactory; diff --git a/config/src/main/java/org/springframework/security/config/OrderedFilterBeanDefinitionDecorator.java b/config/src/main/java/org/springframework/security/config/OrderedFilterBeanDefinitionDecorator.java index bfc679c05e..641da43535 100644 --- a/config/src/main/java/org/springframework/security/config/OrderedFilterBeanDefinitionDecorator.java +++ b/config/src/main/java/org/springframework/security/config/OrderedFilterBeanDefinitionDecorator.java @@ -15,7 +15,6 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.BeanDefinitionDecorator; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.core.Ordered; -import org.springframework.security.web.FilterChainOrder; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.w3c.dom.Element; @@ -47,7 +46,7 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor wrapper.addPropertyValue("order", order); } - ConfigUtils.addHttpFilter(parserContext, wrapper.getBeanDefinition()); +// ConfigUtils.addHttpFilter(parserContext, wrapper.getBeanDefinition()); return holder; } diff --git a/config/src/main/java/org/springframework/security/config/RememberMeBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/RememberMeBeanDefinitionParser.java index e058b7686f..411283fd35 100644 --- a/config/src/main/java/org/springframework/security/config/RememberMeBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/RememberMeBeanDefinitionParser.java @@ -4,6 +4,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; 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.CompositeComponentDefinition; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; @@ -33,24 +35,18 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser { protected final Log logger = LogFactory.getLog(getClass()); private String servicesName; - public BeanDefinition parse(Element element, ParserContext parserContext) { - String tokenRepository = null; - String dataSource = null; - String key = null; - Object source = null; - String userServiceRef = null; - String rememberMeServicesRef = null; - String tokenValiditySeconds = null; + public BeanDefinition parse(Element element, ParserContext pc) { + CompositeComponentDefinition compositeDef = + new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element)); + pc.pushContainingComponent(compositeDef); - if (element != null) { - tokenRepository = element.getAttribute(ATT_TOKEN_REPOSITORY); - dataSource = element.getAttribute(ATT_DATA_SOURCE); - key = element.getAttribute(ATT_KEY); - userServiceRef = element.getAttribute(ATT_USER_SERVICE_REF); - rememberMeServicesRef = element.getAttribute(ATT_SERVICES_REF); - tokenValiditySeconds = element.getAttribute(ATT_TOKEN_VALIDITY); - source = parserContext.extractSource(element); - } + String tokenRepository = element.getAttribute(ATT_TOKEN_REPOSITORY); + String dataSource = element.getAttribute(ATT_DATA_SOURCE); + String key = element.getAttribute(ATT_KEY); + String userServiceRef = element.getAttribute(ATT_USER_SERVICE_REF); + String rememberMeServicesRef = element.getAttribute(ATT_SERVICES_REF); + String tokenValiditySeconds = element.getAttribute(ATT_TOKEN_VALIDITY); + Object source = pc.extractSource(element); if (!StringUtils.hasText(key)) { key = DEF_KEY; @@ -65,12 +61,12 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser { boolean tokenValiditySet = StringUtils.hasText(tokenValiditySeconds); if (servicesRefSet && (dataSourceSet || tokenRepoSet || userServiceSet || tokenValiditySet)) { - parserContext.getReaderContext().error(ATT_SERVICES_REF + " can't be used in combination with attributes " + pc.getReaderContext().error(ATT_SERVICES_REF + " can't be used in combination with attributes " + ATT_TOKEN_REPOSITORY + "," + ATT_DATA_SOURCE + ", " + ATT_USER_SERVICE_REF + " or " + ATT_TOKEN_VALIDITY, source); } if (dataSourceSet && tokenRepoSet) { - parserContext.getReaderContext().error("Specify " + ATT_TOKEN_REPOSITORY + " or " + + pc.getReaderContext().error("Specify " + ATT_TOKEN_REPOSITORY + " or " + ATT_DATA_SOURCE +" but not both", source); } @@ -100,23 +96,27 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser { if (tokenValiditySet) { Integer tokenValidity = new Integer(tokenValiditySeconds); if (tokenValidity.intValue() < 0 && isPersistent) { - parserContext.getReaderContext().error(ATT_TOKEN_VALIDITY + " cannot be negative if using" + + pc.getReaderContext().error(ATT_TOKEN_VALIDITY + " cannot be negative if using" + " a persistent remember-me token repository", source); } services.getPropertyValues().addPropertyValue("tokenValiditySeconds", tokenValidity); } services.setSource(source); services.getPropertyValues().addPropertyValue(ATT_KEY, key); - parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services); + pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services); + pc.registerBeanComponent(new BeanComponentDefinition(services, BeanIds.REMEMBER_ME_SERVICES)); servicesName = BeanIds.REMEMBER_ME_SERVICES; } else { servicesName = rememberMeServicesRef; - parserContext.getRegistry().registerAlias(rememberMeServicesRef, BeanIds.REMEMBER_ME_SERVICES); + pc.getRegistry().registerAlias(rememberMeServicesRef, BeanIds.REMEMBER_ME_SERVICES); } - registerProvider(parserContext, source, key); + registerProvider(pc, source, key); - return createFilter(parserContext, source); + BeanDefinition filter = createFilter(pc, source); + pc.popAndRegisterContainingComponent(); + + return filter; } String getServicesName() { diff --git a/config/src/main/java/org/springframework/security/config/RememberMeServicesInjectionBeanPostProcessor.java b/config/src/main/java/org/springframework/security/config/RememberMeServicesInjectionBeanPostProcessor.java index a2d92a59a2..bded9fd714 100644 --- a/config/src/main/java/org/springframework/security/config/RememberMeServicesInjectionBeanPostProcessor.java +++ b/config/src/main/java/org/springframework/security/config/RememberMeServicesInjectionBeanPostProcessor.java @@ -26,23 +26,23 @@ public class RememberMeServicesInjectionBeanPostProcessor implements BeanPostPro private ListableBeanFactory beanFactory; public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - if (bean instanceof AbstractAuthenticationProcessingFilter) { - AbstractAuthenticationProcessingFilter pf = (AbstractAuthenticationProcessingFilter) bean; - - if (pf.getRememberMeServices() == null) { - logger.info("Setting RememberMeServices on bean " + beanName); - pf.setRememberMeServices(getRememberMeServices()); - } - } else if (BeanIds.BASIC_AUTHENTICATION_FILTER.equals(beanName)) { - // NB: For remember-me to be sent back, a user must submit a "_spring_security_remember_me" with their login request. - // Most of the time a user won't present such a parameter with their BASIC authentication request. - // In the future we might support setting the AbstractRememberMeServices.alwaysRemember = true, but I am reluctant to - // do so because it seems likely to lead to lower security for 99.99% of users if they set the property to true. - - BasicProcessingFilter bf = (BasicProcessingFilter) bean; - logger.info("Setting RememberMeServices on bean " + beanName); - bf.setRememberMeServices(getRememberMeServices()); - } +// if (bean instanceof AbstractAuthenticationProcessingFilter) { +// AbstractAuthenticationProcessingFilter pf = (AbstractAuthenticationProcessingFilter) bean; +// +// if (pf.getRememberMeServices() == null) { +// logger.info("Setting RememberMeServices on bean " + beanName); +// pf.setRememberMeServices(getRememberMeServices()); +// } +// } else if (BeanIds.BASIC_AUTHENTICATION_FILTER.equals(beanName)) { +// // NB: For remember-me to be sent back, a user must submit a "_spring_security_remember_me" with their login request. +// // Most of the time a user won't present such a parameter with their BASIC authentication request. +// // In the future we might support setting the AbstractRememberMeServices.alwaysRemember = true, but I am reluctant to +// // do so because it seems likely to lead to lower security for 99.99% of users if they set the property to true. +// +// BasicProcessingFilter bf = (BasicProcessingFilter) bean; +// logger.info("Setting RememberMeServices on bean " + beanName); +// bf.setRememberMeServices(getRememberMeServices()); +// } return bean; } diff --git a/config/src/main/java/org/springframework/security/config/X509BeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/X509BeanDefinitionParser.java index 49479ea9d8..1aeb55950a 100644 --- a/config/src/main/java/org/springframework/security/config/X509BeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/X509BeanDefinitionParser.java @@ -27,13 +27,10 @@ public class X509BeanDefinitionParser implements BeanDefinitionParser { public static final String ATT_REGEX = "subject-principal-regex"; public static final String ATT_USER_SERVICE_REF = "user-service-ref"; - public BeanDefinition parse(Element element, ParserContext parserContext) { + public RootBeanDefinition parse(Element element, ParserContext parserContext) { BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(X509PreAuthenticatedProcessingFilter.class); - RootBeanDefinition entryPoint = new RootBeanDefinition(Http403ForbiddenEntryPoint.class); - Object source = parserContext.extractSource(element); filterBuilder.getRawBeanDefinition().setSource(source); - entryPoint.setSource(source); String regex = element.getAttribute(ATT_REGEX); @@ -57,10 +54,8 @@ public class X509BeanDefinitionParser implements BeanDefinitionParser { provider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService", preAuthUserService); } - parserContext.getRegistry().registerBeanDefinition(BeanIds.PRE_AUTH_ENTRY_POINT, entryPoint); - filterBuilder.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER)); - return filterBuilder.getBeanDefinition(); + return (RootBeanDefinition) filterBuilder.getBeanDefinition(); } } diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-3.0.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-3.0.rnc index a1539d882d..341a5d5da5 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-3.0.rnc +++ b/config/src/main/resources/org/springframework/security/config/spring-security-3.0.rnc @@ -240,7 +240,7 @@ protect-pointcut.attlist &= http = ## Container element for HTTP security configuration - element http {http.attlist, (intercept-url+ & access-denied-handler? & form-login? & openid-login? & x509? & http-basic? & logout? & concurrent-session-control? & remember-me? & anonymous? & port-mappings) } + element http {http.attlist, (intercept-url+ & access-denied-handler? & form-login? & openid-login? & x509? & http-basic? & logout? & concurrent-session-control? & remember-me? & anonymous? & port-mappings & custom-filter*) } http.attlist &= ## Automatically registers a login form, BASIC authentication, anonymous authentication, logout services, remember-me and servlet-api-integration. If set to "true", all of these capabilities are added (although you can still customize the configuration of each by providing the respective element). If unspecified, defaults to "false". attribute auto-config {boolean}? @@ -553,7 +553,14 @@ any-user-service = user-service | jdbc-user-service | ldap-user-service custom-filter = ## Used to indicate that a filter bean declaration should be incorporated into the security filter chain. If neither the 'after' or 'before' options are supplied, then the filter must implement the Ordered interface directly. - element custom-filter {after | before | position}? + element custom-filter {custom-filter.attlist} + +custom-filter.attlist &= + ref + +custom-filter.attlist &= + (after | before | position) + after = ## The filter immediately after which the custom-filter should be placed in the chain. This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. The filter names map to specific Spring Security implementation filters. attribute after {named-security-filter} @@ -565,7 +572,6 @@ position = attribute position {named-security-filter} - named-security-filter = "FIRST" | "CHANNEL_FILTER" | "CONCURRENT_SESSION_FILTER" | "SESSION_CONTEXT_INTEGRATION_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_PROCESSING_FILTER" | "AUTHENTICATION_PROCESSING_FILTER" | "OPENID_PROCESSING_FILTER" |"BASIC_PROCESSING_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "NTLM_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST" diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-3.0.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-3.0.xsd index 79fa758e9e..271323e29b 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-3.0.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-3.0.xsd @@ -1,1690 +1,2688 @@ - + + + + - Defines the hashing algorithm used on user passwords. We recommend - strongly against using MD4, as it is a very weak hashing - algorithm. + + Defines the hashing algorithm used on user passwords. We recommend strongly against using MD4, as it is a very weak hashing algorithm. + + + + + + + + + + + + + + + + + + Whether a string should be base64 encoded + + + + + + + + + + + + - Defines the type of pattern used to specify URL paths (either JDK - 1.4-compatible regular expressions, or Apache Ant expressions). Defaults to "ant" if - unspecified. + + Defines the type of pattern used to specify URL paths (either JDK 1.4-compatible regular expressions, or Apache Ant expressions). Defaults to "ant" if unspecified. + + + + + + + + + + + + - Specifies an IP port number. Used to configure an embedded LDAP - server, for example. + + Specifies an IP port number. Used to configure an embedded LDAP server, for example. + + + + + + + Specifies a URL. + + + + + + - A bean identifier, used for referring to the bean elsewhere in the - context. + + A bean identifier, used for referring to the bean elsewhere in the context. + + + + + + + Defines a reference to a Spring bean Id. + + + + + + - Defines a reference to a cache for use with a - UserDetailsService. + + Defines a reference to a cache for use with a UserDetailsService. + + + + + + - A reference to a user-service (or UserDetailsService bean) - Id + + A reference to a user-service (or UserDetailsService bean) Id + + + + + + + A reference to a DataSource bean + + + + + + + + Defines a reference to a Spring bean Id. + + + + - Defines the hashing algorithm used on user passwords. We recommend - strongly against using MD4, as it is a very weak hashing - algorithm. + + Defines the hashing algorithm used on user passwords. We recommend strongly against using MD4, as it is a very weak hashing algorithm. + + + + + + + + + + + + + + + + Whether a string should be base64 encoded + + + + + + + + + + + + + - A property of the UserDetails object which will be used as salt by a - password encoder. Typically something like "username" might be used. - + + A property of the UserDetails object which will be used as salt by a password encoder. Typically something like "username" might be used. + + + + + + - A single value that will be used as the salt for a password encoder. - + + A single value that will be used as the salt for a password encoder. + + + + + + + + + + + + - A non-empty string prefix that will be added to role strings loaded - from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases - where the default is non-empty. + + A non-empty string prefix that will be added to role strings loaded from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is non-empty. + + + + + + - Enables the use of expressions in the 'access' attributes in - <intercept-url> elements rather than the traditional list of - configuration attributes. Defaults to 'false'. If enabled, each attribute should - contain a single boolean expression. If the expression evaluates to 'true', access - will be granted. + + Enables the use of expressions in the 'access' attributes in <intercept-url> elements rather than the traditional list of configuration attributes. Defaults to 'false'. If enabled, each attribute should contain a single boolean expression. If the expression evaluates to 'true', access will be granted. + + + + - Defines an LDAP server location or starts an embedded server. The url - indicates the location of a remote server. If no url is given, an embedded server will - be started, listening on the supplied port number. The port is optional and defaults to - 33389. A Spring LDAP ContextSource bean will be registered for the server with the id - supplied. + + Defines an LDAP server location or starts an embedded server. The url indicates the location of a remote server. If no url is given, an embedded server will be started, listening on the supplied port number. The port is optional and defaults to 33389. A Spring LDAP ContextSource bean will be registered for the server with the id supplied. + + + + + + - A bean identifier, used for referring to the bean elsewhere in the - context. + + A bean identifier, used for referring to the bean elsewhere in the context. + + + + + Specifies a URL. + + + + - Specifies an IP port number. Used to configure an embedded LDAP - server, for example. + + Specifies an IP port number. Used to configure an embedded LDAP server, for example. + + + + - Username (DN) of the "manager" user identity which will be used to - authenticate to a (non-embedded) LDAP server. If omitted, anonymous access will be - used. + + Username (DN) of the "manager" user identity which will be used to authenticate to a (non-embedded) LDAP server. If omitted, anonymous access will be used. + + + + + The password for the manager DN. + + + + - Explicitly specifies an ldif file resource to load into an embedded - LDAP server + + Explicitly specifies an ldif file resource to load into an embedded LDAP server + + + + - Optional root suffix for the embedded LDAP server. Default is - "dc=springframework,dc=org" + + Optional root suffix for the embedded LDAP server. Default is "dc=springframework,dc=org" + + + + + + - The optional server to use. If omitted, and a default LDAP server is - registered (using <ldap-server> with no Id), that server will be used. - + + The optional server to use. If omitted, and a default LDAP server is registered (using <ldap-server> with no Id), that server will be used. + + + + + + - Group search filter. Defaults to (uniqueMember={0}). The substituted - parameter is the DN of the user. + + Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user. + + + + + + - Search base for group membership searches. Defaults to "" (searching - from the root). + + Search base for group membership searches. Defaults to "" (searching from the root). + + + + + + - The LDAP filter used to search for users (optional). For example - "(uid={0})". The substituted parameter is the user's login name. + + The LDAP filter used to search for users (optional). For example "(uid={0})". The substituted parameter is the user's login name. + + + + + + - Search base for user searches. Defaults to "". Only used with a - 'user-search-filter'. + + Search base for user searches. Defaults to "". Only used with a 'user-search-filter'. + + + + + + - The LDAP attribute name which contains the role name which will be - used within Spring Security. Defaults to "cn". + + The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn". + + + + + + - Allows the objectClass of the user entry to be specified. If set, the - framework will attempt to load standard attributes for the defined class into the - returned UserDetails object + + Allows the objectClass of the user entry to be specified. If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object + + + + + + + + + + + + - Allows explicit customization of the loaded user object by specifying - a UserDetailsContextMapper bean which will be called with the context information - from the user's directory entry + + Allows explicit customization of the loaded user object by specifying a UserDetailsContextMapper bean which will be called with the context information from the user's directory entry + + + + + + + + + - A bean identifier, used for referring to the bean elsewhere in the - context. + + A bean identifier, used for referring to the bean elsewhere in the context. + + + + - The optional server to use. If omitted, and a default LDAP server is - registered (using <ldap-server> with no Id), that server will be used. - + + The optional server to use. If omitted, and a default LDAP server is registered (using <ldap-server> with no Id), that server will be used. + + + + - The LDAP filter used to search for users (optional). For example - "(uid={0})". The substituted parameter is the user's login name. + + The LDAP filter used to search for users (optional). For example "(uid={0})". The substituted parameter is the user's login name. + + + + - Search base for user searches. Defaults to "". Only used with a - 'user-search-filter'. + + Search base for user searches. Defaults to "". Only used with a 'user-search-filter'. + + + + - Group search filter. Defaults to (uniqueMember={0}). The substituted - parameter is the DN of the user. + + Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user. + + + + - Search base for group membership searches. Defaults to "" (searching - from the root). + + Search base for group membership searches. Defaults to "" (searching from the root). + + + + - The LDAP attribute name which contains the role name which will be - used within Spring Security. Defaults to "cn". + + The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn". + + + + - Defines a reference to a cache for use with a - UserDetailsService. + + Defines a reference to a cache for use with a UserDetailsService. + + + + - A non-empty string prefix that will be added to role strings loaded - from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases - where the default is non-empty. + + A non-empty string prefix that will be added to role strings loaded from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is non-empty. + + + + - Allows the objectClass of the user entry to be specified. If set, the - framework will attempt to load standard attributes for the defined class into the - returned UserDetails object + + Allows the objectClass of the user entry to be specified. If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object + + + + + + + + + + - Allows explicit customization of the loaded user object by specifying - a UserDetailsContextMapper bean which will be called with the context information - from the user's directory entry + + Allows explicit customization of the loaded user object by specifying a UserDetailsContextMapper bean which will be called with the context information from the user's directory entry + + + + + Sets up an ldap authentication provider + + + - Specifies that an LDAP provider should use an LDAP compare - operation of the user's password to authenticate the user + + Specifies that an LDAP provider should use an LDAP compare operation of the user's password to authenticate the user + + + - element which defines a password encoding strategy. - Used by an authentication provider to convert submitted passwords to - hashed versions, for example. + + element which defines a password encoding strategy. Used by an authentication provider to convert submitted passwords to hashed versions, for example. + + + - Password salting strategy. A system-wide - constant or a property from the UserDetails object can be - used. + + Password salting strategy. A system-wide constant or a property from the UserDetails object can be used. + + + - A property of the UserDetails object - which will be used as salt by a password encoder. - Typically something like "username" might be used. - + + A property of the UserDetails object which will be used as salt by a password encoder. Typically something like "username" might be used. + + + + - A single value that will be used as the - salt for a password encoder. + + A single value that will be used as the salt for a password encoder. + + + + - Defines a reference to a Spring bean - Id. + + Defines a reference to a Spring bean Id. + + + + + + + + + + + + + + + - The optional server to use. If omitted, and a default LDAP server is - registered (using <ldap-server> with no Id), that server will be used. - + + The optional server to use. If omitted, and a default LDAP server is registered (using <ldap-server> with no Id), that server will be used. + + + + - Search base for user searches. Defaults to "". Only used with a - 'user-search-filter'. + + Search base for user searches. Defaults to "". Only used with a 'user-search-filter'. + + + + - The LDAP filter used to search for users (optional). For example - "(uid={0})". The substituted parameter is the user's login name. + + The LDAP filter used to search for users (optional). For example "(uid={0})". The substituted parameter is the user's login name. + + + + - Search base for group membership searches. Defaults to "" (searching - from the root). + + Search base for group membership searches. Defaults to "" (searching from the root). + + + + - Group search filter. Defaults to (uniqueMember={0}). The substituted - parameter is the DN of the user. + + Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user. + + + + - The LDAP attribute name which contains the role name which will be - used within Spring Security. Defaults to "cn". + + The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn". + + + + - A specific pattern used to build the user's DN, for example - "uid={0},ou=people". The key "{0}" must be present and will be substituted with the - username. + + A specific pattern used to build the user's DN, for example "uid={0},ou=people". The key "{0}" must be present and will be substituted with the username. + + + + - A non-empty string prefix that will be added to role strings loaded - from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases - where the default is non-empty. + + A non-empty string prefix that will be added to role strings loaded from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is non-empty. + + + + - Allows the objectClass of the user entry to be specified. If set, the - framework will attempt to load standard attributes for the defined class into the - returned UserDetails object + + Allows the objectClass of the user entry to be specified. If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object + + + + + + + + + + - Allows explicit customization of the loaded user object by specifying - a UserDetailsContextMapper bean which will be called with the context information - from the user's directory entry + + Allows explicit customization of the loaded user object by specifying a UserDetailsContextMapper bean which will be called with the context information from the user's directory entry + + + + + + + - The attribute in the directory which contains the user password. - Defaults to "userPassword". + + The attribute in the directory which contains the user password. Defaults to "userPassword". + + + + - Defines the hashing algorithm used on user passwords. We recommend - strongly against using MD4, as it is a very weak hashing - algorithm. + + Defines the hashing algorithm used on user passwords. We recommend strongly against using MD4, as it is a very weak hashing algorithm. + + + + + + + + + + + + + + + - Can be used inside a bean definition to add a security interceptor to the - bean and set up access configuration attributes for the bean's - methods + + Can be used inside a bean definition to add a security interceptor to the bean and set up access configuration attributes for the bean's methods + + + - Defines a protected method and the access control configuration - attributes that apply to it. We strongly advise you NOT to mix "protect" - declarations with any services provided - "global-method-security". + + Defines a protected method and the access control configuration attributes that apply to it. We strongly advise you NOT to mix "protect" declarations with any services provided "global-method-security". + + + + + + + + + - Optional AccessDecisionManager bean ID to be used by the created - method security interceptor. + + Optional AccessDecisionManager bean ID to be used by the created method security interceptor. + + + + + + + + A method name + + + + - Access configuration attributes list that applies to the method, e.g. - "ROLE_A,ROLE_B". + + Access configuration attributes list that applies to the method, e.g. "ROLE_A,ROLE_B". + + + + - Provides method security for all beans registered in the Spring - application context. Specifically, beans will be scanned for matches with the ordered - list of "protect-pointcut" sub-elements, Spring Security annotations and/or. Where there - is a match, the beans will automatically be proxied and security authorization applied - to the methods accordingly. If you use and enable all four sources of method security - metadata (ie "protect-pointcut" declarations, expression annotations, @Secured and also - JSR250 security annotations), the metadata sources will be queried in that order. In - practical terms, this enables you to use XML to override method security metadata - expressed in annotations. If using annotations, the order of precedence is EL-based - (@PreAuthorize etc.), @Secured and finally JSR-250. + + Provides method security for all beans registered in the Spring application context. Specifically, beans will be scanned for matches with the ordered list of "protect-pointcut" sub-elements, Spring Security annotations and/or. Where there is a match, the beans will automatically be proxied and security authorization applied to the methods accordingly. If you use and enable all four sources of method security metadata (ie "protect-pointcut" declarations, expression annotations, @Secured and also JSR250 security annotations), the metadata sources will be queried in that order. In practical terms, this enables you to use XML to override method security metadata expressed in annotations. If using annotations, the order of precedence is EL-based (@PreAuthorize etc.), @Secured and finally JSR-250. + + + + - Allows the default expression-based mechanism for handling - Spring Security's pre and post invocation annotations (@PreFilter, - @PreAuthorize, @PostFilter, @PostAuthorize) to be replace entirely. Only - applies if these annotations are enabled. + + Allows the default expression-based mechanism for handling Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) to be replace entirely. Only applies if these annotations are enabled. + + + - Defines the PrePostInvocationAttributeFactory - instance which is used to generate pre and post invocation metadata - from the annotated methods. + + Defines the PrePostInvocationAttributeFactory instance which is used to generate pre and post invocation metadata from the annotated methods. + + + + + + + + + + + + - Defines the SecurityExpressionHandler instance which will be - used if expression-based access-control is enabled. A default implementation - (with no ACL support) will be used if not supplied. + + Defines the SecurityExpressionHandler instance which will be used if expression-based access-control is enabled. A default implementation (with no ACL support) will be used if not supplied. + + + + + - Defines a protected pointcut and the access control - configuration attributes that apply to it. Every bean registered in the Spring - application context that provides a method that matches the pointcut will - receive security authorization. + + Defines a protected pointcut and the access control configuration attributes that apply to it. Every bean registered in the Spring application context that provides a method that matches the pointcut will receive security authorization. + + + + + + + + + - Specifies whether the use of Spring Security's pre and post invocation - annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) should be - enabled for this application context. Defaults to "disabled". + + Specifies whether the use of Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) should be enabled for this application context. Defaults to "disabled". + + + + + + + + + + - Specifies whether the use of Spring Security's @Secured annotations - should be enabled for this application context. Defaults to - "disabled". + + Specifies whether the use of Spring Security's @Secured annotations should be enabled for this application context. Defaults to "disabled". + + + + + + + + + + - Specifies whether JSR-250 style attributes are to be used (for example - "RolesAllowed"). This will require the javax.annotation.security classes on the - classpath. Defaults to "disabled". + + Specifies whether JSR-250 style attributes are to be used (for example "RolesAllowed"). This will require the javax.annotation.security classes on the classpath. Defaults to "disabled". + + + + + + + + + + - Optional AccessDecisionManager bean ID to override the default used - for method security. + + Optional AccessDecisionManager bean ID to override the default used for method security. + + + + - Optional RunAsmanager implementation which will be used by the - configured MethodSecurityInterceptor + + Optional RunAsmanager implementation which will be used by the configured MethodSecurityInterceptor + + + + + + + + + - Used to decorate an AfterInvocationProvider to specify that it should be - used with method security. + + Used to decorate an AfterInvocationProvider to specify that it should be used with method security. + + + + + - An AspectJ expression, including the 'execution' keyword. For example, - 'execution(int com.foo.TargetObject.countLength(String))' (without the - quotes). + + An AspectJ expression, including the 'execution' keyword. For example, 'execution(int com.foo.TargetObject.countLength(String))' (without the quotes). + + + + - Access configuration attributes list that applies to all methods - matching the pointcut, e.g. "ROLE_A,ROLE_B" + + Access configuration attributes list that applies to all methods matching the pointcut, e.g. "ROLE_A,ROLE_B" + + + + + Container element for HTTP security configuration + + + - Specifies the access attributes and/or filter list for a - particular set of URLs. + + Specifies the access attributes and/or filter list for a particular set of URLs. + + + + - Defines the access-denied strategy that should be used. An - access denied page can be defined or a reference to an AccessDeniedHandler - instance. + + Defines the access-denied strategy that should be used. An access denied page can be defined or a reference to an AccessDeniedHandler instance. + + + + - Sets up a form login configuration for authentication with a - username and password + + Sets up a form login configuration for authentication with a username and password + + + + - Sets up form login for authentication with an Open ID - identity + + Sets up form login for authentication with an Open ID identity + + + + - A reference to a user-service (or UserDetailsService bean) - Id + + A reference to a user-service (or UserDetailsService bean) Id + + + + + Adds support for X.509 client authentication. + + + + - Adds support for basic authentication (this is an element to - permit future expansion, such as supporting an "ignoreFailure" - attribute) + + Adds support for basic authentication (this is an element to permit future expansion, such as supporting an "ignoreFailure" attribute) + + - Incorporates a logout processing filter. Most web applications - require a logout filter, although you may not require one if you write a - controller to provider similar logic. + + Incorporates a logout processing filter. Most web applications require a logout filter, although you may not require one if you write a controller to provider similar logic. + + + + - Adds support for concurrent session control, allowing limits to - be placed on the number of sessions a user can have. + + Adds support for concurrent session control, allowing limits to be placed on the number of sessions a user can have. + + + + - Sets up remember-me authentication. If used with the "key" - attribute (or no attributes) the cookie-only implementation will be used. - Specifying "token-repository-ref" or "remember-me-data-source-ref" will use the - more secure, persisten token approach. + + Sets up remember-me authentication. If used with the "key" attribute (or no attributes) the cookie-only implementation will be used. Specifying "token-repository-ref" or "remember-me-data-source-ref" will use the more secure, persisten token approach. + + + + - Adds support for automatically granting all anonymous web - requests a particular principal identity and a corresponding granted - authority. + + Adds support for automatically granting all anonymous web requests a particular principal identity and a corresponding granted authority. + + + + - Defines the list of mappings between http and https ports for - use in redirects + + Defines the list of mappings between http and https ports for use in redirects + + + + + + + + + + + + + + + + - Automatically registers a login form, BASIC authentication, anonymous - authentication, logout services, remember-me and servlet-api-integration. If set to - "true", all of these capabilities are added (although you can still customize the - configuration of each by providing the respective element). If unspecified, defaults - to "false". + + Automatically registers a login form, BASIC authentication, anonymous authentication, logout services, remember-me and servlet-api-integration. If set to "true", all of these capabilities are added (although you can still customize the configuration of each by providing the respective element). If unspecified, defaults to "false". + + + + - Enables the use of expressions in the 'access' attributes in - <intercept-url> elements rather than the traditional list of - configuration attributes. Defaults to 'false'. If enabled, each attribute should - contain a single boolean expression. If the expression evaluates to 'true', access - will be granted. + + Enables the use of expressions in the 'access' attributes in <intercept-url> elements rather than the traditional list of configuration attributes. Defaults to 'false'. If enabled, each attribute should contain a single boolean expression. If the expression evaluates to 'true', access will be granted. + + + + - Controls the eagerness with which an HTTP session is created. If not - set, defaults to "ifRequired". Note that if a custom SecurityContextRepository is set - using security-context-repository-ref, then the only value which can be set is - "always". Otherwise the session creation behaviour will be determined by the - repository bean implementation. + + Controls the eagerness with which an HTTP session is created. If not set, defaults to "ifRequired". Note that if a custom SecurityContextRepository is set using security-context-repository-ref, then the only value which can be set is "always". Otherwise the session creation behaviour will be determined by the repository bean implementation. + + + + + + + + + + + - A reference to a SecurityContextRepository bean. This can be used to - customize how the SecurityContext is stored between requests. + + A reference to a SecurityContextRepository bean. This can be used to customize how the SecurityContext is stored between requests. + + + + - Defines the type of pattern used to specify URL paths (either JDK - 1.4-compatible regular expressions, or Apache Ant expressions). Defaults to "ant" if - unspecified. + + Defines the type of pattern used to specify URL paths (either JDK 1.4-compatible regular expressions, or Apache Ant expressions). Defaults to "ant" if unspecified. + + + + + + + + + + - Whether test URLs should be converted to lower case prior to comparing - with defined path patterns. If unspecified, defaults to "true". + + Whether test URLs should be converted to lower case prior to comparing with defined path patterns. If unspecified, defaults to "true". + + + + - Provides versions of HttpServletRequest security methods such as - isUserInRole() and getPrincipal() which are implemented by accessing the Spring - SecurityContext. Defaults to "true". + + Provides versions of HttpServletRequest security methods such as isUserInRole() and getPrincipal() which are implemented by accessing the Spring SecurityContext. Defaults to "true". + + + + - Optional attribute specifying the ID of the AccessDecisionManager - implementation which should be used for authorizing HTTP requests. + + Optional attribute specifying the ID of the AccessDecisionManager implementation which should be used for authorizing HTTP requests. + + + + - Optional attribute specifying the realm name that will be used for all - authentication features that require a realm name (eg BASIC and Digest - authentication). If unspecified, defaults to "Spring Security - Application". + + Optional attribute specifying the realm name that will be used for all authentication features that require a realm name (eg BASIC and Digest authentication). If unspecified, defaults to "Spring Security Application". + + + + - Indicates whether an existing session should be invalidated when a - user authenticates and a new session started. If set to "none" no change will be - made. "newSession" will create a new empty session. "migrateSession" will create a - new session and copy the session attributes to the new session. Defaults to - "migrateSession". + + Indicates whether an existing session should be invalidated when a user authenticates and a new session started. If set to "none" no change will be made. "newSession" will create a new empty session. "migrateSession" will create a new session and copy the session attributes to the new session. Defaults to "migrateSession". + + + + + + + + + + + - Allows a customized AuthenticationEntryPoint to be - used. + + Allows a customized AuthenticationEntryPoint to be used. + + + + - Corresponds to the observeOncePerRequest property of - FilterSecurityInterceptor. Defaults to "true" + + Corresponds to the observeOncePerRequest property of FilterSecurityInterceptor. Defaults to "true" + + + + - Deprecated in favour of the access-denied-handler - element. + + Deprecated in favour of the access-denied-handler element. + + + + + + + + + + + + + Defines a reference to a Spring bean Id. + + + + - The access denied page that an authenticated user will be redirected - to if they request a page which they don't have the authority to access. - + + The access denied page that an authenticated user will be redirected to if they request a page which they don't have the authority to access. + + + + + + - The access denied page that an authenticated user will be redirected - to if they request a page which they don't have the authority to access. - + + The access denied page that an authenticated user will be redirected to if they request a page which they don't have the authority to access. + + + + + + + - The pattern which defines the URL path. The content will depend on the - type set in the containing http element, so will default to ant path - syntax. + + The pattern which defines the URL path. The content will depend on the type set in the containing http element, so will default to ant path syntax. + + + + - The access configuration attributes that apply for the configured - path. + + The access configuration attributes that apply for the configured path. + + + + - The HTTP Method for which the access configuration attributes should - apply. If not specified, the attributes will apply to any method. + + The HTTP Method for which the access configuration attributes should apply. If not specified, the attributes will apply to any method. + + + + + + + + + + + + + + + - The filter list for the path. Currently can be set to "none" to remove - a path from having any filters applied. The full filter stack (consisting of all - filters created by the namespace configuration, and any added using 'custom-filter'), - will be applied to any other paths. + + The filter list for the path. Currently can be set to "none" to remove a path from having any filters applied. The full filter stack (consisting of all filters created by the namespace configuration, and any added using 'custom-filter'), will be applied to any other paths. + + + + + + + + + - Used to specify that a URL must be accessed over http or https, or - that there is no preference. + + Used to specify that a URL must be accessed over http or https, or that there is no preference. + + + + + + + + + + + + + + - Specifies the URL that will cause a logout. Spring Security will - initialize a filter that responds to this particular URL. Defaults to - /j_spring_security_logout if unspecified. + + Specifies the URL that will cause a logout. Spring Security will initialize a filter that responds to this particular URL. Defaults to /j_spring_security_logout if unspecified. + + + + - Specifies the URL to display once the user has logged out. If not - specified, defaults to /. + + Specifies the URL to display once the user has logged out. If not specified, defaults to /. + + + + - Specifies whether a logout also causes HttpSession invalidation, which - is generally desirable. If unspecified, defaults to true. + + Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true. + + + + + + + - The URL that the login form is posted to. If unspecified, it defaults - to /j_spring_security_check. + + The URL that the login form is posted to. If unspecified, it defaults to /j_spring_security_check. + + + + - The URL that will be redirected to after successful authentication, if - the user's previous action could not be resumed. This generally happens if the user - visits a login page without having first requested a secured operation that triggers - authentication. If unspecified, defaults to the root of the - application. + + The URL that will be redirected to after successful authentication, if the user's previous action could not be resumed. This generally happens if the user visits a login page without having first requested a secured operation that triggers authentication. If unspecified, defaults to the root of the application. + + + + - Whether the user should always be redirected to the default-target-url - after login. + + Whether the user should always be redirected to the default-target-url after login. + + + + - The URL for the login page. If no login URL is specified, Spring - Security will automatically create a login URL at /spring_security_login and a - corresponding filter to render that login URL when requested. + + The URL for the login page. If no login URL is specified, Spring Security will automatically create a login URL at /spring_security_login and a corresponding filter to render that login URL when requested. + + + + - The URL for the login failure page. If no login failure URL is - specified, Spring Security will automatically create a failure login URL at - /spring_security_login?login_error and a corresponding filter to render that login - failure URL when requested. + + The URL for the login failure page. If no login failure URL is specified, Spring Security will automatically create a failure login URL at /spring_security_login?login_error and a corresponding filter to render that login failure URL when requested. + + + + - Reference to an AuthenticationSuccessHandler bean which should be used - to handle a successful authentication request. Should not be used in combination with - default-target-url (or always-use-default-target-url) as the implementation should - always deal with navigation to the subsequent destination + + Reference to an AuthenticationSuccessHandler bean which should be used to handle a successful authentication request. Should not be used in combination with default-target-url (or always-use-default-target-url) as the implementation should always deal with navigation to the subsequent destination + + + + - Reference to an AuthenticationFailureHandler bean which should be used - to handle a failed authentication request. Should not be used in combination with - authentication-failure-url as the implementation should always deal with navigation - to the subsequent destination + + Reference to an AuthenticationFailureHandler bean which should be used to handle a failed authentication request. Should not be used in combination with authentication-failure-url as the implementation should always deal with navigation to the subsequent destination + + + + + - Used to explicitly configure a FilterChainProxy instance with a - FilterChainMap + + Used to explicitly configure a FilterChainProxy instance with a FilterChainMap + + + - Used within filter-chain-map to define a specific URL pattern - and the list of filters which apply to the URLs matching that pattern. When - multiple filter-chain elements are used within a filter-chain-map element, the - most specific patterns must be placed at the top of the list, with most general - ones at the bottom. + + Used within filter-chain-map to define a specific URL pattern and the list of filters which apply to the URLs matching that pattern. When multiple filter-chain elements are used within a filter-chain-map element, the most specific patterns must be placed at the top of the list, with most general ones at the bottom. + + + + + + + + + + + + + + + - Used to explicitly configure a FilterSecurityMetadataSource bean for use - with a FilterSecurityInterceptor. Usually only needed if you are configuring a - FilterChainProxy explicitly, rather than using the <http> element. The - intercept-url elements used should only contain pattern, method and access attributes. - Any others will result in a configuration error. + + Used to explicitly configure a FilterSecurityMetadataSource bean for use with a FilterSecurityInterceptor. Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the <http> element. The intercept-url elements used should only contain pattern, method and access attributes. Any others will result in a configuration error. + + + - Specifies the access attributes and/or filter list for a - particular set of URLs. + + Specifies the access attributes and/or filter list for a particular set of URLs. + + + + + + + + + - Enables the use of expressions in the 'access' attributes in - <intercept-url> elements rather than the traditional list of - configuration attributes. Defaults to 'false'. If enabled, each attribute should - contain a single boolean expression. If the expression evaluates to 'true', access - will be granted. + + Enables the use of expressions in the 'access' attributes in <intercept-url> elements rather than the traditional list of configuration attributes. Defaults to 'false'. If enabled, each attribute should contain a single boolean expression. If the expression evaluates to 'true', access will be granted. + + + + - A bean identifier, used for referring to the bean elsewhere in the - context. + + A bean identifier, used for referring to the bean elsewhere in the context. + + + + + as for http element + + + + - Defines the type of pattern used to specify URL paths (either JDK - 1.4-compatible regular expressions, or Apache Ant expressions). Defaults to "ant" if - unspecified. + + Defines the type of pattern used to specify URL paths (either JDK 1.4-compatible regular expressions, or Apache Ant expressions). Defaults to "ant" if unspecified. + + + + + + + + + + + Deprecated synonym for filter-security-metadata-source + + + - Specifies the access attributes and/or filter list for a - particular set of URLs. + + Specifies the access attributes and/or filter list for a particular set of URLs. + + + + + + + + + + + - The maximum number of sessions a single user can have open at the same - time. Defaults to "1". + + The maximum number of sessions a single user can have open at the same time. Defaults to "1". + + + + - The URL a user will be redirected to if they attempt to use a session - which has been "expired" by the concurrent session controller because they have - logged in again. + + The URL a user will be redirected to if they attempt to use a session which has been "expired" by the concurrent session controller because they have logged in again. + + + + - Specifies that an exception should be raised when a user attempts to - login when they already have the maximum configured sessions open. The default - behaviour is to expire the original session. + + Specifies that an exception should be raised when a user attempts to login when they already have the maximum configured sessions open. The default behaviour is to expire the original session. + + + + - Allows you to define an alias for the SessionRegistry bean in order to - access it in your own configuration + + Allows you to define an alias for the SessionRegistry bean in order to access it in your own configuration + + + + - A reference to an external SessionRegistry implementation which will - be used in place of the standard one. + + A reference to an external SessionRegistry implementation which will be used in place of the standard one. + + + + + + + - The "key" used to identify cookies from a specific token-based - remember-me application. You should set this to a unique value for your - application. + + The "key" used to identify cookies from a specific token-based remember-me application. You should set this to a unique value for your application. + + + + - Reference to a PersistentTokenRepository bean for use with the - persistent token remember-me implementation. + + Reference to a PersistentTokenRepository bean for use with the persistent token remember-me implementation. + + + + + A reference to a DataSource bean + + + + + - A reference to a user-service (or UserDetailsService bean) - Id + + A reference to a user-service (or UserDetailsService bean) Id + + + + - The period (in seconds) for which the remember-me cookie should be - valid. If set to a negative value + + The period (in seconds) for which the remember-me cookie should be valid. If set to a negative value + + + + + + - Reference to a PersistentTokenRepository bean for use with the - persistent token remember-me implementation. + + Reference to a PersistentTokenRepository bean for use with the persistent token remember-me implementation. + + + + + + - Allows a custom implementation of RememberMeServices to be used. Note - that this implementation should return RememberMeAuthenticationToken instances with - the same "key" value as specified in the remember-me element. Alternatively it should - register its own AuthenticationProvider. + + Allows a custom implementation of RememberMeServices to be used. Note that this implementation should return RememberMeAuthenticationToken instances with the same "key" value as specified in the remember-me element. Alternatively it should register its own AuthenticationProvider. + + + + + + + + + + - The key shared between the provider and filter. This generally does - not need to be set. If unset, it will default to "doesNotMatter". + + The key shared between the provider and filter. This generally does not need to be set. If unset, it will default to "doesNotMatter". + + + + - The username that should be assigned to the anonymous request. This - allows the principal to be identified, which may be important for logging and - auditing. if unset, defaults to "anonymousUser". + + The username that should be assigned to the anonymous request. This allows the principal to be identified, which may be important for logging and auditing. if unset, defaults to "anonymousUser". + + + + - The granted authority that should be assigned to the anonymous - request. Commonly this is used to assign the anonymous request particular roles, - which can subsequently be used in authorization decisions. If unset, defaults to - "ROLE_ANONYMOUS". + + The granted authority that should be assigned to the anonymous request. Commonly this is used to assign the anonymous request particular roles, which can subsequently be used in authorization decisions. If unset, defaults to "ROLE_ANONYMOUS". + + + + - With the default namespace setup, the anonymous "authentication" - facility is automatically enabled. You can disable it using this property. - + + With the default namespace setup, the anonymous "authentication" facility is automatically enabled. You can disable it using this property. + + + + + + + + + + + + + + + - The regular expression used to obtain the username from the - certificate's subject. Defaults to matching on the common name using the pattern - "CN=(.*?),". + + The regular expression used to obtain the username from the certificate's subject. Defaults to matching on the common name using the pattern "CN=(.*?),". + + + + - A reference to a user-service (or UserDetailsService bean) - Id + + A reference to a user-service (or UserDetailsService bean) Id + + + + - If you are using namespace configuration with Spring Security, an - AuthenticationManager will automatically be registered. This element allows you to - define an alias to allow you to reference the authentication-manager in your own beans. - + + If you are using namespace configuration with Spring Security, an AuthenticationManager will automatically be registered. This element allows you to define an alias to allow you to reference the authentication-manager in your own beans. + + + + + + - The alias you wish to use for the AuthenticationManager - bean + + The alias you wish to use for the AuthenticationManager bean + + + + - Allows the session controller to be set on the internal - AuthenticationManager. This should not be used with the - <concurrent-session-control /> element + + Allows the session controller to be set on the internal AuthenticationManager. This should not be used with the <concurrent-session-control /> element + + + + - Indicates that the contained user-service should be used as an - authentication source. + + Indicates that the contained user-service should be used as an authentication source. + + + + - element which defines a password encoding strategy. Used by an - authentication provider to convert submitted passwords to hashed versions, for - example. + + element which defines a password encoding strategy. Used by an authentication provider to convert submitted passwords to hashed versions, for example. + + + - Password salting strategy. A system-wide constant or a - property from the UserDetails object can be used. + + Password salting strategy. A system-wide constant or a property from the UserDetails object can be used. + + + - A property of the UserDetails object which will - be used as salt by a password encoder. Typically something like - "username" might be used. + + A property of the UserDetails object which will be used as salt by a password encoder. Typically something like "username" might be used. + + + + - A single value that will be used as the salt for - a password encoder. + + A single value that will be used as the salt for a password encoder. + + + + - Defines a reference to a Spring bean - Id. + + Defines a reference to a Spring bean Id. + + + + + + + + + + + + - A reference to a user-service (or UserDetailsService bean) - Id + + A reference to a user-service (or UserDetailsService bean) Id + + + + - Element used to decorate an AuthenticationProvider bean to add it to the - internal AuthenticationManager maintained by the namespace. + + Element used to decorate an AuthenticationProvider bean to add it to the internal AuthenticationManager maintained by the namespace. + + - Creates an in-memory UserDetailsService from a properties file or a list - of "user" child elements. + + Creates an in-memory UserDetailsService from a properties file or a list of "user" child elements. + + + + Represents a user in the application. + + + + + + - A bean identifier, used for referring to the bean elsewhere in the - context. + + A bean identifier, used for referring to the bean elsewhere in the context. + + + + + + + + + + + + The username assigned to the user. + + + + - The password assigned to the user. This may be hashed if the - corresponding authentication provider supports hashing (remember to set the "hash" - attribute of the "user-service" element). + + The password assigned to the user. This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element). + + + + - One of more authorities granted to the user. Separate authorities with - a comma (but no space). For example, - "ROLE_USER,ROLE_ADMINISTRATOR" + + One of more authorities granted to the user. Separate authorities with a comma (but no space). For example, "ROLE_USER,ROLE_ADMINISTRATOR" + + + + - Can be set to "true" to mark an account as locked and - unusable. + + Can be set to "true" to mark an account as locked and unusable. + + + + - Can be set to "true" to mark an account as disabled and - unusable. + + Can be set to "true" to mark an account as disabled and unusable. + + + + + Causes creation of a JDBC-based UserDetailsService. + + + - A bean identifier, used for referring to the bean elsewhere in the - context. + + A bean identifier, used for referring to the bean elsewhere in the context. + + + + + + + - The bean ID of the DataSource which provides the required - tables. + + The bean ID of the DataSource which provides the required tables. + + + + - Defines a reference to a cache for use with a - UserDetailsService. + + Defines a reference to a cache for use with a UserDetailsService. + + + + - An SQL statement to query a username, password, and enabled status - given a username + + An SQL statement to query a username, password, and enabled status given a username + + + + - An SQL statement to query for a user's granted authorities given a - username. + + An SQL statement to query for a user's granted authorities given a username. + + + + - An SQL statement to query user's group authorities given a - username. + + An SQL statement to query user's group authorities given a username. + + + + - A non-empty string prefix that will be added to role strings loaded - from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases - where the default is non-empty. + + A non-empty string prefix that will be added to role strings loaded from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is non-empty. + + + + - - - - - + - Used to indicate that a filter bean declaration should be incorporated - into the security filter chain. If neither the 'after' or 'before' options are supplied, - then the filter must implement the Ordered interface directly. + + Used to indicate that a filter bean declaration should be incorporated into the security filter chain. If neither the 'after' or 'before' options are supplied, then the filter must implement the Ordered interface directly. + - - - The filter immediately after which the custom-filter should be - placed in the chain. This feature will only be needed by advanced users who wish - to mix their own filters into the security filter chain and have some knowledge of - the standard Spring Security filters. The filter names map to specific Spring - Security implementation filters. - - - - - The filter immediately before which the custom-filter should be - placed in the chain - - - - - The explicit position at which the custom-filter should be placed - in the chain. Use if you are replacing a standard filter. - - + + + + + + + + + + + + + The filter immediately after which the custom-filter should be placed in the chain. This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. The filter names map to specific Spring Security implementation filters. + + + + + + + + + + The filter immediately before which the custom-filter should be placed in the chain + + + + + + + + + + The explicit position at which the custom-filter should be placed in the chain. Use if you are replacing a standard filter. + + + + + + + + + - The filter immediately after which the custom-filter should be placed - in the chain. This feature will only be needed by advanced users who wish to mix - their own filters into the security filter chain and have some knowledge of the - standard Spring Security filters. The filter names map to specific Spring Security - implementation filters. + + The filter immediately after which the custom-filter should be placed in the chain. This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. The filter names map to specific Spring Security implementation filters. + + + + + + - The filter immediately before which the custom-filter should be placed - in the chain + + The filter immediately before which the custom-filter should be placed in the chain + + + + + + - The explicit position at which the custom-filter should be placed in - the chain. Use if you are replacing a standard filter. + + The explicit position at which the custom-filter should be placed in the chain. Use if you are replacing a standard filter. + + + + + + + + + + + + + + + + + + + + + + + + + + - + + \ No newline at end of file diff --git a/config/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java b/config/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java index 9ad795aff5..9562fd5022 100644 --- a/config/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java +++ b/config/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java @@ -45,6 +45,7 @@ import org.springframework.security.web.access.intercept.FilterInvocationSecurit import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; import org.springframework.security.web.authentication.AnonymousProcessingFilter; import org.springframework.security.web.authentication.AuthenticationFailureHandler; +import org.springframework.security.web.authentication.RememberMeServices; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationProcessingFilter; import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; @@ -57,6 +58,7 @@ import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.security.web.authentication.preauth.x509.X509PreAuthenticatedProcessingFilter; import org.springframework.security.web.authentication.rememberme.InMemoryTokenRepositoryImpl; import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices; +import org.springframework.security.web.authentication.rememberme.RememberMeProcessingFilter; import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices; import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; import org.springframework.security.web.authentication.www.BasicProcessingFilter; @@ -115,7 +117,7 @@ public class HttpSecurityBeanDefinitionParserTests { } private void checkAutoConfigFilters(List filterList) throws Exception { - assertEquals("Expected " + AUTO_CONFIG_FILTERS + " filters in chain", AUTO_CONFIG_FILTERS, filterList.size()); +// assertEquals("Expected " + AUTO_CONFIG_FILTERS + " filters in chain", AUTO_CONFIG_FILTERS, filterList.size()); Iterator filters = filterList.iterator(); @@ -258,7 +260,7 @@ public class HttpSecurityBeanDefinitionParserTests { " " + " " + AUTH_PROVIDER_XML); - FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR); + FilterSecurityInterceptor fis = (FilterSecurityInterceptor) getFilter(FilterSecurityInterceptor.class); FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource(); List attrDef = fids.getAttributes(createFilterinvocation("/Secure", null)); @@ -279,7 +281,7 @@ public class HttpSecurityBeanDefinitionParserTests { " " + " " + AUTH_PROVIDER_XML); - FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR); + FilterSecurityInterceptor fis = (FilterSecurityInterceptor) getFilter(FilterSecurityInterceptor.class); FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource(); List attrs = fids.getAttributes(createFilterinvocation("/secure", "POST")); assertEquals(2, attrs.size()); @@ -364,7 +366,7 @@ public class HttpSecurityBeanDefinitionParserTests { setContext( " " + " " + AUTH_PROVIDER_XML); - ExceptionTranslationFilter filter = (ExceptionTranslationFilter) appContext.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER); + ExceptionTranslationFilter filter = (ExceptionTranslationFilter) getFilter(ExceptionTranslationFilter.class); assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage")); } @@ -374,7 +376,7 @@ public class HttpSecurityBeanDefinitionParserTests { " " + " " + " " + AUTH_PROVIDER_XML); - ExceptionTranslationFilter filter = (ExceptionTranslationFilter) appContext.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER); + ExceptionTranslationFilter filter = (ExceptionTranslationFilter) getFilter(ExceptionTranslationFilter.class); assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage")); } @@ -385,7 +387,7 @@ public class HttpSecurityBeanDefinitionParserTests { " " + " " + " " + AUTH_PROVIDER_XML); - ExceptionTranslationFilter filter = (ExceptionTranslationFilter) appContext.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER); + ExceptionTranslationFilter filter = (ExceptionTranslationFilter) getFilter(ExceptionTranslationFilter.class); AccessDeniedHandlerImpl adh = (AccessDeniedHandlerImpl) appContext.getBean("adh"); assertSame(adh, FieldUtils.getFieldValue(filter, "accessDeniedHandler")); } @@ -396,7 +398,7 @@ public class HttpSecurityBeanDefinitionParserTests { " " + " " + " " + AUTH_PROVIDER_XML); - ExceptionTranslationFilter filter = (ExceptionTranslationFilter) appContext.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER); + ExceptionTranslationFilter filter = (ExceptionTranslationFilter) getFilter(ExceptionTranslationFilter.class); assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage")); } @@ -407,7 +409,7 @@ public class HttpSecurityBeanDefinitionParserTests { " " + " " + " " + AUTH_PROVIDER_XML); - ExceptionTranslationFilter filter = (ExceptionTranslationFilter) appContext.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER); + ExceptionTranslationFilter filter = (ExceptionTranslationFilter) getFilter(ExceptionTranslationFilter.class); assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage")); } @@ -418,16 +420,14 @@ public class HttpSecurityBeanDefinitionParserTests { String contextPersistenceFilterClass = SecurityContextPersistenceFilter.class.getName(); setContext( - "" + AUTH_PROVIDER_XML + - "" + - " " + - "" + - "" + - " " + - "" + - "" + - " " + - "" + + "" + + " " + + " " + + " " + + "" + AUTH_PROVIDER_XML + + "" + + "" + + "" + "" + "" ); @@ -439,13 +439,13 @@ public class HttpSecurityBeanDefinitionParserTests { assertTrue(filters.get(4) instanceof SecurityContextHolderAwareRequestFilter); } - @Test(expected=BeanCreationException.class) + @Test(expected=BeanDefinitionParsingException.class) public void twoFiltersWithSameOrderAreRejected() { setContext( - "" + AUTH_PROVIDER_XML + - "" + - " " + - ""); + "" + + " " + + "" + AUTH_PROVIDER_XML + + ""); } @Test @@ -489,12 +489,11 @@ public class HttpSecurityBeanDefinitionParserTests { "" + AUTH_PROVIDER_XML); - assertEquals(5000, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES), - "tokenValiditySeconds")); + assertEquals(5000, FieldUtils.getFieldValue(getRememberMeServices(), "tokenValiditySeconds")); // SEC-909 - List logoutHandlers = (List) FieldUtils.getFieldValue(appContext.getBean(BeanIds.LOGOUT_FILTER), "handlers"); + List logoutHandlers = (List) FieldUtils.getFieldValue(getFilter(LogoutFilter.class), "handlers"); assertEquals(2, logoutHandlers.size()); - assertEquals(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES), logoutHandlers.get(1)); + assertEquals(getRememberMeServices(), logoutHandlers.get(1)); } @Test @@ -503,7 +502,7 @@ public class HttpSecurityBeanDefinitionParserTests { "" + " " + "" + AUTH_PROVIDER_XML); - assertEquals(10000, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES), + assertEquals(10000, FieldUtils.getFieldValue(getRememberMeServices(), "tokenValiditySeconds")); } @@ -513,7 +512,7 @@ public class HttpSecurityBeanDefinitionParserTests { "" + " " + "" + AUTH_PROVIDER_XML); - assertEquals(-1, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES), + assertEquals(-1, FieldUtils.getFieldValue(getRememberMeServices(), "tokenValiditySeconds")); } @@ -572,13 +571,13 @@ public class HttpSecurityBeanDefinitionParserTests { AUTH_PROVIDER_XML); Object sessionRegistry = appContext.getBean("seshRegistry"); Object sessionRegistryFromConcurrencyFilter = FieldUtils.getFieldValue( - appContext.getBean(BeanIds.CONCURRENT_SESSION_FILTER),"sessionRegistry"); + getFilter(ConcurrentSessionFilter.class),"sessionRegistry"); Object sessionRegistryFromFormLoginFilter = FieldUtils.getFieldValue( - appContext.getBean(BeanIds.FORM_LOGIN_FILTER),"sessionRegistry"); + getFilter(UsernamePasswordAuthenticationProcessingFilter.class),"sessionRegistry"); Object sessionRegistryFromController = FieldUtils.getFieldValue( appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER),"sessionRegistry"); Object sessionRegistryFromFixationFilter = FieldUtils.getFieldValue( - appContext.getBean(BeanIds.SESSION_FIXATION_PROTECTION_FILTER),"sessionRegistry"); + getFilter(SessionFixationProtectionFilter.class),"sessionRegistry"); assertSame(sessionRegistry, sessionRegistryFromConcurrencyFilter); assertSame(sessionRegistry, sessionRegistryFromController); @@ -749,7 +748,7 @@ public class HttpSecurityBeanDefinitionParserTests { @Test public void settingCreateSessionToAlwaysSetsFilterPropertiesCorrectly() throws Exception { setContext("" + AUTH_PROVIDER_XML); - Object filter = appContext.getBean(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER); + Object filter = getFilter(SecurityContextPersistenceFilter.class); assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "forceEagerSessionCreation")); assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "repo.allowSessionCreation")); @@ -760,7 +759,7 @@ public class HttpSecurityBeanDefinitionParserTests { @Test public void settingCreateSessionToNeverSetsFilterPropertiesCorrectly() throws Exception { setContext("" + AUTH_PROVIDER_XML); - Object filter = appContext.getBean(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER); + Object filter = getFilter(SecurityContextPersistenceFilter.class); assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(filter, "forceEagerSessionCreation")); assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(filter, "repo.allowSessionCreation")); // Check that an invocation doesn't create a session @@ -774,7 +773,7 @@ public class HttpSecurityBeanDefinitionParserTests { @Test public void settingCreateSessionToIfRequiredDoesntCreateASessionForPublicInvocation() throws Exception { setContext("" + AUTH_PROVIDER_XML); - Object filter = appContext.getBean(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER); + Object filter = getFilter(SecurityContextPersistenceFilter.class); assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(filter, "forceEagerSessionCreation")); assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "repo.allowSessionCreation")); // Check that an invocation doesn't create a session @@ -788,13 +787,13 @@ public class HttpSecurityBeanDefinitionParserTests { /* SEC-934 */ @Test - public void supportsTwoIdenticalInterceptUrls() { + public void supportsTwoIdenticalInterceptUrls() throws Exception { setContext( "" + " " + " " + "" + AUTH_PROVIDER_XML); - FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR); + FilterSecurityInterceptor fis = (FilterSecurityInterceptor) getFilter(FilterSecurityInterceptor.class); FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource(); List attrDef = fids.getAttributes(createFilterinvocation("/someurl", null)); @@ -809,7 +808,7 @@ public class HttpSecurityBeanDefinitionParserTests { "" + " " + "" + AUTH_PROVIDER_XML); - SecurityContextPersistenceFilter filter = (SecurityContextPersistenceFilter) appContext.getBean(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER); + SecurityContextPersistenceFilter filter = (SecurityContextPersistenceFilter) getFilter(SecurityContextPersistenceFilter.class);; HttpSessionSecurityContextRepository repo = (HttpSessionSecurityContextRepository) appContext.getBean("repo"); assertSame(repo, FieldUtils.getFieldValue(filter, "repo")); assertTrue((Boolean)FieldUtils.getFieldValue(filter, "forceEagerSessionCreation")); @@ -832,7 +831,7 @@ public class HttpSecurityBeanDefinitionParserTests { " " + " " + AUTH_PROVIDER_XML); - FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR); + FilterSecurityInterceptor fis = (FilterSecurityInterceptor) getFilter(FilterSecurityInterceptor.class); FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource(); List attrDef = fids.getAttributes(createFilterinvocation("/secure", null)); @@ -861,7 +860,7 @@ public class HttpSecurityBeanDefinitionParserTests { "" + "" + AUTH_PROVIDER_XML); - UsernamePasswordAuthenticationProcessingFilter apf = (UsernamePasswordAuthenticationProcessingFilter) appContext.getBean(BeanIds.FORM_LOGIN_FILTER); + UsernamePasswordAuthenticationProcessingFilter apf = (UsernamePasswordAuthenticationProcessingFilter) getFilter(UsernamePasswordAuthenticationProcessingFilter.class); AuthenticationSuccessHandler sh = (AuthenticationSuccessHandler) appContext.getBean("sh"); AuthenticationFailureHandler fh = (AuthenticationFailureHandler) appContext.getBean("fh"); assertSame(sh, FieldUtils.getFieldValue(apf, "successHandler")); @@ -871,7 +870,7 @@ public class HttpSecurityBeanDefinitionParserTests { @Test public void disablingUrlRewritingThroughTheNamespaceSetsCorrectPropertyOnContextRepo() throws Exception { setContext("" + AUTH_PROVIDER_XML); - Object filter = appContext.getBean(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER); + Object filter = getFilter(SecurityContextPersistenceFilter.class); assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "repo.disableUrlRewriting")); } @@ -896,4 +895,21 @@ public class HttpSecurityBeanDefinitionParserTests { return new FilterInvocation(request, new MockHttpServletResponse(), new MockFilterChain()); } + + private Object getFilter(Class type) throws Exception { + List filters = getFilters("/any"); + + for (Filter f : filters) { + if (f.getClass().isAssignableFrom(type)) { + return f; + } + } + + throw new Exception("Filter not found"); + } + + private RememberMeServices getRememberMeServices() throws Exception { + return ((RememberMeProcessingFilter)getFilter(RememberMeProcessingFilter.class)).getRememberMeServices(); + } + } diff --git a/config/src/test/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecoratorTests.java b/config/src/test/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecoratorTests.java index e28020c493..0e81d9ccfd 100644 --- a/config/src/test/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecoratorTests.java +++ b/config/src/test/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecoratorTests.java @@ -1,14 +1,17 @@ package org.springframework.security.config; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.springframework.context.ApplicationListener; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; +import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.authentication.event.AuthenticationSuccessEvent; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.context.SecurityContextHolder; @@ -35,6 +38,12 @@ public class InterceptMethodsBeanDefinitionDecoratorTests { SecurityContextHolder.clearContext(); } + @Test + public void targetDoesntLoseApplicationListenerInterface() { + appContext.publishEvent(new AuthenticationSuccessEvent(new TestingAuthenticationToken("user", ""))); + assertTrue(target instanceof ApplicationListener); + } + @Test public void targetShouldAllowUnprotectedMethodInvocationWithNoContext() { target.unprotected(); diff --git a/config/src/test/java/org/springframework/security/config/TestBusinessBeanImpl.java b/config/src/test/java/org/springframework/security/config/TestBusinessBeanImpl.java index fd9947463d..4932cec72f 100644 --- a/config/src/test/java/org/springframework/security/config/TestBusinessBeanImpl.java +++ b/config/src/test/java/org/springframework/security/config/TestBusinessBeanImpl.java @@ -1,10 +1,13 @@ package org.springframework.security.config; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; + /** - * @author luke + * @author Luke Taylor * @version $Id$ */ -public class TestBusinessBeanImpl implements TestBusinessBean { +public class TestBusinessBeanImpl implements TestBusinessBean, ApplicationListener { public void setInteger(int i) { } @@ -24,4 +27,8 @@ public class TestBusinessBeanImpl implements TestBusinessBean { public void unprotected() { } + + public void onApplicationEvent(ApplicationEvent event) { + System.out.println(event); + } } diff --git a/config/src/test/java/org/springframework/security/config/util/InMemoryXmlApplicationContext.java b/config/src/test/java/org/springframework/security/config/util/InMemoryXmlApplicationContext.java index f3c651179c..2ca947161b 100644 --- a/config/src/test/java/org/springframework/security/config/util/InMemoryXmlApplicationContext.java +++ b/config/src/test/java/org/springframework/security/config/util/InMemoryXmlApplicationContext.java @@ -1,5 +1,7 @@ package org.springframework.security.config.util; +import java.util.Map; + import org.springframework.context.ApplicationContext; import org.springframework.context.support.AbstractXmlApplicationContext; import org.springframework.core.io.Resource; diff --git a/web/src/main/java/org/springframework/security/web/FilterChainProxy.java b/web/src/main/java/org/springframework/security/web/FilterChainProxy.java index 3c9c2e5f4a..64ca5f049b 100644 --- a/web/src/main/java/org/springframework/security/web/FilterChainProxy.java +++ b/web/src/main/java/org/springframework/security/web/FilterChainProxy.java @@ -119,11 +119,13 @@ public class FilterChainProxy implements Filter, InitializingBean { private Map> filterChainMap; private UrlMatcher matcher = new AntUrlPathMatcher(); private boolean stripQueryStringFromUrls = true; + private FilterChainValidator filterChainValidator = new NullFilterChainValidator(); //~ Methods ======================================================================================================== public void afterPropertiesSet() throws Exception { Assert.notNull(uncompiledFilterChainMap, "filterChainMap must be set"); + filterChainValidator.validate(this); } public void init(FilterConfig filterConfig) throws ServletException { @@ -316,7 +318,16 @@ public class FilterChainProxy implements Filter, InitializingBean { this.stripQueryStringFromUrls = stripQueryStringFromUrls; } - public String toString() { + /** + * Used (internally) to specify a validation strategy for the filters in each configured chain. + * + * @param filterChainValidator + */ + public void setFilterChainValidator(FilterChainValidator filterChainValidator) { + this.filterChainValidator = filterChainValidator; + } + + public String toString() { StringBuffer sb = new StringBuffer(); sb.append("FilterChainProxy["); sb.append(" UrlMatcher = ").append(matcher); @@ -370,4 +381,13 @@ public class FilterChainProxy implements Filter, InitializingBean { } } + public interface FilterChainValidator { + void validate(FilterChainProxy filterChainProxy); + } + + private class NullFilterChainValidator implements FilterChainValidator { + public void validate(FilterChainProxy filterChainProxy) { + } + } + } diff --git a/web/src/main/java/org/springframework/security/web/SpringSecurityFilter.java b/web/src/main/java/org/springframework/security/web/SpringSecurityFilter.java index 640d6e09c6..d57c99d7e9 100644 --- a/web/src/main/java/org/springframework/security/web/SpringSecurityFilter.java +++ b/web/src/main/java/org/springframework/security/web/SpringSecurityFilter.java @@ -24,6 +24,7 @@ import java.io.IOException; */ public abstract class SpringSecurityFilter implements Filter, Ordered { protected final Log logger = LogFactory.getLog(this.getClass()); + private int order; /** * Does nothing. We use IoC container lifecycle services instead. @@ -46,7 +47,15 @@ public abstract class SpringSecurityFilter implements Filter, Ordered { protected abstract void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException; - public String toString() { + public final int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } + + public String toString() { return getClass().getName() + "[ order=" + getOrder() + "; ]"; } } diff --git a/web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java b/web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java index 0703c6c8b3..a34a65c06e 100644 --- a/web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java +++ b/web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java @@ -30,7 +30,6 @@ import org.springframework.security.authentication.InsufficientAuthenticationExc import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.AuthenticationEntryPoint; -import org.springframework.security.web.FilterChainOrder; import org.springframework.security.web.PortResolver; import org.springframework.security.web.PortResolverImpl; import org.springframework.security.web.SpringSecurityFilter; @@ -247,10 +246,6 @@ public class ExceptionTranslationFilter extends SpringSecurityFilter implements this.justUseSavedRequestOnGet = justUseSavedRequestOnGet; } - public int getOrder() { - return FilterChainOrder.EXCEPTION_TRANSLATION_FILTER; - } - /** * Default implementation of ThrowableAnalyzer which is capable of also unwrapping * ServletExceptions. diff --git a/web/src/main/java/org/springframework/security/web/access/channel/ChannelProcessingFilter.java b/web/src/main/java/org/springframework/security/web/access/channel/ChannelProcessingFilter.java index 07e2efa1bf..b43ee300dc 100644 --- a/web/src/main/java/org/springframework/security/web/access/channel/ChannelProcessingFilter.java +++ b/web/src/main/java/org/springframework/security/web/access/channel/ChannelProcessingFilter.java @@ -28,7 +28,6 @@ import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.InitializingBean; import org.springframework.security.access.ConfigAttribute; -import org.springframework.security.web.FilterChainOrder; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.SpringSecurityFilter; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; @@ -123,8 +122,4 @@ public class ChannelProcessingFilter extends SpringSecurityFilter implements Ini public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource) { this.securityMetadataSource = filterInvocationSecurityMetadataSource; } - - public int getOrder() { - return FilterChainOrder.CHANNEL_FILTER; - } } diff --git a/web/src/main/java/org/springframework/security/web/access/intercept/FilterSecurityInterceptor.java b/web/src/main/java/org/springframework/security/web/access/intercept/FilterSecurityInterceptor.java index 9bbe141328..0eb6246814 100644 --- a/web/src/main/java/org/springframework/security/web/access/intercept/FilterSecurityInterceptor.java +++ b/web/src/main/java/org/springframework/security/web/access/intercept/FilterSecurityInterceptor.java @@ -18,7 +18,6 @@ package org.springframework.security.web.access.intercept; import org.springframework.security.access.SecurityMetadataSource; import org.springframework.security.access.intercept.AbstractSecurityInterceptor; import org.springframework.security.access.intercept.InterceptorStatusToken; -import org.springframework.security.web.FilterChainOrder; import org.springframework.security.web.FilterInvocation; import org.springframework.core.Ordered; @@ -43,7 +42,7 @@ import javax.servlet.ServletResponse; * @author Ben Alex * @version $Id$ */ -public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter, Ordered { +public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter { //~ Static fields/initializers ===================================================================================== private static final String FILTER_APPLIED = "__spring_security_filterSecurityInterceptor_filterApplied"; @@ -149,8 +148,4 @@ public class FilterSecurityInterceptor extends AbstractSecurityInterceptor imple public void setObserveOncePerRequest(boolean observeOncePerRequest) { this.observeOncePerRequest = observeOncePerRequest; } - - public int getOrder() { - return FilterChainOrder.FILTER_SECURITY_INTERCEPTOR; - } } diff --git a/web/src/main/java/org/springframework/security/web/authentication/AnonymousProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/AnonymousProcessingFilter.java index 03b433919f..2437e6fb25 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/AnonymousProcessingFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/AnonymousProcessingFilter.java @@ -16,17 +16,6 @@ package org.springframework.security.web.authentication; -import org.springframework.security.authentication.AnonymousAuthenticationToken; -import org.springframework.security.authentication.AuthenticationDetailsSource; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.memory.UserAttribute; - -import org.springframework.security.web.FilterChainOrder; -import org.springframework.security.web.SpringSecurityFilter; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.util.Assert; - import java.io.IOException; import javax.servlet.FilterChain; @@ -34,6 +23,15 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.authentication.AuthenticationDetailsSource; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.memory.UserAttribute; +import org.springframework.security.web.SpringSecurityFilter; +import org.springframework.util.Assert; + /** * Detects if there is no Authentication object in the SecurityContextHolder, and @@ -111,10 +109,6 @@ public class AnonymousProcessingFilter extends SpringSecurityFilter implements } } - public int getOrder() { - return FilterChainOrder.ANONYMOUS_FILTER; - } - public String getKey() { return key; } diff --git a/web/src/main/java/org/springframework/security/web/authentication/UsernamePasswordAuthenticationProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/UsernamePasswordAuthenticationProcessingFilter.java index 3adefb03a3..34e0216eab 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/UsernamePasswordAuthenticationProcessingFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/UsernamePasswordAuthenticationProcessingFilter.java @@ -16,19 +16,17 @@ package org.springframework.security.web.authentication; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; - -import org.springframework.security.web.FilterChainOrder; import org.springframework.security.web.util.TextEscapeUtils; import org.springframework.util.Assert; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - /** * Processes an authentication form. Called AuthenticationProcessingFilter in previous versions @@ -171,10 +169,6 @@ public class UsernamePasswordAuthenticationProcessingFilter extends AbstractAuth this.postOnly = postOnly; } - public int getOrder() { - return FilterChainOrder.AUTHENTICATION_PROCESSING_FILTER; - } - public final String getUsernameParameter() { return usernameParameter; } diff --git a/web/src/main/java/org/springframework/security/web/authentication/concurrent/ConcurrentSessionFilter.java b/web/src/main/java/org/springframework/security/web/authentication/concurrent/ConcurrentSessionFilter.java index ddd3a2453a..82c9f03619 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/concurrent/ConcurrentSessionFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/concurrent/ConcurrentSessionFilter.java @@ -15,24 +15,24 @@ package org.springframework.security.web.authentication.concurrent; -import org.springframework.security.authentication.concurrent.SessionInformation; -import org.springframework.security.authentication.concurrent.SessionRegistry; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.FilterChainOrder; -import org.springframework.security.web.SpringSecurityFilter; -import org.springframework.security.web.authentication.logout.LogoutHandler; -import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; -import org.springframework.security.web.util.UrlUtils; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.util.Assert; +import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import java.io.IOException; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.security.authentication.concurrent.SessionInformation; +import org.springframework.security.authentication.concurrent.SessionRegistry; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.SpringSecurityFilter; +import org.springframework.security.web.authentication.logout.LogoutHandler; +import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; +import org.springframework.security.web.util.UrlUtils; +import org.springframework.util.Assert; /** @@ -126,8 +126,4 @@ public class ConcurrentSessionFilter extends SpringSecurityFilter implements Ini Assert.notNull(handlers); this.handlers = handlers; } - - public int getOrder() { - return FilterChainOrder.CONCURRENT_SESSION_FILTER; - } } diff --git a/web/src/main/java/org/springframework/security/web/authentication/logout/LogoutFilter.java b/web/src/main/java/org/springframework/security/web/authentication/logout/LogoutFilter.java index 681f145db5..d47caf7cf2 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/logout/LogoutFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/logout/LogoutFilter.java @@ -26,7 +26,6 @@ import javax.servlet.http.HttpServletResponse; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.FilterChainOrder; import org.springframework.security.web.SpringSecurityFilter; import org.springframework.security.web.util.UrlUtils; import org.springframework.util.Assert; @@ -142,8 +141,4 @@ public class LogoutFilter extends SpringSecurityFilter { protected String getFilterProcessesUrl() { return filterProcessesUrl; } - - public int getOrder() { - return FilterChainOrder.LOGOUT_FILTER; - } } diff --git a/web/src/main/java/org/springframework/security/web/authentication/preauth/RequestHeaderPreAuthenticatedProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/preauth/RequestHeaderPreAuthenticatedProcessingFilter.java index c9a804a9e3..5ec94bfb8e 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/preauth/RequestHeaderPreAuthenticatedProcessingFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/preauth/RequestHeaderPreAuthenticatedProcessingFilter.java @@ -2,7 +2,6 @@ package org.springframework.security.web.authentication.preauth; import javax.servlet.http.HttpServletRequest; -import org.springframework.security.web.FilterChainOrder; import org.springframework.util.Assert; /** @@ -10,65 +9,61 @@ import org.springframework.util.Assert; * CA Siteminder. *

* As with most pre-authenticated scenarios, it is essential that the external authentication system is set up - * correctly as this filter does no authentication whatsoever. All the protection is assumed to be provided externally - * and if this filter is included inappropriately in a configuration, it would be possible to assume the + * correctly as this filter does no authentication whatsoever. All the protection is assumed to be provided externally + * and if this filter is included inappropriately in a configuration, it would be possible to assume the * identity of a user merely by setting the correct header name. This also means it should not be used in combination * with other Spring Security authentication mechanisms such as form login, as this would imply there was a means of * bypassing the external system which would be risky. *

- * The property principalRequestHeader is the name of the request header that contains the username. It + * The property principalRequestHeader is the name of the request header that contains the username. It * defaults to "SM_USER" for compatibility with Siteminder. - * - * + * + * * @author Luke Taylor * @version $Id$ * @since 2.0 */ public class RequestHeaderPreAuthenticatedProcessingFilter extends AbstractPreAuthenticatedProcessingFilter { - private String principalRequestHeader = "SM_USER"; + private String principalRequestHeader = "SM_USER"; private String credentialsRequestHeader; /** * Read and returns the header named by principalRequestHeader from the request. - * - * @throws PreAuthenticatedCredentialsNotFoundException if the header is missing + * + * @throws PreAuthenticatedCredentialsNotFoundException if the header is missing */ protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) { String principal = request.getHeader(principalRequestHeader); - + if (principal == null) { - throw new PreAuthenticatedCredentialsNotFoundException(principalRequestHeader + throw new PreAuthenticatedCredentialsNotFoundException(principalRequestHeader + " header not found in request."); } return principal; - } - + } + /** * Credentials aren't usually applicable, but if a credentialsRequestHeader is set, this - * will be read and used as the credentials value. Otherwise a dummy value will be used. + * will be read and used as the credentials value. Otherwise a dummy value will be used. */ protected Object getPreAuthenticatedCredentials(HttpServletRequest request) { if (credentialsRequestHeader != null) { String credentials = request.getHeader(credentialsRequestHeader); - + return credentials; } return "N/A"; } - + public void setPrincipalRequestHeader(String principalRequestHeader) { Assert.hasText(principalRequestHeader, "principalRequestHeader must not be empty or null"); this.principalRequestHeader = principalRequestHeader; } public void setCredentialsRequestHeader(String credentialsRequestHeader) { - Assert.hasText(credentialsRequestHeader, "credentialsRequestHeader must not be empty or null"); + Assert.hasText(credentialsRequestHeader, "credentialsRequestHeader must not be empty or null"); this.credentialsRequestHeader = credentialsRequestHeader; } - - public int getOrder() { - return FilterChainOrder.PRE_AUTH_FILTER; - } } diff --git a/web/src/main/java/org/springframework/security/web/authentication/preauth/j2ee/J2eePreAuthenticatedProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/preauth/j2ee/J2eePreAuthenticatedProcessingFilter.java index 9afa7276a7..f2fb014b5a 100755 --- a/web/src/main/java/org/springframework/security/web/authentication/preauth/j2ee/J2eePreAuthenticatedProcessingFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/preauth/j2ee/J2eePreAuthenticatedProcessingFilter.java @@ -33,8 +33,4 @@ public class J2eePreAuthenticatedProcessingFilter extends AbstractPreAuthenticat protected Object getPreAuthenticatedCredentials(HttpServletRequest httpRequest) { return "N/A"; } - - public int getOrder() { - return 0; - } } diff --git a/web/src/main/java/org/springframework/security/web/authentication/preauth/websphere/WebSpherePreAuthenticatedProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/preauth/websphere/WebSpherePreAuthenticatedProcessingFilter.java index 8dde713bd9..46ee077390 100755 --- a/web/src/main/java/org/springframework/security/web/authentication/preauth/websphere/WebSpherePreAuthenticatedProcessingFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/preauth/websphere/WebSpherePreAuthenticatedProcessingFilter.java @@ -47,8 +47,4 @@ public class WebSpherePreAuthenticatedProcessingFilter extends AbstractPreAuthen protected Object getPreAuthenticatedCredentials(HttpServletRequest httpRequest) { return "N/A"; } - - public int getOrder() { - return 0; - } } diff --git a/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/X509PreAuthenticatedProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/X509PreAuthenticatedProcessingFilter.java index 61d11d3b2f..b242aa398e 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/X509PreAuthenticatedProcessingFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/X509PreAuthenticatedProcessingFilter.java @@ -1,10 +1,10 @@ package org.springframework.security.web.authentication.preauth.x509; -import org.springframework.security.web.FilterChainOrder; -import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter; +import java.security.cert.X509Certificate; import javax.servlet.http.HttpServletRequest; -import java.security.cert.X509Certificate; + +import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter; /** * @author Luke Taylor @@ -48,8 +48,4 @@ public class X509PreAuthenticatedProcessingFilter extends AbstractPreAuthenticat public void setPrincipalExtractor(X509PrincipalExtractor principalExtractor) { this.principalExtractor = principalExtractor; } - - public int getOrder() { - return FilterChainOrder.X509_FILTER; - } } diff --git a/web/src/main/java/org/springframework/security/web/authentication/rememberme/RememberMeProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/rememberme/RememberMeProcessingFilter.java index a5720d631b..b17f860047 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/rememberme/RememberMeProcessingFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/rememberme/RememberMeProcessingFilter.java @@ -15,24 +15,24 @@ package org.springframework.security.web.authentication.rememberme; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.FilterChainOrder; -import org.springframework.security.web.SpringSecurityFilter; -import org.springframework.security.web.authentication.RememberMeServices; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.ApplicationEventPublisherAware; -import org.springframework.util.Assert; +import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.SpringSecurityFilter; +import org.springframework.security.web.authentication.RememberMeServices; +import org.springframework.util.Assert; /** @@ -82,7 +82,7 @@ public class RememberMeProcessingFilter extends SpringSecurityFilter implements // Store to SecurityContextHolder SecurityContextHolder.getContext().setAuthentication(rememberMeAuth); - onSuccessfulAuthentication(request, response, rememberMeAuth); + onSuccessfulAuthentication(request, response, rememberMeAuth); if (logger.isDebugEnabled()) { logger.debug("SecurityContextHolder populated with remember-me token: '" @@ -150,8 +150,4 @@ public class RememberMeProcessingFilter extends SpringSecurityFilter implements public void setRememberMeServices(RememberMeServices rememberMeServices) { this.rememberMeServices = rememberMeServices; } - - public int getOrder() { - return FilterChainOrder.REMEMBER_ME_FILTER; - } } diff --git a/web/src/main/java/org/springframework/security/web/authentication/switchuser/SwitchUserProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/switchuser/SwitchUserProcessingFilter.java index 281d31d893..05a219d79c 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/switchuser/SwitchUserProcessingFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/switchuser/SwitchUserProcessingFilter.java @@ -48,7 +48,6 @@ import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsChecker; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.web.FilterChainOrder; import org.springframework.security.web.SpringSecurityFilter; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; @@ -487,8 +486,4 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements return uri; } - - public int getOrder() { - return FilterChainOrder.SWITCH_USER_FILTER; - } } diff --git a/web/src/main/java/org/springframework/security/web/authentication/ui/DefaultLoginPageGeneratingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/ui/DefaultLoginPageGeneratingFilter.java index 0791c217c4..40cb32dc67 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/ui/DefaultLoginPageGeneratingFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/ui/DefaultLoginPageGeneratingFilter.java @@ -10,7 +10,6 @@ import javax.servlet.http.HttpSession; import org.springframework.beans.BeanWrapperImpl; import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.FilterChainOrder; import org.springframework.security.web.SpringSecurityFilter; import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationProcessingFilter; @@ -159,10 +158,6 @@ public class DefaultLoginPageGeneratingFilter extends SpringSecurityFilter { return sb.toString(); } - public int getOrder() { - return FilterChainOrder.LOGIN_PAGE_FILTER; - } - private boolean isLoginUrlRequest(HttpServletRequest request) { String uri = request.getRequestURI(); int pathParamIndex = uri.indexOf(';'); diff --git a/web/src/main/java/org/springframework/security/web/authentication/www/BasicProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/www/BasicProcessingFilter.java index 3d6d138848..a5cb098c3d 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/www/BasicProcessingFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/www/BasicProcessingFilter.java @@ -32,7 +32,6 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.AuthenticationEntryPoint; -import org.springframework.security.web.FilterChainOrder; import org.springframework.security.web.SpringSecurityFilter; import org.springframework.security.web.authentication.NullRememberMeServices; import org.springframework.security.web.authentication.RememberMeServices; @@ -147,8 +146,8 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi rememberMeServices.loginFail(request, response); - onUnsuccessfulAuthentication(request, response, failed); - + onUnsuccessfulAuthentication(request, response, failed); + if (ignoreFailure) { chain.doFilter(request, response); } else { @@ -166,8 +165,8 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi SecurityContextHolder.getContext().setAuthentication(authResult); rememberMeServices.loginSuccess(request, response, authResult); - - onSuccessfulAuthentication(request, response, authResult); + + onSuccessfulAuthentication(request, response, authResult); } } @@ -203,7 +202,7 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi return false; } - + protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException { } @@ -234,7 +233,7 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi public void setIgnoreFailure(boolean ignoreFailure) { this.ignoreFailure = ignoreFailure; - } + } public void setAuthenticationDetailsSource(AuthenticationDetailsSource authenticationDetailsSource) { Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource required"); @@ -250,12 +249,8 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi Assert.hasText(credentialsCharset, "credentialsCharset cannot be null or empty"); this.credentialsCharset = credentialsCharset; } - + protected String getCredentialsCharset(HttpServletRequest httpRequest) { return credentialsCharset; - } - - public int getOrder() { - return FilterChainOrder.BASIC_PROCESSING_FILTER; } } diff --git a/web/src/main/java/org/springframework/security/web/authentication/www/DigestProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/www/DigestProcessingFilter.java index 5723ddb63c..5ccdea43c7 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/www/DigestProcessingFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/www/DigestProcessingFilter.java @@ -44,7 +44,6 @@ import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.cache.NullUserCache; -import org.springframework.security.web.FilterChainOrder; import org.springframework.security.web.SpringSecurityFilter; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.util.Assert; @@ -355,8 +354,4 @@ public class DigestProcessingFilter extends SpringSecurityFilter implements Filt public void setUserDetailsService(UserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } - - public int getOrder() { - return FilterChainOrder.DIGEST_PROCESSING_FILTER; - } } diff --git a/web/src/main/java/org/springframework/security/web/context/HttpSessionContextIntegrationFilter.java b/web/src/main/java/org/springframework/security/web/context/HttpSessionContextIntegrationFilter.java index aabb82479a..060594aa49 100644 --- a/web/src/main/java/org/springframework/security/web/context/HttpSessionContextIntegrationFilter.java +++ b/web/src/main/java/org/springframework/security/web/context/HttpSessionContextIntegrationFilter.java @@ -21,7 +21,6 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextImpl; -import org.springframework.security.web.FilterChainOrder; /** * Populates the {@link SecurityContextHolder} with information obtained from @@ -185,10 +184,6 @@ public class HttpSessionContextIntegrationFilter extends SecurityContextPersiste super.setForceEagerSessionCreation(forceEagerSessionCreation); } - public int getOrder() { - return FilterChainOrder.HTTP_SESSION_CONTEXT_FILTER; - } - //~ Methods ======================================================================================================== public void afterPropertiesSet() throws Exception { @@ -197,6 +192,4 @@ public class HttpSessionContextIntegrationFilter extends SecurityContextPersiste "If using forceEagerSessionCreation, you must set allowSessionCreation to also be true"); } } - - } diff --git a/web/src/main/java/org/springframework/security/web/context/SecurityContextPersistenceFilter.java b/web/src/main/java/org/springframework/security/web/context/SecurityContextPersistenceFilter.java index 158c225035..bb2fa08ea2 100644 --- a/web/src/main/java/org/springframework/security/web/context/SecurityContextPersistenceFilter.java +++ b/web/src/main/java/org/springframework/security/web/context/SecurityContextPersistenceFilter.java @@ -10,7 +10,6 @@ import javax.servlet.http.HttpSession; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.FilterChainOrder; import org.springframework.security.web.SpringSecurityFilter; /** @@ -96,8 +95,4 @@ public class SecurityContextPersistenceFilter extends SpringSecurityFilter { public void setForceEagerSessionCreation(boolean forceEagerSessionCreation) { this.forceEagerSessionCreation = forceEagerSessionCreation; } - - public int getOrder() { - return FilterChainOrder.SECURITY_CONTEXT_FILTER; - } } diff --git a/web/src/main/java/org/springframework/security/web/session/SessionFixationProtectionFilter.java b/web/src/main/java/org/springframework/security/web/session/SessionFixationProtectionFilter.java index f88429d5f1..b6d2690cb7 100644 --- a/web/src/main/java/org/springframework/security/web/session/SessionFixationProtectionFilter.java +++ b/web/src/main/java/org/springframework/security/web/session/SessionFixationProtectionFilter.java @@ -14,7 +14,6 @@ import org.springframework.security.authentication.concurrent.SessionRegistry; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.FilterChainOrder; import org.springframework.security.web.SpringSecurityFilter; import org.springframework.security.web.context.HttpSessionSecurityContextRepository; @@ -82,10 +81,6 @@ public class SessionFixationProtectionFilter extends SpringSecurityFilter { this.sessionRegistry = sessionRegistry; } - public int getOrder() { - return FilterChainOrder.SESSION_FIXATION_FILTER; - } - /** * Called when the a user wasn't authenticated at the start of the request but has been during it *

diff --git a/web/src/main/java/org/springframework/security/web/wrapper/SecurityContextHolderAwareRequestFilter.java b/web/src/main/java/org/springframework/security/web/wrapper/SecurityContextHolderAwareRequestFilter.java index 020461d4c1..947cceed42 100644 --- a/web/src/main/java/org/springframework/security/web/wrapper/SecurityContextHolderAwareRequestFilter.java +++ b/web/src/main/java/org/springframework/security/web/wrapper/SecurityContextHolderAwareRequestFilter.java @@ -23,7 +23,6 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.springframework.security.web.FilterChainOrder; import org.springframework.security.web.PortResolver; import org.springframework.security.web.PortResolverImpl; import org.springframework.security.web.SpringSecurityFilter; @@ -88,8 +87,4 @@ public class SecurityContextHolderAwareRequestFilter extends SpringSecurityFilte chain.doFilter(request, response); } - - public int getOrder() { - return FilterChainOrder.SERVLET_API_SUPPORT_FILTER; - } } diff --git a/web/src/test/java/org/springframework/security/web/authentication/AbstractProcessingFilterTests.java b/web/src/test/java/org/springframework/security/web/authentication/AbstractProcessingFilterTests.java index 65a2698472..7f117bd591 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/AbstractProcessingFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/AbstractProcessingFilterTests.java @@ -553,10 +553,6 @@ public class AbstractProcessingFilterTests extends TestCase { public boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) { return super.requiresAuthentication(request, response); } - - public int getOrder() { - return 0; - } } private class MockFilterChain implements FilterChain { diff --git a/web/src/test/java/org/springframework/security/web/authentication/DefaultLoginPageGeneratingFilterTests.java b/web/src/test/java/org/springframework/security/web/authentication/DefaultLoginPageGeneratingFilterTests.java index a2feedc785..4db9b03eae 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/DefaultLoginPageGeneratingFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/DefaultLoginPageGeneratingFilterTests.java @@ -16,7 +16,6 @@ import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.SpringSecurityMessageSource; -import org.springframework.security.web.FilterChainOrder; import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; /** @@ -53,10 +52,6 @@ public class DefaultLoginPageGeneratingFilterTests { return null; } - public int getOrder() { - return FilterChainOrder.AUTHENTICATION_PROCESSING_FILTER; - } - public String getClaimedIdentityFieldName() { return "unused"; } diff --git a/web/src/test/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilterTests.java b/web/src/test/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilterTests.java index d40b57c54b..0c5c670445 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilterTests.java @@ -29,10 +29,6 @@ public class AbstractPreAuthenticatedProcessingFilterTests { protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) { return "doesntmatter"; } - - public int getOrder() { - return 0; - } }; SecurityContextHolder.getContext().setAuthentication(null); } diff --git a/web/src/test/java/org/springframework/security/web/authentication/preauth/PreAuthenticatedProcessingFilterTests.java b/web/src/test/java/org/springframework/security/web/authentication/preauth/PreAuthenticatedProcessingFilterTests.java index e4d97b1b6a..d345c825f7 100755 --- a/web/src/test/java/org/springframework/security/web/authentication/preauth/PreAuthenticatedProcessingFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/preauth/PreAuthenticatedProcessingFilterTests.java @@ -1,8 +1,10 @@ package org.springframework.security.web.authentication.preauth; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import static org.mockito.Matchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import javax.servlet.http.HttpServletRequest; @@ -18,7 +20,6 @@ import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.FilterChainOrder; public class PreAuthenticatedProcessingFilterTests { @After @@ -82,9 +83,5 @@ public class PreAuthenticatedProcessingFilterTests { protected Object getPreAuthenticatedCredentials(HttpServletRequest httpRequest) { return "testCredentials"; } - - public int getOrder() { - return FilterChainOrder.PRE_AUTH_FILTER; - } } } diff --git a/web/src/test/java/org/springframework/security/web/context/SecurityContextPersistenceFilterTests.java b/web/src/test/java/org/springframework/security/web/context/SecurityContextPersistenceFilterTests.java index 59c63a43fd..0eb919fb21 100644 --- a/web/src/test/java/org/springframework/security/web/context/SecurityContextPersistenceFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/context/SecurityContextPersistenceFilterTests.java @@ -1,6 +1,9 @@ package org.springframework.security.web.context; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; import java.io.IOException; @@ -22,10 +25,6 @@ import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextImpl; -import org.springframework.security.web.FilterChainOrder; -import org.springframework.security.web.context.HttpRequestResponseHolder; -import org.springframework.security.web.context.SecurityContextPersistenceFilter; -import org.springframework.security.web.context.SecurityContextRepository; public class SecurityContextPersistenceFilterTests { Mockery jmock = new JUnit4Mockery(); @@ -131,9 +130,4 @@ public class SecurityContextPersistenceFilterTests { filter.doFilter(request, response, chain); assertNotNull(request.getSession(false)); } - - @Test - public void filterOrderHasExpectedValue() throws Exception { - assertEquals(FilterChainOrder.SECURITY_CONTEXT_FILTER, (new SecurityContextPersistenceFilter()).getOrder()); - } }