Browse Source

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 năm trước cách đây
mục cha
commit
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()
+        }
+    }
 }