From d619434f899f9f0a1e987f61e33d0a1a502e9a7f Mon Sep 17 00:00:00 2001 From: Tadaya Tsuyukubo Date: Thu, 18 Apr 2019 17:09:11 -0700 Subject: [PATCH] Set "rolePrefix" in ReactiveMethodSecurityConfiguration Currently, `GrantedAuthorityDefaults` is not considered in `ReactiveMethodSecurityConfiguration`. This commit updates the configuration to be aware of `GrantedAuthorityDefaults` and update `rolePrefix` when the bean is available. Also, use the same instance of `DefaultMethodSecurityExpressionHandler` when constructing `ExpressionBasedAnnotationAttributeFactory`. --- .../ReactiveMethodSecurityConfiguration.java | 23 ++++- ...ctiveMethodSecurityConfigurationTests.java | 91 +++++++++++++++++++ 2 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfigurationTests.java diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfiguration.java index f6d9aa6cce8..fd7367805aa 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2019 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. @@ -16,6 +16,7 @@ package org.springframework.security.config.annotation.method.configuration; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -28,17 +29,21 @@ import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource; import org.springframework.security.access.prepost.PrePostAdviceReactiveMethodInterceptor; import org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource; +import org.springframework.security.config.core.GrantedAuthorityDefaults; import java.util.Arrays; /** * @author Rob Winch + * @author Tadaya Tsuyukubo * @since 5.0 */ @Configuration class ReactiveMethodSecurityConfiguration implements ImportAware { private int advisorOrder; + private GrantedAuthorityDefaults grantedAuthorityDefaults; + @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public MethodSecurityMetadataSourceAdvisor methodSecurityInterceptor(AbstractMethodSecurityMetadataSource source) throws Exception { @@ -49,9 +54,9 @@ public MethodSecurityMetadataSourceAdvisor methodSecurityInterceptor(AbstractMet } @Bean - public DelegatingMethodSecurityMetadataSource methodMetadataSource() { + public DelegatingMethodSecurityMetadataSource methodMetadataSource(MethodSecurityExpressionHandler methodSecurityExpressionHandler) { ExpressionBasedAnnotationAttributeFactory attributeFactory = new ExpressionBasedAnnotationAttributeFactory( - new DefaultMethodSecurityExpressionHandler()); + methodSecurityExpressionHandler); PrePostAnnotationSecurityMetadataSource prePostSource = new PrePostAnnotationSecurityMetadataSource( attributeFactory); return new DelegatingMethodSecurityMetadataSource(Arrays.asList(prePostSource)); @@ -70,11 +75,21 @@ public PrePostAdviceReactiveMethodInterceptor securityMethodInterceptor(Abstract @Bean public DefaultMethodSecurityExpressionHandler methodSecurityExpressionHandler() { - return new DefaultMethodSecurityExpressionHandler(); + DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler(); + if (this.grantedAuthorityDefaults != null) { + handler.setDefaultRolePrefix(this.grantedAuthorityDefaults.getRolePrefix()); + } + return handler; } @Override public void setImportMetadata(AnnotationMetadata importMetadata) { this.advisorOrder = (int) importMetadata.getAnnotationAttributes(EnableReactiveMethodSecurity.class.getName()).get("order"); } + + @Autowired(required = false) + void setGrantedAuthorityDefaults(GrantedAuthorityDefaults grantedAuthorityDefaults) { + this.grantedAuthorityDefaults = grantedAuthorityDefaults; + } + } diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfigurationTests.java new file mode 100644 index 00000000000..97f8294df39 --- /dev/null +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfigurationTests.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2019 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 + * + * https://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.annotation.method.configuration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +import org.junit.Rule; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.expression.EvaluationContext; +import org.springframework.security.access.expression.SecurityExpressionRoot; +import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; +import org.springframework.security.access.intercept.method.MockMethodInvocation; +import org.springframework.security.authentication.TestingAuthenticationToken; +import org.springframework.security.config.core.GrantedAuthorityDefaults; +import org.springframework.security.config.test.SpringTestRule; + +/** + * @author Tadaya Tsuyukubo + */ +public class ReactiveMethodSecurityConfigurationTests { + + @Rule + public final SpringTestRule spring = new SpringTestRule(); + + @Autowired + DefaultMethodSecurityExpressionHandler methodSecurityExpressionHandler; + + @Test + public void rolePrefixWithGrantedAuthorityDefaults() { + this.spring.register(WithRolePrefixConfiguration.class).autowire(); + + TestingAuthenticationToken authentication = new TestingAuthenticationToken( + "principal", "credential", "CUSTOM_ABC"); + MockMethodInvocation methodInvocation = mock(MockMethodInvocation.class); + + EvaluationContext context = this.methodSecurityExpressionHandler + .createEvaluationContext(authentication, methodInvocation); + SecurityExpressionRoot root = (SecurityExpressionRoot) context.getRootObject() + .getValue(); + + assertThat(root.hasRole("ROLE_ABC")).isFalse(); + assertThat(root.hasRole("ROLE_CUSTOM_ABC")).isFalse(); + assertThat(root.hasRole("CUSTOM_ABC")).isTrue(); + assertThat(root.hasRole("ABC")).isTrue(); + } + + @Test + public void rolePrefixWithDefaultConfig() { + this.spring.register(ReactiveMethodSecurityConfiguration.class).autowire(); + + TestingAuthenticationToken authentication = new TestingAuthenticationToken( + "principal", "credential", "ROLE_ABC"); + MockMethodInvocation methodInvocation = mock(MockMethodInvocation.class); + + EvaluationContext context = this.methodSecurityExpressionHandler + .createEvaluationContext(authentication, methodInvocation); + SecurityExpressionRoot root = (SecurityExpressionRoot) context.getRootObject() + .getValue(); + + assertThat(root.hasRole("ROLE_ABC")).isTrue(); + assertThat(root.hasRole("ABC")).isTrue(); + } + + @Configuration + @EnableReactiveMethodSecurity // this imports ReactiveMethodSecurityConfiguration + static class WithRolePrefixConfiguration { + @Bean + GrantedAuthorityDefaults grantedAuthorityDefaults() { + return new GrantedAuthorityDefaults("CUSTOM_"); + } + } + +}