Sfoglia il codice sorgente

Move "realm" attribute to be on <http> element rather than <http-basic>.
This faciltiates reuse with other mechanisms (like Digest) whilst also
moving towards the <http-auto-configure> element (which benefits from
having shared configuration in <http> as opposed to mechanism-specific
elements).

Ben Alex 18 anni fa
parent
commit
2441ab6d9a

+ 11 - 9
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;
     }

+ 9 - 1
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);

+ 44 - 28
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
      *
      * <ol>
-     * <li>If only one use that.</li>
-     * <li>If more than one, check the default interactive login Ids in order of preference</li>
-     * <li>throw an exception (for now). TODO: Examine additional beans and types and make decision</li>
+     * <li>If only one, use that one.</li>
+     * <li>If more than one, use the form login entry point (if form login is being used)</li>
+     * <li>If still ambiguous, throw an exception (for now). TODO: Examine additional beans and types and make decision</li>
      * </ol>
      *
      */
-    private void configureAuthenticationEntryPoint(ConfigurableListableBeanFactory beanFactory) {
+    private void injectAuthenticationEntryPointIntoExceptionTranslationFilter(ConfigurableListableBeanFactory beanFactory) {
         logger.info("Selecting AuthenticationEntryPoint for use in ExceptionTranslationFilter");
 
         BeanDefinition etf =

+ 6 - 4
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.

+ 7 - 7
core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd

@@ -146,6 +146,11 @@
         <xs:documentation>Optional attribute specifying the ID of the AccessDecisionManager implementation which should be used for authorizing HTTP requests.</xs:documentation>
       </xs:annotation>
     </xs:attribute>
+    <xs:attribute name="realm" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>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".</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
   </xs:attributeGroup>
   <xs:element name="intercept-url">
     <xs:annotation>
@@ -263,15 +268,10 @@
   </xs:attributeGroup>
   <xs:element name="http-basic">
     <xs:annotation>
-      <xs:documentation>Adds support for basic authentication</xs:documentation>
+      <xs:documentation>Adds support for basic authentication (this is an element to permit future expansion, such as supporting an "ignoreFailure" attribute)</xs:documentation>
     </xs:annotation>
-    <xs:complexType>
-      <xs:attributeGroup ref="security:http-basic.attlist"/>
-    </xs:complexType>
+    <xs:complexType/>
   </xs:element>
-  <xs:attributeGroup name="http-basic.attlist">
-    <xs:attribute name="realm" use="required" type="xs:string"/>
-  </xs:attributeGroup>
   <xs:element name="concurrent-session-control">
     <xs:annotation>
       <xs:documentation>Adds support for concurrent session control, allowing limits to be placed on the number of sessions a user can have.</xs:documentation>

+ 1 - 1
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
         <form-login loginUrl="/j_spring_security_check" />
 
         <!-- Default basic auth configuration. Will create filter and entry point -->
-        <http-basic realm="NamespaceTestRealm" />
+        <http-basic/>
 
         <!-- Default logout configuration -->
         <logout logoutUrl="/j_spring_security_logout" logoutSuccessUrl="/" invalidateSession="true" />

+ 1 - 1
samples/tutorial/src/main/webapp/WEB-INF/applicationContext-security-ns.xml

@@ -19,7 +19,7 @@
 
         <form-login />
         <anonymous />
-        <http-basic realm="SpringSecurityTutorialApp"  />
+        <http-basic />
         <logout />
         <concurrent-session-control maxSessions="1" exceptionIfMaximumExceeded="true"/>