Browse Source

SEC-1196: Introduce AuthenticationManagerDelegator is MethodSecurityInterceptor which is configured by global-method-security. Prevents regression of SEC-933 caused by eager init of AuthenitcationManager and dependent beans

Luke Taylor 16 years ago
parent
commit
e40b9fbc75

+ 0 - 1
config/src/main/java/org/springframework/security/config/BeanIds.java

@@ -27,7 +27,6 @@ public abstract class BeanIds {
     public static final String OPEN_ID_ENTRY_POINT = "_openIDFilterEntryPoint";
 
     public static final String FILTER_CHAIN_PROXY = "_filterChainProxy";
-    public static final String LDAP_AUTHENTICATION_PROVIDER = "_ldapAuthenticationProvider";
 
     public static final String METHOD_SECURITY_METADATA_SOURCE_ADVISOR = "_methodSecurityMetadataSourceAdvisor";
     public static final String EMBEDDED_APACHE_DS = "_apacheDirectoryServerContainer";

+ 36 - 1
config/src/main/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParser.java

@@ -10,6 +10,9 @@ import java.util.Map;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.aop.config.AopNamespaceUtils;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
 import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.beans.factory.config.RuntimeBeanReference;
 import org.springframework.beans.factory.parsing.BeanComponentDefinition;
@@ -38,7 +41,12 @@ import org.springframework.security.access.prepost.PrePostAnnotationSecurityMeta
 import org.springframework.security.access.vote.AffirmativeBased;
 import org.springframework.security.access.vote.AuthenticatedVoter;
 import org.springframework.security.access.vote.RoleVoter;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.ProviderManager;
 import org.springframework.security.config.BeanIds;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 import org.springframework.util.xml.DomUtils;
 import org.w3c.dom.Element;
@@ -264,7 +272,7 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
         bldr.getRawBeanDefinition().setSource(source);
 
         bldr.addPropertyReference("accessDecisionManager", accessManagerId);
-        bldr.addPropertyReference("authenticationManager", BeanIds.AUTHENTICATION_MANAGER);
+        bldr.addPropertyValue("authenticationManager", new RootBeanDefinition(AuthenticationManagerDelegator.class));
         bldr.addPropertyReference("securityMetadataSource", DELEGATING_METHOD_DEFINITION_SOURCE_ID);
         if (StringUtils.hasText(runAsManagerId)) {
             bldr.addPropertyReference("runAsManager", runAsManagerId);
@@ -286,4 +294,31 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
 
         parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_METADATA_SOURCE_ADVISOR, advisor);
     }
+
+    /**
+     * Delays the lookup of the AuthenticationManager within MethodSecurityInterceptor, to prevent issues like SEC-933.
+     *
+     * @author Luke Taylor
+     * @since 3.0
+     */
+    public static final class AuthenticationManagerDelegator implements AuthenticationManager, BeanFactoryAware {
+        private AuthenticationManager delegate;
+        private final Object delegateMonitor = new Object();
+        private BeanFactory beanFactory;
+
+        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+            synchronized(delegateMonitor) {
+                if (delegate == null) {
+                    Assert.state(beanFactory != null, "BeanFactory must be set to resolve " + BeanIds.AUTHENTICATION_MANAGER);
+                    delegate = beanFactory.getBean(BeanIds.AUTHENTICATION_MANAGER, ProviderManager.class);
+                }
+            }
+
+            return delegate.authenticate(authentication);
+        }
+
+        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+            this.beanFactory = beanFactory;
+        }
+    }
 }

+ 7 - 5
itest/context/src/test/resources/python-method-access-app-context.xml

@@ -23,10 +23,12 @@
 
     <b:bean id="service" class="org.springframework.security.integration.python.TestServiceImpl"/>
 
-    <authentication-provider>
-        <user-service>
-            <user name="bob" password="bobspassword" authorities="ROLE_A,ROLE_B"/>
-        </user-service>
-    </authentication-provider>
+    <authentication-manager>
+        <authentication-provider>
+            <user-service>
+                <user name="bob" password="bobspassword" authorities="ROLE_A,ROLE_B"/>
+            </user-service>
+        </authentication-provider>
+    </authentication-manager>
 
 </b:beans>

+ 3 - 1
itest/context/src/test/resources/sec-933-app-context.xml

@@ -12,8 +12,10 @@
 
     <bean id="userRepository" class="org.springframework.security.integration.StubUserRepository"/>
 
-    <security:authentication-provider
+    <security:authentication-manager>
+        <security:authentication-provider
         user-service-ref="userDetailsService" />
+    </security:authentication-manager>
 
     <bean id="userDetailsService" class="org.springframework.security.integration.UserDetailsServiceImpl">
         <property name="userRepository" ref="userRepository"/>

+ 7 - 7
itest/context/src/test/resources/sec-936-app-context.xml

@@ -7,13 +7,13 @@
     http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
     http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
 
-    <security:authentication-provider>
-        <security:user-service>
-            <security:user name="bob" password="bobspassword" authorities="ROLE_A,ROLE_B"/>
-        </security:user-service>
-    </security:authentication-provider>
-
-    <security:authentication-manager alias="authenticationManager"/>
+    <security:authentication-manager alias="authenticationManager">
+        <security:authentication-provider>
+            <security:user-service>
+                <security:user name="bob" password="bobspassword" authorities="ROLE_A,ROLE_B"/>
+            </security:user-service>
+        </security:authentication-provider>
+    </security:authentication-manager>
 
     <bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
         <property name="allowIfAllAbstainDecisions" value="false"/>

+ 9 - 7
itest/web/src/main/webapp/WEB-INF/in-memory-provider.xml

@@ -6,12 +6,14 @@
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
                         http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
 
-  <authentication-provider>
-    <user-service>
-      <user name="miles" password="milespassword" authorities="ROLE_USER,ROLE_JAZZ,ROLE_TRUMPETER"/>
-      <user name="johnc" password="johncspassword" authorities="ROLE_USER,ROLE_JAZZ,ROLE_SAXOPHONIST"/>
-      <user name="jimi" password="jimispassword" authorities="ROLE_USER,ROLE_ROCK,ROLE_GUITARIST"/>
-    </user-service>
-  </authentication-provider>
+    <authentication-manager alias="authenticationManager">
+        <authentication-provider>
+            <user-service>
+              <user name="miles" password="milespassword" authorities="ROLE_USER,ROLE_JAZZ,ROLE_TRUMPETER"/>
+              <user name="johnc" password="johncspassword" authorities="ROLE_USER,ROLE_JAZZ,ROLE_SAXOPHONIST"/>
+              <user name="jimi" password="jimispassword" authorities="ROLE_USER,ROLE_ROCK,ROLE_GUITARIST"/>
+            </user-service>
+        </authentication-provider>
+    </authentication-manager>
 
 </beans:beans>

+ 7 - 5
itest/web/src/main/webapp/WEB-INF/ldap-provider.xml

@@ -9,12 +9,14 @@
     xmlns:beans="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
-                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.2.xsd">
+                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
 
     <ldap-server ldif="classpath*:test-server.ldif"/>
-    
-    <ldap-authentication-provider user-search-filter="(uid={0})" group-role-attribute="ou" />
-    
+
+    <authentication-manager alias="authenticationManager">
+        <ldap-authentication-provider user-search-filter="(uid={0})" group-role-attribute="ou" />
+    </authentication-manager>
+
     <ldap-user-service user-search-filter="(uid={0})" group-role-attribute="ou"/>
 
-</beans:beans>
+</beans:beans>