浏览代码

SEC-2305: GlobalMethodSecurityConfiguration autowire PermissionEvaluator

If a single PermissionEvaluator bean is found the
DefaultMethodSecurityExpressionHandler is configured with the
PermissionEvaluator. If multiple PermissionEvaluator beans are found, the
beans are ignored.
Rob Winch 12 年之前
父节点
当前提交
614c94187e

+ 9 - 0
config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java

@@ -39,6 +39,7 @@ import org.springframework.core.type.AnnotationMetadata;
 import org.springframework.security.access.AccessDecisionManager;
 import org.springframework.security.access.AccessDecisionVoter;
 import org.springframework.security.access.AfterInvocationProvider;
+import org.springframework.security.access.PermissionEvaluator;
 import org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource;
 import org.springframework.security.access.annotation.Jsr250Voter;
 import org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource;
@@ -361,6 +362,14 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
         this.defaultMethodExpressionHandler = objectPostProcessor.postProcess(defaultMethodExpressionHandler);
     }
 
+    @Autowired(required = false)
+    public void setPermissionEvaluator(List<PermissionEvaluator> permissionEvaluators) {
+        if(permissionEvaluators.size() != 1) {
+            logger.debug("Not autwiring PermissionEvaluator since size != 1. Got " + permissionEvaluators);
+        }
+        this.defaultMethodExpressionHandler.setPermissionEvaluator(permissionEvaluators.get(0));
+    }
+
     @SuppressWarnings("unchecked")
     private <T> T lazyBean(Class<T> interfaceName) {
         LazyInitTargetSource lazyTargetSource = new LazyInitTargetSource();

+ 78 - 1
config/src/test/groovy/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfigurationTests.groovy

@@ -24,6 +24,7 @@ import org.springframework.context.ApplicationListener
 import org.springframework.context.annotation.Bean
 import org.springframework.context.annotation.Configuration
 import org.springframework.security.access.AccessDeniedException
+import org.springframework.security.access.PermissionEvaluator
 import org.springframework.security.access.prepost.PreAuthorize
 import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter
 import org.springframework.security.authentication.AuthenticationManager
@@ -32,7 +33,6 @@ import org.springframework.security.authentication.DefaultAuthenticationEventPub
 import org.springframework.security.authentication.TestingAuthenticationToken
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
 import org.springframework.security.authentication.event.AuthenticationSuccessEvent
-import org.springframework.security.config.MockAfterInvocationProvider;
 import org.springframework.security.config.annotation.BaseSpringSpec
 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
 import org.springframework.security.core.Authentication
@@ -199,4 +199,81 @@ public class GlobalMethodSecurityConfigurationTests extends BaseSpringSpec {
             new MethodSecurityServiceImpl()
         }
     }
+
+    def "GlobalMethodSecurityConfiguration autowires PermissionEvaluator"() {
+        setup:
+            SecurityContextHolder.getContext().setAuthentication(
+                new TestingAuthenticationToken("user", "password","ROLE_USER"))
+            PermissionEvaluator evaluator = Mock()
+            AutowirePermissionEvaluatorConfig.PE = evaluator
+            loadConfig(AutowirePermissionEvaluatorConfig)
+            MethodSecurityService service = context.getBean(MethodSecurityService)
+        when:
+            service.hasPermission("something")
+        then:
+            1 * evaluator.hasPermission(_, "something", "read") >> true
+        when:
+            service.hasPermission("something")
+        then:
+            1 * evaluator.hasPermission(_, "something", "read") >> false
+            thrown(AccessDeniedException)
+    }
+
+    @Configuration
+    @EnableGlobalMethodSecurity(prePostEnabled = true)
+    public static class AutowirePermissionEvaluatorConfig extends GlobalMethodSecurityConfiguration {
+        static PermissionEvaluator PE
+
+        @Override
+        protected void registerAuthentication(AuthenticationManagerBuilder auth)
+                throws Exception {
+            auth
+                .inMemoryAuthentication()
+        }
+
+        @Bean
+        public PermissionEvaluator pe() {
+            PE
+        }
+
+        @Bean
+        public MethodSecurityService service() {
+            new MethodSecurityServiceImpl()
+        }
+    }
+
+    def "GlobalMethodSecurityConfiguration does not failw with multiple PermissionEvaluator"() {
+        when:
+            loadConfig(MultiPermissionEvaluatorConfig)
+        then:
+            noExceptionThrown()
+    }
+
+    @Configuration
+    @EnableGlobalMethodSecurity(prePostEnabled = true)
+    public static class MultiPermissionEvaluatorConfig extends GlobalMethodSecurityConfiguration {
+        static PermissionEvaluator PE
+
+        @Override
+        protected void registerAuthentication(AuthenticationManagerBuilder auth)
+                throws Exception {
+            auth
+                .inMemoryAuthentication()
+        }
+
+        @Bean
+        public PermissionEvaluator pe() {
+            PE
+        }
+
+        @Bean
+        public PermissionEvaluator pe2() {
+            PE
+        }
+
+        @Bean
+        public MethodSecurityService service() {
+            new MethodSecurityServiceImpl()
+        }
+    }
 }