From 2441ab6d9acb1f80ddd4e23296f3cbc23994b5e6 Mon Sep 17 00:00:00 2001 From: Ben Alex Date: Tue, 4 Dec 2007 08:02:40 +0000 Subject: [PATCH] Move "realm" attribute to be on element rather than . This faciltiates reuse with other mechanisms (like Digest) whilst also moving towards the element (which benefits from having shared configuration in as opposed to mechanism-specific elements). --- ...sicAuthenticationBeanDefinitionParser.java | 20 +++--- .../HttpSecurityBeanDefinitionParser.java | 10 ++- .../HttpSecurityConfigPostProcessor.java | 72 +++++++++++-------- .../security/config/spring-security-2.0.rnc | 10 +-- .../security/config/spring-security-2.0.xsd | 14 ++-- .../security/config/http-security.xml | 2 +- .../applicationContext-security-ns.xml | 2 +- 7 files changed, 79 insertions(+), 51 deletions(-) diff --git a/core/src/main/java/org/springframework/security/config/BasicAuthenticationBeanDefinitionParser.java b/core/src/main/java/org/springframework/security/config/BasicAuthenticationBeanDefinitionParser.java index a2ddc3dafb..e7f7b4d988 100644 --- a/core/src/main/java/org/springframework/security/config/BasicAuthenticationBeanDefinitionParser.java +++ b/core/src/main/java/org/springframework/security/config/BasicAuthenticationBeanDefinitionParser.java @@ -1,6 +1,7 @@ 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.BeanDefinitionBuilder; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; @@ -18,26 +19,27 @@ import org.w3c.dom.Element; * @version $Id$ */ public class BasicAuthenticationBeanDefinitionParser implements BeanDefinitionParser { - static final String ATT_REALM = "realm"; + private String realmName; + + public BasicAuthenticationBeanDefinitionParser(String realmName) { + this.realmName = realmName; + } public BeanDefinition parse(Element elt, ParserContext parserContext) { BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicProcessingFilter.class); RootBeanDefinition entryPoint = new RootBeanDefinition(BasicProcessingFilterEntryPoint.class); - String realm = elt.getAttribute(ATT_REALM); - - entryPoint.getPropertyValues().addPropertyValue("realmName", realm); + entryPoint.getPropertyValues().addPropertyValue("realmName", realmName); filterBuilder.addPropertyValue("authenticationEntryPoint", entryPoint); + parserContext.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)); - // TODO: Remove autowiring approach from here. - // Detect auth manager - filterBuilder.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE); - parserContext.getRegistry().registerBeanDefinition(BeanIds.BASIC_AUTHENTICATION_FILTER, filterBuilder.getBeanDefinition()); - parserContext.getRegistry().registerBeanDefinition(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, entryPoint); return null; } diff --git a/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java b/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java index b55ef50f07..c4ed8cd450 100644 --- a/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java +++ b/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java @@ -44,6 +44,9 @@ import java.util.Map; */ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { + static final String ATT_REALM = "realm"; + static final String DEF_REALM = "Spring Security Application"; + static final String ATT_PATH_PATTERN = "pattern"; static final String ATT_PATTERN_TYPE = "pathType"; static final String ATT_PATTERN_TYPE_REGEX = "regex"; @@ -149,11 +152,16 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { if (formLoginElt != null) { new FormLoginBeanDefinitionParser().parse(formLoginElt, parserContext); } + + String realm = element.getAttribute(ATT_REALM); + if (!StringUtils.hasText(realm)) { + realm = DEF_REALM; + } Element basicAuthElt = DomUtils.getChildElementByTagName(element, Elements.BASIC_AUTH); if (basicAuthElt != null) { - new BasicAuthenticationBeanDefinitionParser().parse(basicAuthElt, parserContext); + new BasicAuthenticationBeanDefinitionParser(realm).parse(basicAuthElt, parserContext); } registry.registerBeanDefinition(BeanIds.FILTER_CHAIN_PROXY, filterChainProxy); diff --git a/core/src/main/java/org/springframework/security/config/HttpSecurityConfigPostProcessor.java b/core/src/main/java/org/springframework/security/config/HttpSecurityConfigPostProcessor.java index dd8e8e280a..8a4a13d090 100644 --- a/core/src/main/java/org/springframework/security/config/HttpSecurityConfigPostProcessor.java +++ b/core/src/main/java/org/springframework/security/config/HttpSecurityConfigPostProcessor.java @@ -1,11 +1,15 @@ package org.springframework.security.config; -import org.springframework.security.concurrent.ConcurrentSessionFilter; -import org.springframework.security.context.HttpSessionContextIntegrationFilter; -import org.springframework.security.ui.AbstractProcessingFilter; -import org.springframework.security.ui.AuthenticationEntryPoint; -import org.springframework.security.ui.rememberme.RememberMeServices; -import org.springframework.security.util.FilterChainProxy; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.servlet.Filter; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanDefinition; @@ -13,23 +17,21 @@ import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.core.OrderComparator; import org.springframework.core.Ordered; +import org.springframework.security.concurrent.ConcurrentSessionFilter; +import org.springframework.security.context.HttpSessionContextIntegrationFilter; +import org.springframework.security.ui.AbstractProcessingFilter; +import org.springframework.security.ui.AuthenticationEntryPoint; +import org.springframework.security.ui.basicauth.BasicProcessingFilter; +import org.springframework.security.ui.rememberme.RememberMeServices; +import org.springframework.security.util.FilterChainProxy; import org.springframework.util.Assert; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import javax.servlet.Filter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - /** * Responsible for tying up the HTTP security configuration - building ordered filter stack and linking up * with other beans. * * @author Luke Taylor + * @author Ben Alex * @version $Id$ */ public class HttpSecurityConfigPostProcessor implements BeanFactoryPostProcessor, Ordered { @@ -42,16 +44,16 @@ public class HttpSecurityConfigPostProcessor implements BeanFactoryPostProcessor ConfigUtils.configureSecurityInterceptor(beanFactory, securityInterceptor); - configureRememberMeSerices(beanFactory); + injectUserDetailsServiceIntoRememberMeServices(beanFactory); - configureAuthenticationEntryPoint(beanFactory); + injectAuthenticationEntryPointIntoExceptionTranslationFilter(beanFactory); - configureAuthenticationFilter(beanFactory); + injectRememberMeServicesIntoFiltersRequiringIt(beanFactory); configureFilterChain(beanFactory); } - private void configureRememberMeSerices(ConfigurableListableBeanFactory beanFactory) { + private void injectUserDetailsServiceIntoRememberMeServices(ConfigurableListableBeanFactory beanFactory) { try { BeanDefinition rememberMeServices = beanFactory.getBeanDefinition(BeanIds.REMEMBER_ME_SERVICES); @@ -66,7 +68,7 @@ public class HttpSecurityConfigPostProcessor implements BeanFactoryPostProcessor * Sets the authentication manager, (and remember-me services, if required) on any instances of * AbstractProcessingFilter */ - private void configureAuthenticationFilter(ConfigurableListableBeanFactory beanFactory) { + private void injectRememberMeServicesIntoFiltersRequiringIt(ConfigurableListableBeanFactory beanFactory) { Map beans = beanFactory.getBeansOfType(RememberMeServices.class); RememberMeServices rememberMeServices = null; @@ -75,29 +77,43 @@ public class HttpSecurityConfigPostProcessor implements BeanFactoryPostProcessor rememberMeServices = (RememberMeServices) beans.values().toArray()[0]; } - Iterator authFilters = beanFactory.getBeansOfType(AbstractProcessingFilter.class).values().iterator(); + // Address AbstractProcessingFilter instances + Iterator filters = beanFactory.getBeansOfType(AbstractProcessingFilter.class).values().iterator(); - while (authFilters.hasNext()) { - AbstractProcessingFilter filter = (AbstractProcessingFilter) authFilters.next(); + while (filters.hasNext()) { + AbstractProcessingFilter filter = (AbstractProcessingFilter) filters.next(); if (rememberMeServices != null) { logger.info("Using RememberMeServices " + rememberMeServices + " with filter " + filter); filter.setRememberMeServices(rememberMeServices); } } + + // Address BasicProcessingFilter instance, if it exists + // 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 filter = (BasicProcessingFilter) getBeanOfType(BasicProcessingFilter.class, beanFactory); + + if (filter != null && rememberMeServices != null) { + logger.info("Using RememberMeServices " + rememberMeServices + " with filter " + filter); + filter.setRememberMeServices(rememberMeServices); + } + } /** * Selects the entry point that should be used in ExceptionTranslationFilter. Strategy is * *
    - *
  1. If only one use that.
  2. - *
  3. If more than one, check the default interactive login Ids in order of preference
  4. - *
  5. throw an exception (for now). TODO: Examine additional beans and types and make decision
  6. + *
  7. If only one, use that one.
  8. + *
  9. If more than one, use the form login entry point (if form login is being used)
  10. + *
  11. If still ambiguous, throw an exception (for now). TODO: Examine additional beans and types and make decision
  12. *
* */ - private void configureAuthenticationEntryPoint(ConfigurableListableBeanFactory beanFactory) { + private void injectAuthenticationEntryPointIntoExceptionTranslationFilter(ConfigurableListableBeanFactory beanFactory) { logger.info("Selecting AuthenticationEntryPoint for use in ExceptionTranslationFilter"); BeanDefinition etf = diff --git a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc index 0dc483bb50..c8189503e3 100644 --- a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc +++ b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc @@ -71,6 +71,9 @@ http.attlist &= http.attlist &= ## Optional attribute specifying the ID of the AccessDecisionManager implementation which should be used for authorizing HTTP requests. attribute accessDecisionManager {xsd:string}? +http.attlist &= + ## 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". + attribute realm {xsd:string}? intercept-url = @@ -129,10 +132,9 @@ filter-chain.attlist &= attribute filters {xsd:string} http-basic = - ## Adds support for basic authentication - element http-basic {http-basic.attlist, empty} -http-basic.attlist &= - attribute realm {xsd:string} + ## Adds support for basic authentication (this is an element to permit future expansion, such as supporting an "ignoreFailure" attribute) + element http-basic {empty} + concurrent-session-control = ## Adds support for concurrent session control, allowing limits to be placed on the number of sessions a user can have. diff --git a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd index 83e4d23a01..94abcf4126 100644 --- a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd +++ b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd @@ -146,6 +146,11 @@ 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". + + @@ -263,15 +268,10 @@ - Adds support for basic authentication + Adds support for basic authentication (this is an element to permit future expansion, such as supporting an "ignoreFailure" attribute) - - - + - - - Adds support for concurrent session control, allowing limits to be placed on the number of sessions a user can have. diff --git a/core/src/test/resources/org/springframework/security/config/http-security.xml b/core/src/test/resources/org/springframework/security/config/http-security.xml index f7fa78a0c4..1101957f43 100644 --- a/core/src/test/resources/org/springframework/security/config/http-security.xml +++ b/core/src/test/resources/org/springframework/security/config/http-security.xml @@ -15,7 +15,7 @@ http://www.springframework.org/schema/security http://www.springframework.org/sc - + diff --git a/samples/tutorial/src/main/webapp/WEB-INF/applicationContext-security-ns.xml b/samples/tutorial/src/main/webapp/WEB-INF/applicationContext-security-ns.xml index 0a26951570..bd351fb7ee 100644 --- a/samples/tutorial/src/main/webapp/WEB-INF/applicationContext-security-ns.xml +++ b/samples/tutorial/src/main/webapp/WEB-INF/applicationContext-security-ns.xml @@ -19,7 +19,7 @@ - +