From 1afa67c954d8d07cb846e712c007f1f453c4eb2a Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Wed, 15 Jul 2009 23:09:47 +0000 Subject: [PATCH] SEC-1195: Added internal AuthenticationManager for use by beans which are generated by the block. --- .../config/AnonymousBeanDefinitionParser.java | 71 ------ ...enticationManagerBeanDefinitionParser.java | 7 +- .../security/config/BeanIds.java | 39 +-- ...oncurrentSessionsBeanDefinitionParser.java | 26 -- .../security/config/ConfigUtils.java | 28 +-- .../config/FormLoginBeanDefinitionParser.java | 2 - .../HttpSecurityBeanDefinitionParser.java | 231 ++++++++++++++---- .../RememberMeBeanDefinitionParser.java | 12 - .../config/X509BeanDefinitionParser.java | 61 ----- ...tadataSourceBeanDefinitionParserTests.java | 1 + ...HttpSecurityBeanDefinitionParserTests.java | 24 +- .../authentication/ProviderManager.java | 16 +- .../authentication/ProviderManagerTests.java | 5 +- .../WEB-INF/applicationContext-security.xml | 4 +- 14 files changed, 237 insertions(+), 290 deletions(-) delete mode 100644 config/src/main/java/org/springframework/security/config/AnonymousBeanDefinitionParser.java delete mode 100644 config/src/main/java/org/springframework/security/config/X509BeanDefinitionParser.java diff --git a/config/src/main/java/org/springframework/security/config/AnonymousBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/AnonymousBeanDefinitionParser.java deleted file mode 100644 index 18375a537a..0000000000 --- a/config/src/main/java/org/springframework/security/config/AnonymousBeanDefinitionParser.java +++ /dev/null @@ -1,71 +0,0 @@ -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.support.RootBeanDefinition; -import org.springframework.beans.factory.xml.BeanDefinitionParser; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.security.authentication.AnonymousAuthenticationProvider; -import org.springframework.security.web.authentication.AnonymousProcessingFilter; -import org.springframework.util.StringUtils; -import org.w3c.dom.Element; - -/** - * @author Ben Alex - * @version $Id: RememberMeBeanDefinitionParser.java 2231 2007-11-07 13:29:15Z luke_t $ - */ -public class AnonymousBeanDefinitionParser implements BeanDefinitionParser { - static final String ATT_KEY = "key"; - static final String DEF_KEY = "doesNotMatter"; - - static final String ATT_USERNAME = "username"; - static final String DEF_USERNAME = "anonymousUser"; - - static final String ATT_GRANTED_AUTHORITY = "granted-authority"; - static final String DEF_GRANTED_AUTHORITY = "ROLE_ANONYMOUS"; - - protected final Log logger = LogFactory.getLog(getClass()); - - public BeanDefinition parse(Element element, ParserContext parserContext) { - String grantedAuthority = null; - String username = null; - String key = null; - Object source = null; - - if (element != null) { - grantedAuthority = element.getAttribute(ATT_GRANTED_AUTHORITY); - username = element.getAttribute(ATT_USERNAME); - key = element.getAttribute(ATT_KEY); - source = parserContext.extractSource(element); - } - - if (!StringUtils.hasText(grantedAuthority)) { - grantedAuthority = DEF_GRANTED_AUTHORITY; - } - - if (!StringUtils.hasText(username)) { - username = DEF_USERNAME; - } - - if (!StringUtils.hasText(key)) { - key = DEF_KEY; - } - - RootBeanDefinition filter = new RootBeanDefinition(AnonymousProcessingFilter.class); - - filter.setSource(source); - filter.getPropertyValues().addPropertyValue("userAttribute", username + "," + grantedAuthority); - filter.getPropertyValues().addPropertyValue(ATT_KEY, key); - - RootBeanDefinition provider = new RootBeanDefinition(AnonymousAuthenticationProvider.class); - provider.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - provider.setSource(source); - provider.getPropertyValues().addPropertyValue(ATT_KEY, key); - - parserContext.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_AUTHENTICATION_PROVIDER, provider); - ConfigUtils.addAuthenticationProvider(parserContext, BeanIds.ANONYMOUS_AUTHENTICATION_PROVIDER, null); - - return filter; - } -} 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 f4675bdac7..092a0a0a55 100644 --- a/config/src/main/java/org/springframework/security/config/AuthenticationManagerBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/AuthenticationManagerBeanDefinitionParser.java @@ -1,12 +1,11 @@ package org.springframework.security.config; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.util.StringUtils; - import org.w3c.dom.Element; /** @@ -34,8 +33,6 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition if (StringUtils.hasText(sessionControllerRef)) { BeanDefinition authManager = parserContext.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER); - ConfigUtils.setSessionControllerOnAuthenticationManager(parserContext, - BeanIds.CONCURRENT_SESSION_CONTROLLER, element); authManager.getPropertyValues().addPropertyValue("sessionController", new RuntimeBeanReference(sessionControllerRef)); RootBeanDefinition sessionRegistryInjector = new RootBeanDefinition(SessionRegistryInjectionBeanPostProcessor.class); 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 b669bde2ad..3571b3e449 100644 --- a/config/src/main/java/org/springframework/security/config/BeanIds.java +++ b/config/src/main/java/org/springframework/security/config/BeanIds.java @@ -13,24 +13,10 @@ public abstract class BeanIds { /** External alias for FilterChainProxy bean, for use in web.xml files */ public static final String SPRING_SECURITY_FILTER_CHAIN = "springSecurityFilterChain"; - /** 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 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"; -// 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_AUTHENTICATION_PROVIDER = "_anonymousAuthenticationProvider"; -// 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_CONTROLLER = "_concurrentSessionController"; + public static final String METHOD_ACCESS_MANAGER = "_defaultMethodAccessManager"; public static final String WEB_ACCESS_MANAGER = "_webAccessManager"; public static final String AUTHENTICATION_MANAGER = "_authenticationManager"; @@ -39,31 +25,12 @@ public abstract class BeanIds { public static final String FORM_LOGIN_ENTRY_POINT = "_formLoginEntryPoint"; public static final String OPEN_ID_FILTER = "_openIDFilter"; public static final String OPEN_ID_ENTRY_POINT = "_openIDFilterEntryPoint"; - 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 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 CHANNEL_DECISION_MANAGER = "_channelDecisionManager"; -// 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 SESSION_FIXATION_PROTECTION_FILTER = "_sessionFixationProtectionFilter"; public static final String METHOD_SECURITY_METADATA_SOURCE_ADVISOR = "_methodSecurityMetadataSourceAdvisor"; -// public static final String PROTECT_POINTCUT_POST_PROCESSOR = "_protectPointcutPostProcessor"; -// public static final String SECURED_METHOD_SECURITY_METADATA_SOURCE = "_securedSecurityMetadataSource"; -// public static final String JSR_250_METHOD_SECURITY_METADATA_SOURCE = "_jsr250SecurityMetadataSource"; 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_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/ConcurrentSessionsBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/ConcurrentSessionsBeanDefinitionParser.java index 44680bcafa..8c2a32f9c0 100644 --- a/config/src/main/java/org/springframework/security/config/ConcurrentSessionsBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/ConcurrentSessionsBeanDefinitionParser.java @@ -26,8 +26,6 @@ import org.w3c.dom.Element; public class ConcurrentSessionsBeanDefinitionParser implements BeanDefinitionParser { static final String ATT_EXPIRY_URL = "expired-url"; - static final String ATT_MAX_SESSIONS = "max-sessions"; - static final String ATT_EXCEPTION_IF_MAX_EXCEEDED = "exception-if-maximum-exceeded"; static final String ATT_SESSION_REGISTRY_ALIAS = "session-registry-alias"; static final String ATT_SESSION_REGISTRY_REF = "session-registry-ref"; @@ -67,30 +65,6 @@ public class ConcurrentSessionsBeanDefinitionParser implements BeanDefinitionPar filterBuilder.addPropertyValue("expiredUrl", expiryUrl); } - BeanDefinitionBuilder controllerBuilder - = BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionControllerImpl.class); - controllerBuilder.getRawBeanDefinition().setSource(source); - controllerBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - controllerBuilder.addPropertyReference("sessionRegistry", sessionRegistryId); - - String maxSessions = element.getAttribute(ATT_MAX_SESSIONS); - - if (StringUtils.hasText(maxSessions)) { - controllerBuilder.addPropertyValue("maximumSessions", maxSessions); - } - - String exceptionIfMaximumExceeded = element.getAttribute(ATT_EXCEPTION_IF_MAX_EXCEEDED); - - if (StringUtils.hasText(exceptionIfMaximumExceeded)) { - controllerBuilder.addPropertyValue("exceptionIfMaximumExceeded", exceptionIfMaximumExceeded); - } - - BeanDefinition controller = controllerBuilder.getBeanDefinition(); - - beanRegistry.registerBeanDefinition(BeanIds.CONCURRENT_SESSION_CONTROLLER, controller); - pc.registerComponent(new BeanComponentDefinition(controller, BeanIds.CONCURRENT_SESSION_CONTROLLER)); - ConfigUtils.setSessionControllerOnAuthenticationManager(pc, BeanIds.CONCURRENT_SESSION_CONTROLLER, element); - pc.popAndRegisterContainingComponent(); return filterBuilder.getBeanDefinition(); 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 caa1b1c933..c4c45a5072 100644 --- a/config/src/main/java/org/springframework/security/config/ConfigUtils.java +++ b/config/src/main/java/org/springframework/security/config/ConfigUtils.java @@ -2,9 +2,7 @@ package org.springframework.security.config; import java.util.ArrayList; -import org.springframework.beans.PropertyValue; 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.BeanDefinitionBuilder; import org.springframework.beans.factory.support.ManagedList; @@ -27,7 +25,6 @@ import org.w3c.dom.Element; * @version $Id$ */ abstract class ConfigUtils { - @SuppressWarnings("unchecked") static void registerDefaultMethodAccessManagerIfNecessary(ParserContext parserContext) { if (!parserContext.getRegistry().containsBeanDefinition(BeanIds.METHOD_ACCESS_MANAGER)) { @@ -69,7 +66,6 @@ abstract class ConfigUtils { * @param element the source element under which this bean should be registered. */ static void registerProviderManagerIfNecessary(ParserContext pc, Element element) { - if(pc.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER)) { return; } @@ -118,16 +114,16 @@ abstract class ConfigUtils { pc.getReaderContext().warning(url + " is not a valid redirect URL (must start with '/' or http(s))", source); } - static void setSessionControllerOnAuthenticationManager(ParserContext pc, String beanName, Element sourceElt) { - BeanDefinition authManager = pc.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER); - PropertyValue pv = authManager.getPropertyValues().getPropertyValue("sessionController"); - - if (pv != null && pv.getValue() != null) { - pc.getReaderContext().error("A session controller has already been set on the authentication manager. " + - "The element isn't compatible with a custom session controller", - pc.extractSource(sourceElt)); - } - - authManager.getPropertyValues().addPropertyValue("sessionController", new RuntimeBeanReference(beanName)); - } +// static void setSessionControllerOnAuthenticationManager(ParserContext pc, String beanName, Element sourceElt) { +// BeanDefinition authManager = pc.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER); +// PropertyValue pv = authManager.getPropertyValues().getPropertyValue("sessionController"); +// +// if (pv != null && pv.getValue() != null) { +// pc.getReaderContext().error("A session controller has already been set on the authentication manager. " + +// "The element isn't compatible with a custom session controller", +// pc.extractSource(sourceElt)); +// } +// +// authManager.getPropertyValues().addPropertyValue("sessionController", new RuntimeBeanReference(beanName)); +// } } 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 c5fa8f70f3..ede9f3b719 100644 --- a/config/src/main/java/org/springframework/security/config/FormLoginBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/FormLoginBeanDefinitionParser.java @@ -81,8 +81,6 @@ public class FormLoginBeanDefinitionParser { filterBean = createFilterBean(loginUrl, defaultTargetUrl, alwaysUseDefault, loginPage, authenticationFailureUrl, successHandlerRef, failureHandlerRef); filterBean.setSource(source); - filterBean.getPropertyValues().addPropertyValue("authenticationManager", - new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER)); // Copy session migration values from the session fixation protection filter if (sfpf != 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 75bd255f71..0f8c5729ea 100644 --- a/config/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java @@ -33,6 +33,10 @@ import org.springframework.security.access.SecurityConfig; import org.springframework.security.access.vote.AuthenticatedVoter; import org.springframework.security.access.vote.RoleVoter; import org.springframework.security.authentication.AnonymousAuthenticationProvider; +import org.springframework.security.authentication.ProviderManager; +import org.springframework.security.authentication.RememberMeAuthenticationProvider; +import org.springframework.security.authentication.concurrent.ConcurrentSessionControllerImpl; +import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper; import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.access.AccessDeniedHandlerImpl; import org.springframework.security.web.access.ExceptionTranslationFilter; @@ -48,6 +52,9 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept import org.springframework.security.web.access.intercept.RequestKey; import org.springframework.security.web.authentication.AnonymousProcessingFilter; import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint; +import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider; +import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor; +import org.springframework.security.web.authentication.preauth.x509.X509PreAuthenticatedProcessingFilter; import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; import org.springframework.security.web.authentication.www.BasicProcessingFilter; import org.springframework.security.web.authentication.www.BasicProcessingFilterEntryPoint; @@ -149,7 +156,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { * 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, element); +// ConfigUtils.registerProviderManagerIfNecessary(pc, element); CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element)); pc.pushContainingComponent(compositeDef); @@ -170,6 +177,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { BeanDefinition cpf = null; BeanReference sessionRegistryRef = null; + BeanReference concurrentSessionControllerRef = null; BeanDefinition concurrentSessionFilter = createConcurrentSessionFilterAndRelatedBeansIfRequired(element, pc); BeanDefinition scpf = createSecurityContextPersistenceFilter(element, pc); @@ -179,19 +187,23 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { concurrentSessionFilter.getPropertyValues().getPropertyValue("sessionRegistry").getValue(); logger.info("Concurrent session filter in use, setting 'forceEagerSessionCreation' to true"); scpf.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.TRUE); + concurrentSessionControllerRef = createConcurrentSessionController(element, concurrentSessionFilter, sessionRegistryRef, pc); } + ManagedList authenticationProviders = new ManagedList(); + BeanReference authenticationManager = createAuthenticationManager(element, pc, authenticationProviders, concurrentSessionControllerRef); + BeanDefinition servApiFilter = createServletApiFilter(element, pc); // 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); - RootBeanDefinition rememberMeFilter = createRememberMeFilter(element, pc); + RootBeanDefinition rememberMeFilter = createRememberMeFilter(element, pc, authenticationManager); BeanDefinition anonFilter = createAnonymousFilter(element, pc); BeanDefinition etf = createExceptionTranslationFilter(element, pc, allowSessionCreation); RootBeanDefinition sfpf = createSessionFixationProtectionFilter(pc, element.getAttribute(ATT_SESSION_FIXATION_PROTECTION), sessionRegistryRef); - BeanDefinition fsi = createFilterSecurityInterceptor(element, pc, matcher, convertPathsToLowerCase); + BeanDefinition fsi = createFilterSecurityInterceptor(element, pc, matcher, convertPathsToLowerCase, authenticationManager); String portMapperName = pc.getReaderContext().registerWithGeneratedName(portMapper); if (channelRequestMap.size() > 0) { @@ -204,9 +216,11 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { pc.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER, sfpf); } - 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); + final FilterAndEntryPoint basic = createBasicFilter(element, pc, autoConfig, authenticationManager); + final FilterAndEntryPoint form = createFormLoginFilter(element, pc, autoConfig, allowSessionCreation, + sfpf, authenticationManager); + final FilterAndEntryPoint openID = createOpenIDLoginFilter(element, pc, autoConfig, allowSessionCreation, + sfpf, authenticationManager); String rememberMeServicesId = null; if (rememberMeFilter != null) { @@ -233,7 +247,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { injectSessionRegistryRef(openID.filter, sessionRegistryRef); } - FilterAndEntryPoint x509 = createX509Filter(element, pc); + String x509ProviderId = null; + FilterAndEntryPoint x509 = createX509Filter(element, pc, authenticationManager); BeanMetadataElement entryPoint = selectEntryPoint(element, pc, basic, form, openID, x509); etf.getPropertyValues().addPropertyValue("authenticationEntryPoint", entryPoint); @@ -256,6 +271,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { if (x509.filter != null) { unorderedFilterChain.add(new OrderDecorator(x509.filter, X509_FILTER)); + BeanReference x509Provider = createX509Provider(element, pc); + x509ProviderId = x509Provider.getBeanName(); + authenticationProviders.add(x509Provider); } if (form.filter != null) { @@ -264,6 +282,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { if (openID.filter != null) { unorderedFilterChain.add(new OrderDecorator(openID.filter, OPENID_PROCESSING_FILTER)); + authenticationProviders.add(createOpenIDProvider(element, pc)); } if (loginPageGenerationFilter != null) { @@ -280,10 +299,12 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { if (rememberMeFilter != null) { unorderedFilterChain.add(new OrderDecorator(rememberMeFilter, REMEMBER_ME_FILTER)); + authenticationProviders.add(createRememberMeProvider(rememberMeFilter, pc, rememberMeServicesId)); } if (anonFilter != null) { unorderedFilterChain.add(new OrderDecorator(anonFilter, ANONYMOUS_FILTER)); + authenticationProviders.add(createAnonymousProvider(anonFilter, pc)); } unorderedFilterChain.add(new OrderDecorator(etf, EXCEPTION_TRANSLATION_FILTER)); @@ -313,7 +334,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { registerFilterChainProxy(pc, filterChainMap, matcher, source); BeanDefinitionBuilder userServiceInjector = BeanDefinitionBuilder.rootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class); - userServiceInjector.addConstructorArgValue(BeanIds.X509_AUTH_PROVIDER); + userServiceInjector.addConstructorArgValue(x509ProviderId); userServiceInjector.addConstructorArgValue(rememberMeServicesId); userServiceInjector.addConstructorArgValue(rememberMeServicesId); userServiceInjector.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); @@ -323,6 +344,28 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { return null; } + /** + * Creates the internal AuthentiationManager bean which uses the externally registered (global) one as + * a parent. + * + * All the providers registered by this <http> block will be registered with the internal + * authentication manager, along with the ConcurrentSessionController (if necessary). + */ + private BeanReference createAuthenticationManager(Element element, ParserContext pc, + ManagedList authenticationProviders, BeanReference concurrencyController) { + BeanDefinitionBuilder authManager = BeanDefinitionBuilder.rootBeanDefinition(ProviderManager.class); + authManager.addPropertyReference("parent", BeanIds.AUTHENTICATION_MANAGER); + authManager.addPropertyValue("providers", authenticationProviders); + + if (concurrencyController != null) { + authManager.addPropertyValue("sessionController", concurrencyController); + } + authManager.getRawBeanDefinition().setSource(pc.extractSource(element)); + String id = pc.getReaderContext().registerWithGeneratedName(authManager.getBeanDefinition()); + + return new RuntimeBeanReference(id); + } + private void injectRememberMeServicesRef(RootBeanDefinition bean, String rememberMeServicesId) { if (rememberMeServicesId != null) { bean.getPropertyValues().addPropertyValue("rememberMeServices", new RuntimeBeanReference(rememberMeServicesId)); @@ -367,6 +410,10 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { public int getOrder() { return order; } + + public String toString() { + return bean + ", order = " + order; + } } List buildCustomFilterList(Element element, ParserContext pc) { @@ -420,13 +467,13 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { String grantedAuthority = null; String username = null; String key = null; - Object source = null; + Object source = pc.extractSource(element); - if (element != null) { + if (anonymousElt != null) { grantedAuthority = element.getAttribute("granted-authority"); username = element.getAttribute("username"); key = element.getAttribute("key"); - source = pc.extractSource(element); + source = pc.extractSource(anonymousElt); } if (!StringUtils.hasText(grantedAuthority)) { @@ -449,17 +496,21 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { filter.getPropertyValues().addPropertyValue("userAttribute", username + "," + grantedAuthority); filter.getPropertyValues().addPropertyValue(keyPV); - RootBeanDefinition provider = new RootBeanDefinition(AnonymousAuthenticationProvider.class); - provider.setSource(source); - provider.getPropertyValues().addPropertyValue(keyPV); - - pc.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_AUTHENTICATION_PROVIDER, provider); - ConfigUtils.addAuthenticationProvider(pc, BeanIds.ANONYMOUS_AUTHENTICATION_PROVIDER, element); - return filter; } - private FilterAndEntryPoint createBasicFilter(Element elt, ParserContext pc, boolean autoConfig) { + private BeanReference createAnonymousProvider(BeanDefinition anonFilter, ParserContext pc) { + RootBeanDefinition provider = new RootBeanDefinition(AnonymousAuthenticationProvider.class); + provider.setSource(anonFilter.getSource()); + provider.getPropertyValues().addPropertyValue(anonFilter.getPropertyValues().getPropertyValue("key")); + String id = pc.getReaderContext().registerWithGeneratedName(provider); + pc.registerBeanComponent(new BeanComponentDefinition(provider, id)); + + return new RuntimeBeanReference(id); + } + + private FilterAndEntryPoint createBasicFilter(Element elt, ParserContext pc, + boolean autoConfig, BeanReference authManager) { Element basicAuthElt = DomUtils.getChildElementByTagName(elt, Elements.BASIC_AUTH); String realm = elt.getAttribute(ATT_REALM); @@ -477,23 +528,35 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { entryPoint.getPropertyValues().addPropertyValue("realmName", realm); - pc.getRegistry().registerBeanDefinition(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, entryPoint); + String entryPointId = pc.getReaderContext().registerWithGeneratedName(entryPoint); - filterBuilder.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER)); - filterBuilder.addPropertyValue("authenticationEntryPoint", new RuntimeBeanReference(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT)); + filterBuilder.addPropertyValue("authenticationManager", authManager); + filterBuilder.addPropertyValue("authenticationEntryPoint", new RuntimeBeanReference(entryPointId)); filter = (RootBeanDefinition) filterBuilder.getBeanDefinition(); } return new FilterAndEntryPoint(filter, entryPoint); } - private FilterAndEntryPoint createX509Filter(Element elt, ParserContext pc) { + private FilterAndEntryPoint createX509Filter(Element elt, ParserContext pc, BeanReference authManager) { Element x509Elt = DomUtils.getChildElementByTagName(elt, Elements.X509); RootBeanDefinition filter = null; RootBeanDefinition entryPoint = null; if (x509Elt != null) { - filter = new X509BeanDefinitionParser().parse(x509Elt, pc); + BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(X509PreAuthenticatedProcessingFilter.class); + filterBuilder.getRawBeanDefinition().setSource(pc.extractSource(x509Elt)); + filterBuilder.addPropertyValue("authenticationManager", authManager); + + String regex = x509Elt.getAttribute("subject-principal-regex"); + + if (StringUtils.hasText(regex)) { + SubjectDnX509PrincipalExtractor extractor = new SubjectDnX509PrincipalExtractor(); + extractor.setSubjectDnRegex(regex); + + filterBuilder.addPropertyValue("principalExtractor", extractor); + } + filter = (RootBeanDefinition) filterBuilder.getBeanDefinition(); entryPoint = new RootBeanDefinition(Http403ForbiddenEntryPoint.class); entryPoint.setSource(pc.extractSource(x509Elt)); } @@ -501,6 +564,23 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { return new FilterAndEntryPoint(filter, entryPoint); } + private BeanReference createX509Provider(Element elt, ParserContext pc) { + Element x509Elt = DomUtils.getChildElementByTagName(elt, Elements.X509); + BeanDefinition provider = new RootBeanDefinition(PreAuthenticatedAuthenticationProvider.class); + + String userServiceRef = x509Elt.getAttribute(ATT_USER_SERVICE_REF); + + if (StringUtils.hasText(userServiceRef)) { + RootBeanDefinition preAuthUserService = new RootBeanDefinition(UserDetailsByNameServiceWrapper.class); + preAuthUserService.setSource(pc.extractSource(x509Elt)); + preAuthUserService.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(userServiceRef)); + provider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService", preAuthUserService); + } + + String id = pc.getReaderContext().registerWithGeneratedName(provider); + return new RuntimeBeanReference(id); + } + private BeanDefinition createLogoutFilter(Element elt, boolean autoConfig, ParserContext pc, String rememberMeServicesId) { Element logoutElt = DomUtils.getChildElementByTagName(elt, Elements.LOGOUT); if (logoutElt != null || autoConfig) { @@ -511,17 +591,42 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { return null; } - private RootBeanDefinition createRememberMeFilter(Element elt, ParserContext pc) { + private RootBeanDefinition createRememberMeFilter(Element elt, ParserContext pc, BeanReference authenticationManager) { // 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); + RootBeanDefinition filter = (RootBeanDefinition) new RememberMeBeanDefinitionParser().parse(rememberMeElt, pc); + filter.getPropertyValues().addPropertyValue("authenticationManager", authenticationManager); + return filter; } return null; } + private BeanReference createRememberMeProvider(BeanDefinition filter, ParserContext pc, String servicesId) { + RootBeanDefinition provider = new RootBeanDefinition(RememberMeAuthenticationProvider.class); + provider.setSource(filter.getSource()); + // Locate the RememberMeServices bean and read the "key" property from it + PropertyValue key = null; + if (pc.getRegistry().containsBeanDefinition(servicesId)) { + BeanDefinition services = pc.getRegistry().getBeanDefinition(servicesId); + + key = services.getPropertyValues().getPropertyValue("key"); + } + + if (key == null) { + key = new PropertyValue("key", RememberMeBeanDefinitionParser.DEF_KEY); + } + + provider.getPropertyValues().addPropertyValue(key); + + String id = pc.getReaderContext().registerWithGeneratedName(provider); + pc.registerBeanComponent(new BeanComponentDefinition(provider, id)); + + return new RuntimeBeanReference(id); + } + 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); @@ -602,6 +707,32 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { return sessionControlFilter; } + private BeanReference createConcurrentSessionController(Element elt, BeanDefinition filter, BeanReference sessionRegistry, ParserContext pc) { + BeanDefinitionBuilder controllerBuilder = BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionControllerImpl.class); + Element sessionCtrlElement = DomUtils.getChildElementByTagName(elt, Elements.CONCURRENT_SESSIONS); + controllerBuilder.getRawBeanDefinition().setSource(filter.getSource()); + controllerBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + controllerBuilder.addPropertyValue("sessionRegistry", sessionRegistry); + + String maxSessions = sessionCtrlElement.getAttribute("max-sessions"); + + if (StringUtils.hasText(maxSessions)) { + controllerBuilder.addPropertyValue("maximumSessions", maxSessions); + } + + String exceptionIfMaximumExceeded = sessionCtrlElement.getAttribute("exception-if-maximum-exceeded"); + + if (StringUtils.hasText(exceptionIfMaximumExceeded)) { + controllerBuilder.addPropertyValue("exceptionIfMaximumExceeded", exceptionIfMaximumExceeded); + } + + BeanDefinition controller = controllerBuilder.getBeanDefinition(); + + String id = pc.getReaderContext().registerWithGeneratedName(controller); + pc.registerComponent(new BeanComponentDefinition(controller, id)); + return new RuntimeBeanReference(id); + } + private BeanDefinition createExceptionTranslationFilter(Element element, ParserContext pc, boolean allowSessionCreation) { BeanDefinitionBuilder exceptionTranslationFilterBuilder = BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class); @@ -649,7 +780,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { } @SuppressWarnings("unchecked") - private BeanDefinition createFilterSecurityInterceptor(Element element, ParserContext pc, UrlMatcher matcher, boolean convertPathsToLowerCase) { + private BeanDefinition createFilterSecurityInterceptor(Element element, ParserContext pc, UrlMatcher matcher, + boolean convertPathsToLowerCase, BeanReference authManager) { BeanDefinitionBuilder fidsBuilder; boolean useExpressions = "true".equals(element.getAttribute(ATT_USE_EXPRESSIONS)); @@ -699,7 +831,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class); builder.addPropertyReference("accessDecisionManager", accessManagerId); - builder.addPropertyReference("authenticationManager", BeanIds.AUTHENTICATION_MANAGER); + builder.addPropertyValue("authenticationManager", authManager); if ("false".equals(element.getAttribute(ATT_ONCE_PER_REQUEST))) { builder.addPropertyValue("observeOncePerRequest", Boolean.FALSE); @@ -712,8 +844,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { private BeanDefinition createChannelProcessingFilter(ParserContext pc, UrlMatcher matcher, LinkedHashMap> channelRequestMap, String portMapperBeanName) { RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class); - channelFilter.getPropertyValues().addPropertyValue("channelDecisionManager", - new RuntimeBeanReference(BeanIds.CHANNEL_DECISION_MANAGER)); + DefaultFilterInvocationSecurityMetadataSource channelFilterInvDefSource = new DefaultFilterInvocationSecurityMetadataSource(matcher, channelRequestMap); channelFilterInvDefSource.setStripQueryStringFromUrls(matcher instanceof AntUrlPathMatcher); @@ -734,7 +865,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { channelProcessors.add(inSecureChannelProcessor); channelDecisionManager.getPropertyValues().addPropertyValue("channelProcessors", channelProcessors); - pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_DECISION_MANAGER, channelDecisionManager); + String id = pc.getReaderContext().registerWithGeneratedName(channelDecisionManager); + channelFilter.getPropertyValues().addPropertyValue("channelDecisionManager", new RuntimeBeanReference(id)); return channelFilter; } @@ -757,7 +889,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { return null; } - private FilterAndEntryPoint createFormLoginFilter(Element element, ParserContext pc, boolean autoConfig, boolean allowSessionCreation, RootBeanDefinition sfpf) { + private FilterAndEntryPoint createFormLoginFilter(Element element, ParserContext pc, boolean autoConfig, + boolean allowSessionCreation, RootBeanDefinition sfpf, BeanReference authManager) { RootBeanDefinition formLoginFilter = null; RootBeanDefinition formLoginEntryPoint = null; @@ -774,12 +907,14 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { if (formLoginFilter != null) { formLoginFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation)); + formLoginFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager); } return new FilterAndEntryPoint(formLoginFilter, formLoginEntryPoint); } - private FilterAndEntryPoint createOpenIDLoginFilter(Element element, ParserContext pc, boolean autoConfig, boolean allowSessionCreation, RootBeanDefinition sfpf) { + private FilterAndEntryPoint createOpenIDLoginFilter(Element element, ParserContext pc, boolean autoConfig, + boolean allowSessionCreation, RootBeanDefinition sfpf, BeanReference authManager) { Element openIDLoginElt = DomUtils.getChildElementByTagName(element, Elements.OPENID_LOGIN); RootBeanDefinition openIDFilter = null; RootBeanDefinition openIDEntryPoint = null; @@ -791,28 +926,32 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { parser.parse(openIDLoginElt, pc, sfpf); openIDFilter = parser.getFilterBean(); openIDEntryPoint = parser.getEntryPointBean(); - - BeanDefinitionBuilder openIDProviderBuilder = - BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_AUTHENTICATION_PROVIDER_CLASS); - - String userService = openIDLoginElt.getAttribute(ATT_USER_SERVICE_REF); - - if (StringUtils.hasText(userService)) { - openIDProviderBuilder.addPropertyReference("userDetailsService", userService); - } - - BeanDefinition openIDProvider = openIDProviderBuilder.getBeanDefinition(); - pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_PROVIDER, openIDProvider); - ConfigUtils.addAuthenticationProvider(pc, BeanIds.OPEN_ID_PROVIDER, element); } if (openIDFilter != null) { openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation)); + openIDFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager); } return new FilterAndEntryPoint(openIDFilter, openIDEntryPoint); } + private BeanReference createOpenIDProvider(Element elt, ParserContext pc) { + Element openIDLoginElt = DomUtils.getChildElementByTagName(elt, Elements.OPENID_LOGIN); + BeanDefinitionBuilder openIDProviderBuilder = + BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_AUTHENTICATION_PROVIDER_CLASS); + + String userService = openIDLoginElt.getAttribute(ATT_USER_SERVICE_REF); + + if (StringUtils.hasText(userService)) { + openIDProviderBuilder.addPropertyReference("userDetailsService", userService); + } + + BeanDefinition openIDProvider = openIDProviderBuilder.getBeanDefinition(); + String id = pc.getReaderContext().registerWithGeneratedName(openIDProvider); + return new RuntimeBeanReference(id); + } + class FilterAndEntryPoint { RootBeanDefinition filter; RootBeanDefinition entryPoint; 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 e6e768d69b..058c2a667a 100644 --- a/config/src/main/java/org/springframework/security/config/RememberMeBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/RememberMeBeanDefinitionParser.java @@ -14,7 +14,6 @@ import org.springframework.security.web.authentication.rememberme.JdbcTokenRepos 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.authentication.RememberMeAuthenticationProvider; import org.springframework.util.StringUtils; import org.w3c.dom.Element; @@ -115,26 +114,15 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser { pc.getRegistry().registerAlias(servicesName, element.getAttribute(ATT_SERVICES_ALIAS)); } - RootBeanDefinition provider = new RootBeanDefinition(RememberMeAuthenticationProvider.class); - provider.setSource(source); - provider.getPropertyValues().addPropertyValue(ATT_KEY, key); - pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_AUTHENTICATION_PROVIDER, provider); - ConfigUtils.addAuthenticationProvider(pc, BeanIds.REMEMBER_ME_AUTHENTICATION_PROVIDER, element); - BeanDefinition filter = createFilter(pc, source); pc.popAndRegisterContainingComponent(); return filter; } - String getServicesName() { - return servicesName; - } - private BeanDefinition createFilter(ParserContext pc, Object source) { BeanDefinitionBuilder filter = BeanDefinitionBuilder.rootBeanDefinition(RememberMeProcessingFilter.class); filter.getRawBeanDefinition().setSource(source); - filter.addPropertyReference("authenticationManager", BeanIds.AUTHENTICATION_MANAGER); filter.addPropertyReference("rememberMeServices", servicesName); return filter.getBeanDefinition(); diff --git a/config/src/main/java/org/springframework/security/config/X509BeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/X509BeanDefinitionParser.java deleted file mode 100644 index 586ac53b68..0000000000 --- a/config/src/main/java/org/springframework/security/config/X509BeanDefinitionParser.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.springframework.security.config; - -import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint; -import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider; -import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor; -import org.springframework.security.web.authentication.preauth.x509.X509PreAuthenticatedProcessingFilter; -import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper; -import org.springframework.beans.factory.xml.BeanDefinitionParser; -import org.springframework.beans.factory.xml.ParserContext; -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.util.StringUtils; - -import org.w3c.dom.Element; - -/** - * Parses x509 element in namespace, registering an {@link X509PreAuthenticatedProcessingFilter} instance and a - * {@link Http403ForbiddenEntryPoint}. - * - * @author Luke Taylor - * @version $Id$ - * @since 2.0 - */ -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 RootBeanDefinition parse(Element element, ParserContext parserContext) { - BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(X509PreAuthenticatedProcessingFilter.class); - Object source = parserContext.extractSource(element); - filterBuilder.getRawBeanDefinition().setSource(source); - - String regex = element.getAttribute(ATT_REGEX); - - if (StringUtils.hasText(regex)) { - SubjectDnX509PrincipalExtractor extractor = new SubjectDnX509PrincipalExtractor(); - extractor.setSubjectDnRegex(regex); - - filterBuilder.addPropertyValue("principalExtractor", extractor); - } - - BeanDefinition provider = new RootBeanDefinition(PreAuthenticatedAuthenticationProvider.class); - parserContext.getRegistry().registerBeanDefinition(BeanIds.X509_AUTH_PROVIDER, provider); - ConfigUtils.addAuthenticationProvider(parserContext, BeanIds.X509_AUTH_PROVIDER, element); - - String userServiceRef = element.getAttribute(ATT_USER_SERVICE_REF); - - if (StringUtils.hasText(userServiceRef)) { - RootBeanDefinition preAuthUserService = new RootBeanDefinition(UserDetailsByNameServiceWrapper.class); - preAuthUserService.setSource(source); - preAuthUserService.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(userServiceRef)); - provider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService", preAuthUserService); - } - - filterBuilder.addPropertyReference("authenticationManager", BeanIds.AUTHENTICATION_MANAGER); - - return (RootBeanDefinition) filterBuilder.getBeanDefinition(); - } -} diff --git a/config/src/test/java/org/springframework/security/config/FilterSecurityMetadataSourceBeanDefinitionParserTests.java b/config/src/test/java/org/springframework/security/config/FilterSecurityMetadataSourceBeanDefinitionParserTests.java index 201dd73b56..d4baae64b7 100644 --- a/config/src/test/java/org/springframework/security/config/FilterSecurityMetadataSourceBeanDefinitionParserTests.java +++ b/config/src/test/java/org/springframework/security/config/FilterSecurityMetadataSourceBeanDefinitionParserTests.java @@ -67,6 +67,7 @@ public class FilterSecurityMetadataSourceBeanDefinitionParserTests { " " + " " + " " + + " "+ "" + ConfigTestUtils.AUTH_PROVIDER_XML); 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 976c4af77f..e9a29635de 100644 --- a/config/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java +++ b/config/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java @@ -28,6 +28,7 @@ import org.springframework.security.access.SecurityConfig; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.concurrent.ConcurrentLoginException; +import org.springframework.security.authentication.concurrent.ConcurrentSessionController; import org.springframework.security.authentication.concurrent.ConcurrentSessionControllerImpl; import org.springframework.security.authentication.concurrent.SessionRegistryImpl; import org.springframework.security.config.util.InMemoryXmlApplicationContext; @@ -565,7 +566,7 @@ public class HttpSecurityBeanDefinitionParserTests { assertTrue(filters.get(0) instanceof ConcurrentSessionFilter); assertNotNull(appContext.getBean("seshRegistry")); - assertNotNull(appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER)); + assertNotNull(getConcurrentSessionController()); } @Test @@ -581,8 +582,7 @@ public class HttpSecurityBeanDefinitionParserTests { getFilter(ConcurrentSessionFilter.class),"sessionRegistry"); Object sessionRegistryFromFormLoginFilter = FieldUtils.getFieldValue( getFilter(UsernamePasswordAuthenticationProcessingFilter.class),"sessionRegistry"); - Object sessionRegistryFromController = FieldUtils.getFieldValue( - appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER),"sessionRegistry"); + Object sessionRegistryFromController = FieldUtils.getFieldValue(getConcurrentSessionController(),"sessionRegistry"); Object sessionRegistryFromFixationFilter = FieldUtils.getFieldValue( getFilter(SessionFixationProtectionFilter.class),"sessionRegistry"); @@ -592,7 +592,9 @@ public class HttpSecurityBeanDefinitionParserTests { // SEC-1143 assertSame(sessionRegistry, sessionRegistryFromFormLoginFilter); } - +/* +// These no longer apply with the internal authentication manager in and it won't be possible to check the +// Validity of the configuration against the central AuthenticationManager when we allow more than one element. @Test(expected=BeanDefinitionParsingException.class) public void concurrentSessionSupportCantBeUsedWithIndependentControllerBean() throws Exception { setContext( @@ -620,14 +622,14 @@ public class HttpSecurityBeanDefinitionParserTests { "" + "" + AUTH_PROVIDER_XML); } - +*/ @Test(expected=ConcurrentLoginException.class) public void concurrentSessionMaxSessionsIsCorrectlyConfigured() throws Exception { setContext( "" + " " + "" + AUTH_PROVIDER_XML); - ConcurrentSessionControllerImpl seshController = (ConcurrentSessionControllerImpl) appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER); + ConcurrentSessionControllerImpl seshController = (ConcurrentSessionControllerImpl) getConcurrentSessionController(); UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("bob", "pass"); // Register 2 sessions and then check a third MockHttpServletRequest req = new MockHttpServletRequest(); @@ -919,4 +921,14 @@ public class HttpSecurityBeanDefinitionParserTests { return ((RememberMeProcessingFilter)getFilter(RememberMeProcessingFilter.class)).getRememberMeServices(); } + @SuppressWarnings("unchecked") + private ConcurrentSessionController getConcurrentSessionController() { + Map beans = appContext.getBeansOfType(ConcurrentSessionController.class); + + if (beans.size() == 0) { + return null; + } + return (ConcurrentSessionController) new ArrayList(beans.values()).get(0); + } + } diff --git a/core/src/main/java/org/springframework/security/authentication/ProviderManager.java b/core/src/main/java/org/springframework/security/authentication/ProviderManager.java index a6b57826ea..087c3a1b90 100644 --- a/core/src/main/java/org/springframework/security/authentication/ProviderManager.java +++ b/core/src/main/java/org/springframework/security/authentication/ProviderManager.java @@ -15,10 +15,12 @@ package org.springframework.security.authentication; +import java.util.Collections; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.InitializingBean; import org.springframework.context.MessageSource; import org.springframework.context.MessageSourceAware; import org.springframework.context.support.MessageSourceAccessor; @@ -69,7 +71,7 @@ import org.springframework.util.Assert; * @see ConcurrentSessionController * @see DefaultAuthenticationEventPublisher */ -public class ProviderManager extends AbstractAuthenticationManager implements MessageSourceAware { +public class ProviderManager extends AbstractAuthenticationManager implements MessageSourceAware, InitializingBean { //~ Static fields/initializers ===================================================================================== private static final Log logger = LogFactory.getLog(ProviderManager.class); @@ -78,12 +80,19 @@ public class ProviderManager extends AbstractAuthenticationManager implements Me private AuthenticationEventPublisher eventPublisher = new NullEventPublisher(); private ConcurrentSessionController sessionController = new NullConcurrentSessionController(); - private List providers; + private List providers = Collections.emptyList(); protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); private AuthenticationManager parent; //~ Methods ======================================================================================================== + public void afterPropertiesSet() throws Exception { + if (parent == null && providers.isEmpty()) { + throw new IllegalArgumentException("A parent AuthenticationManager or a list " + + "of AuthenticationProviders is required"); + } + } + /** * Attempts to authenticate the passed {@link Authentication} object. *

@@ -222,8 +231,7 @@ public class ProviderManager extends AbstractAuthenticationManager implements Me */ @SuppressWarnings("unchecked") public void setProviders(List providers) { - Assert.notEmpty(providers, "A list of AuthenticationProviders is required"); - + Assert.notNull(providers); for(Object currentObject : providers) { Assert.isInstanceOf(AuthenticationProvider.class, currentObject, "Can only provide AuthenticationProvider instances"); } diff --git a/core/src/test/java/org/springframework/security/authentication/ProviderManagerTests.java b/core/src/test/java/org/springframework/security/authentication/ProviderManagerTests.java index 8c4a86067b..81acc9a7f0 100644 --- a/core/src/test/java/org/springframework/security/authentication/ProviderManagerTests.java +++ b/core/src/test/java/org/springframework/security/authentication/ProviderManagerTests.java @@ -110,10 +110,9 @@ public class ProviderManagerTests { } @Test(expected=IllegalArgumentException.class) - public void testStartupFailsIfProviderListNull() throws Exception { + public void testStartupFailsIfProvidersNotSet() throws Exception { ProviderManager mgr = new ProviderManager(); - - mgr.setProviders(null); + mgr.afterPropertiesSet(); } @Test diff --git a/samples/tutorial/src/main/webapp/WEB-INF/applicationContext-security.xml b/samples/tutorial/src/main/webapp/WEB-INF/applicationContext-security.xml index 499572b3c0..96593ccb17 100644 --- a/samples/tutorial/src/main/webapp/WEB-INF/applicationContext-security.xml +++ b/samples/tutorial/src/main/webapp/WEB-INF/applicationContext-security.xml @@ -33,9 +33,9 @@ Uncomment to enable X509 client authentication support --> - - --> +