瀏覽代碼

SEC-2087: GlobalMethodSecurityBeanDefinitionParser uses AuthenticationManager to create AuthenticationManagerDelegator

Rob Winch 12 年之前
父節點
當前提交
e9215c4dc3

+ 19 - 4
config/src/main/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParser.java

@@ -1,3 +1,18 @@
+/*
+ * Copyright 2002-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.springframework.security.config.method;
 
 import static org.springframework.security.config.Elements.*;
@@ -47,7 +62,6 @@ 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.config.Elements;
 import org.springframework.security.config.authentication.AuthenticationManagerFactoryBean;
@@ -63,6 +77,7 @@ import org.w3c.dom.Element;
  *
  * @author Ben Alex
  * @author Luke Taylor
+ * @author Rob Winch
  * @since 2.0
  */
 public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
@@ -234,7 +249,7 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
      * expression voter if expression-based access control is enabled.
      * @return
      */
-    @SuppressWarnings("unchecked")
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     private String registerAccessManager(ParserContext pc, boolean jsr250Enabled, BeanDefinition expressionVoter) {
 
         BeanDefinitionBuilder accessMgrBuilder = BeanDefinitionBuilder.rootBeanDefinition(AffirmativeBased.class);
@@ -259,7 +274,7 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
         return id;
     }
 
-    @SuppressWarnings("unchecked")
+    @SuppressWarnings("rawtypes")
     private BeanReference registerDelegatingMethodSecurityMetadataSource(ParserContext pc, ManagedList delegates, Object source) {
         RootBeanDefinition delegatingMethodSecurityMetadataSource = new RootBeanDefinition(DelegatingMethodSecurityMetadataSource.class);
         delegatingMethodSecurityMetadataSource.setSource(source);
@@ -383,7 +398,7 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
                 if (delegate == null) {
                     Assert.state(beanFactory != null, "BeanFactory must be set to resolve " + authMgrBean);
                     try {
-                        delegate = beanFactory.getBean(authMgrBean, ProviderManager.class);
+                        delegate = beanFactory.getBean(authMgrBean, AuthenticationManager.class);
                     } catch (NoSuchBeanDefinitionException e) {
                         if (BeanIds.AUTHENTICATION_MANAGER.equals(e.getBeanName())) {
                             throw new NoSuchBeanDefinitionException(BeanIds.AUTHENTICATION_MANAGER,

+ 50 - 0
config/src/test/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParserTests.java

@@ -10,9 +10,11 @@ import org.junit.After;
 import org.junit.Test;
 import org.springframework.aop.Advisor;
 import org.springframework.aop.framework.Advised;
+import org.springframework.beans.BeansException;
 import org.springframework.beans.MutablePropertyValues;
 import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
 import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
 import org.springframework.context.support.AbstractXmlApplicationContext;
 import org.springframework.context.support.StaticApplicationContext;
 import org.springframework.security.access.AccessDeniedException;
@@ -29,11 +31,13 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
 import org.springframework.security.access.vote.AffirmativeBased;
 import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
+import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.TestingAuthenticationToken;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.config.ConfigTestUtils;
 import org.springframework.security.config.PostProcessedMockUserDetailsService;
 import org.springframework.security.config.util.InMemoryXmlApplicationContext;
+import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.core.authority.AuthorityUtils;
 import org.springframework.security.core.context.SecurityContextHolder;
@@ -368,6 +372,52 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
         foo.foo(new SecurityConfig("A"));
     }
 
+    @Test
+    public void supportsCustomAuthenticationManager() throws Exception {
+        setContext(
+                "<b:bean id='target' class='" + ConcreteFoo.class.getName()  + "'/>" +
+                "<method-security-metadata-source id='mds'>" +
+                "      <protect method='"+ Foo.class.getName() + ".foo' access='ROLE_ADMIN'/>" +
+                "</method-security-metadata-source>" +
+                "<global-method-security pre-post-annotations='enabled' metadata-source-ref='mds' authentication-manager-ref='customAuthMgr'/>" +
+                "<b:bean id='customAuthMgr' class='org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParserTests$CustomAuthManager'>" +
+                "      <b:constructor-arg value='authManager'/>" +
+                "</b:bean>" +
+                AUTH_PROVIDER_XML
+        );
+        SecurityContextHolder.getContext().setAuthentication(bob);
+        Foo foo = (Foo) appContext.getBean("target");
+        try {
+            foo.foo(new SecurityConfig("A"));
+            fail("Bob can't invoke admin methods");
+        } catch (AccessDeniedException expected) {
+        }
+        SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("admin", "password"));
+        foo.foo(new SecurityConfig("A"));
+    }
+
+    static class CustomAuthManager implements AuthenticationManager, ApplicationContextAware {
+        private String beanName;
+        private AuthenticationManager authenticationManager;
+
+        CustomAuthManager(String beanName) {
+            this.beanName = beanName;
+        }
+
+        public Authentication authenticate(Authentication authentication)
+                throws AuthenticationException {
+            return authenticationManager.authenticate(authentication);
+        }
+
+        /* (non-Javadoc)
+         * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
+         */
+        public void setApplicationContext(ApplicationContext applicationContext)
+                throws BeansException {
+            this.authenticationManager = applicationContext.getBean(beanName,AuthenticationManager.class);
+        }
+    }
+
     private void setContext(String context) {
         appContext = new InMemoryXmlApplicationContext(context);
     }