From bb997eecde68164f1ba5195bfeb2849485588c4f Mon Sep 17 00:00:00 2001 From: Rob Winch Date: Wed, 10 Aug 2016 23:48:07 -0500 Subject: [PATCH] Fix defaultMethodExpressionHandler autowiring Previously if a Bean for GlobalMethodSecurityConfiguration's defaultMethodExpressionHandler was found on a Configuration that also @Autowired a Bean that enabled method security, the Bean that was @Autowired would not have security enabled. This fixes the issue by delaying the lookup of Beans populated on GlobalMethodSecurityConfiguration's defaultMethodExpressionHandler. Fixes gh-4020 --- .../GlobalMethodSecurityConfiguration.java | 46 +++++----- ...lobalMethodSecurityConfigurationTests.java | 86 +++++++++++++++++++ 2 files changed, 112 insertions(+), 20 deletions(-) create mode 100644 config/src/test/java/org/springframework/security/config/method/configuration/Gh4020GlobalMethodSecurityConfigurationTests.java diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java index b7d088c570..eaf3a8c2df 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java @@ -150,6 +150,32 @@ public class GlobalMethodSecurityConfiguration catch (Exception e) { throw new RuntimeException(e); } + + PermissionEvaluator permissionEvaluator = getSingleBeanOrNull( + PermissionEvaluator.class); + if (permissionEvaluator != null) { + this.defaultMethodExpressionHandler + .setPermissionEvaluator(permissionEvaluator); + } + + RoleHierarchy roleHierarchy = getSingleBeanOrNull(RoleHierarchy.class); + if (roleHierarchy != null) { + this.defaultMethodExpressionHandler.setRoleHierarchy(roleHierarchy); + } + + AuthenticationTrustResolver trustResolver = getSingleBeanOrNull( + AuthenticationTrustResolver.class); + if (trustResolver != null) { + this.defaultMethodExpressionHandler.setTrustResolver(trustResolver); + } + } + + private T getSingleBeanOrNull(Class type) { + String[] beanNamesForType = this.context.getBeanNamesForType(type); + if (beanNamesForType == null || beanNamesForType.length != 1) { + return null; + } + return this.context.getBean(beanNamesForType[0], type); } private void initializeMethodSecurityInterceptor() throws Exception { @@ -357,16 +383,6 @@ public class GlobalMethodSecurityConfiguration enableMethodSecurity = AnnotationAttributes.fromMap(annotationAttributes); } - @Autowired(required = false) - public void setAuthenticationTrustResolver(AuthenticationTrustResolver trustResolver) { - this.defaultMethodExpressionHandler.setTrustResolver(trustResolver); - } - - @Autowired(required = false) - public void setRoleHierarchy(RoleHierarchy roleHierarchy){ - this.defaultMethodExpressionHandler.setRoleHierarchy(roleHierarchy); - } - @Autowired(required = false) public void setObjectPostProcessor(ObjectPostProcessor objectPostProcessor) { this.objectPostProcessor = objectPostProcessor; @@ -380,16 +396,6 @@ public class GlobalMethodSecurityConfiguration this.jsr250MethodSecurityMetadataSource = jsr250MethodSecurityMetadataSource; } - @Autowired(required = false) - public void setPermissionEvaluator(List permissionEvaluators) { - if (permissionEvaluators.size() != 1) { - logger.debug("Not autwiring PermissionEvaluator since size != 1. Got " - + permissionEvaluators); - } - this.defaultMethodExpressionHandler.setPermissionEvaluator(permissionEvaluators - .get(0)); - } - @Autowired(required = false) public void setMethodSecurityExpressionHandler( List handlers) { diff --git a/config/src/test/java/org/springframework/security/config/method/configuration/Gh4020GlobalMethodSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/method/configuration/Gh4020GlobalMethodSecurityConfigurationTests.java new file mode 100644 index 0000000000..bee05b14f2 --- /dev/null +++ b/config/src/test/java/org/springframework/security/config/method/configuration/Gh4020GlobalMethodSecurityConfigurationTests.java @@ -0,0 +1,86 @@ +/* + * Copyright 2012-2016 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.configuration; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.access.PermissionEvaluator; +import org.springframework.security.access.hierarchicalroles.RoleHierarchy; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; +import org.springframework.security.authentication.AuthenticationTrustResolver; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import static org.mockito.Mockito.mock; + +/** + * @author Rob Winch + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class Gh4020GlobalMethodSecurityConfigurationTests { + @Autowired + DenyAllService denyAll; + + // gh-4020 + @Test(expected = AuthenticationCredentialsNotFoundException.class) + public void denyAll() { + this.denyAll.denyAll(); + } + + @Configuration + @EnableGlobalMethodSecurity(prePostEnabled = true) + static class SecurityConfig { + @Bean + PermissionEvaluator permissionEvaluator() { + return mock(PermissionEvaluator.class); + } + + @Bean + RoleHierarchy RoleHierarchy() { + return mock(RoleHierarchy.class); + } + + @Bean + AuthenticationTrustResolver trustResolver() { + return mock(AuthenticationTrustResolver.class); + } + + @Autowired + DenyAllService denyAll; + } + + @Configuration + static class ServiceConfig { + @Bean + DenyAllService denyAllService() { + return new DenyAllService(); + } + } + + @PreAuthorize("denyAll") + static class DenyAllService { + void denyAll() { + } + } +}