Simplify Method Interceptor Configuration

Simplifies to use only one ObjectProvider for easier
future maintenance

Issue gh-15592
This commit is contained in:
Josh Cummings 2024-08-14 08:07:17 -06:00
parent 24036578df
commit 27af1df87d
No known key found for this signature in database
GPG Key ID: A306A51F43B8E5A5
4 changed files with 278 additions and 193 deletions

View File

@ -0,0 +1,67 @@
/*
* Copyright 2002-2024 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 java.util.function.Supplier;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInvocation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.aop.Pointcut;
import org.springframework.security.authorization.method.AuthorizationAdvisor;
import org.springframework.util.function.SingletonSupplier;
final class DeferringMethodInterceptor<M extends AuthorizationAdvisor> implements AuthorizationAdvisor {
private final Pointcut pointcut;
private final Supplier<M> delegate;
DeferringMethodInterceptor(Pointcut pointcut, Supplier<M> delegate) {
this.pointcut = pointcut;
this.delegate = SingletonSupplier.of(delegate);
}
@Nullable
@Override
public Object invoke(@NotNull MethodInvocation invocation) throws Throwable {
return this.delegate.get().invoke(invocation);
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
@Override
public Advice getAdvice() {
return this;
}
@Override
public int getOrder() {
return this.delegate.get().getOrder();
}
@Override
public boolean isPerInstance() {
return true;
}
}

View File

@ -16,27 +16,30 @@
package org.springframework.security.config.annotation.method.configuration;
import java.util.function.Supplier;
import io.micrometer.observation.ObservationRegistry;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.AopInfrastructureBean;
import org.springframework.beans.factory.ObjectProvider;
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;
import org.springframework.context.annotation.ImportAware;
import org.springframework.context.annotation.Role;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.authorization.AuthoritiesAuthorizationManager;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.ObservationAuthorizationManager;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.authorization.method.Jsr250AuthorizationManager;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
/**
@ -47,42 +50,64 @@ import org.springframework.security.core.context.SecurityContextHolderStrategy;
* @since 5.6
* @see EnableMethodSecurity
*/
@Configuration(proxyBeanMethods = false)
@Configuration(value = "_jsr250MethodSecurityConfiguration", proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
final class Jsr250MethodSecurityConfiguration implements ImportAware, AopInfrastructureBean {
private int interceptorOrderOffset;
private static final Pointcut pointcut = AuthorizationManagerBeforeMethodInterceptor.jsr250().getPointcut();
private final Jsr250AuthorizationManager authorizationManager = new Jsr250AuthorizationManager();
private AuthorizationManagerBeforeMethodInterceptor methodInterceptor = AuthorizationManagerBeforeMethodInterceptor
.jsr250(this.authorizationManager);
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static MethodInterceptor jsr250AuthorizationMethodInterceptor(
ObjectProvider<GrantedAuthorityDefaults> defaultsProvider,
ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
ObjectProvider<AuthorizationEventPublisher> eventPublisherProvider,
ObjectProvider<ObservationRegistry> registryProvider, ObjectProvider<RoleHierarchy> roleHierarchyProvider,
Jsr250MethodSecurityConfiguration configuration) {
Jsr250AuthorizationManager jsr250 = new Jsr250AuthorizationManager();
AuthoritiesAuthorizationManager authoritiesAuthorizationManager = new AuthoritiesAuthorizationManager();
RoleHierarchy roleHierarchy = roleHierarchyProvider.getIfAvailable(NullRoleHierarchy::new);
authoritiesAuthorizationManager.setRoleHierarchy(roleHierarchy);
jsr250.setAuthoritiesAuthorizationManager(authoritiesAuthorizationManager);
defaultsProvider.ifAvailable((d) -> jsr250.setRolePrefix(d.getRolePrefix()));
SecurityContextHolderStrategy strategy = strategyProvider
.getIfAvailable(SecurityContextHolder::getContextHolderStrategy);
AuthorizationManager<MethodInvocation> manager = new DeferringObservationAuthorizationManager<>(
registryProvider, jsr250);
AuthorizationManagerBeforeMethodInterceptor interceptor = AuthorizationManagerBeforeMethodInterceptor
.jsr250(manager);
interceptor.setOrder(interceptor.getOrder() + configuration.interceptorOrderOffset);
interceptor.setSecurityContextHolderStrategy(strategy);
eventPublisherProvider.ifAvailable(interceptor::setAuthorizationEventPublisher);
return interceptor;
ObjectProvider<Jsr250MethodSecurityConfiguration> _jsr250MethodSecurityConfiguration) {
Supplier<AuthorizationManagerBeforeMethodInterceptor> supplier = () -> {
Jsr250MethodSecurityConfiguration configuration = _jsr250MethodSecurityConfiguration.getObject();
return configuration.methodInterceptor;
};
return new DeferringMethodInterceptor<>(pointcut, supplier);
}
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
EnableMethodSecurity annotation = importMetadata.getAnnotations().get(EnableMethodSecurity.class).synthesize();
this.interceptorOrderOffset = annotation.offset();
this.methodInterceptor.setOrder(this.methodInterceptor.getOrder() + annotation.offset());
}
@Autowired(required = false)
void setGrantedAuthorityDefaults(GrantedAuthorityDefaults defaults) {
this.authorizationManager.setRolePrefix(defaults.getRolePrefix());
}
@Autowired(required = false)
void setRoleHierarchy(RoleHierarchy roleHierarchy) {
AuthoritiesAuthorizationManager authoritiesAuthorizationManager = new AuthoritiesAuthorizationManager();
authoritiesAuthorizationManager.setRoleHierarchy(roleHierarchy);
this.authorizationManager.setAuthoritiesAuthorizationManager(authoritiesAuthorizationManager);
}
@Autowired(required = false)
void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
this.methodInterceptor.setSecurityContextHolderStrategy(securityContextHolderStrategy);
}
@Autowired(required = false)
void setObservationRegistry(ObservationRegistry registry) {
if (registry.isNoop()) {
return;
}
AuthorizationManager<MethodInvocation> observed = new ObservationAuthorizationManager<>(registry,
this.authorizationManager);
this.methodInterceptor = AuthorizationManagerBeforeMethodInterceptor.secured(observed);
}
@Autowired(required = false)
void setEventPublisher(AuthorizationEventPublisher eventPublisher) {
this.methodInterceptor.setAuthorizationEventPublisher(eventPublisher);
}
}

View File

@ -16,21 +16,17 @@
package org.springframework.security.config.annotation.method.configuration;
import java.util.function.Consumer;
import java.util.function.Supplier;
import io.micrometer.observation.ObservationRegistry;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.AopInfrastructureBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
@ -38,11 +34,9 @@ import org.springframework.context.annotation.Role;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.method.AuthorizationAdvisor;
import org.springframework.security.authorization.ObservationAuthorizationManager;
import org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.authorization.method.PostAuthorizeAuthorizationManager;
@ -52,7 +46,6 @@ import org.springframework.security.authorization.method.PreFilterAuthorizationM
import org.springframework.security.authorization.method.PrePostTemplateDefaults;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.util.function.SingletonSupplier;
/**
* Base {@link Configuration} for enabling Spring Security Method Security.
@ -62,164 +55,142 @@ import org.springframework.util.function.SingletonSupplier;
* @since 5.6
* @see EnableMethodSecurity
*/
@Configuration(proxyBeanMethods = false)
@Configuration(value = "_prePostMethodSecurityConfiguration", proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
final class PrePostMethodSecurityConfiguration implements ImportAware, AopInfrastructureBean {
final class PrePostMethodSecurityConfiguration implements ImportAware, ApplicationContextAware, AopInfrastructureBean {
private int interceptorOrderOffset;
private static final Pointcut preFilterPointcut = new PreFilterAuthorizationMethodInterceptor().getPointcut();
private static final Pointcut preAuthorizePointcut = AuthorizationManagerBeforeMethodInterceptor.preAuthorize()
.getPointcut();
private static final Pointcut postAuthorizePointcut = AuthorizationManagerAfterMethodInterceptor.postAuthorize()
.getPointcut();
private static final Pointcut postFilterPointcut = new PostFilterAuthorizationMethodInterceptor().getPointcut();
private final PreAuthorizeAuthorizationManager preAuthorizeAuthorizationManager = new PreAuthorizeAuthorizationManager();
private final PostAuthorizeAuthorizationManager postAuthorizeAuthorizationManager = new PostAuthorizeAuthorizationManager();
private final PreFilterAuthorizationMethodInterceptor preFilterMethodInterceptor = new PreFilterAuthorizationMethodInterceptor();
private AuthorizationManagerBeforeMethodInterceptor preAuthorizeMethodInterceptor = AuthorizationManagerBeforeMethodInterceptor
.preAuthorize(this.preAuthorizeAuthorizationManager);
private AuthorizationManagerAfterMethodInterceptor postAuthorizeMethodInterceptor = AuthorizationManagerAfterMethodInterceptor
.postAuthorize(this.postAuthorizeAuthorizationManager);
private final PostFilterAuthorizationMethodInterceptor postFilterMethodInterceptor = new PostFilterAuthorizationMethodInterceptor();
private final DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
{
this.preFilterMethodInterceptor.setExpressionHandler(this.expressionHandler);
this.preAuthorizeAuthorizationManager.setExpressionHandler(this.expressionHandler);
this.postAuthorizeAuthorizationManager.setExpressionHandler(this.expressionHandler);
this.postFilterMethodInterceptor.setExpressionHandler(this.expressionHandler);
}
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.expressionHandler.setApplicationContext(context);
this.preAuthorizeAuthorizationManager.setApplicationContext(context);
this.postAuthorizeAuthorizationManager.setApplicationContext(context);
}
@Autowired(required = false)
void setGrantedAuthorityDefaults(GrantedAuthorityDefaults grantedAuthorityDefaults) {
this.expressionHandler.setDefaultRolePrefix(grantedAuthorityDefaults.getRolePrefix());
}
@Autowired(required = false)
void setRoleHierarchy(RoleHierarchy roleHierarchy) {
this.expressionHandler.setRoleHierarchy(roleHierarchy);
}
@Autowired(required = false)
void setTemplateDefaults(PrePostTemplateDefaults templateDefaults) {
this.preFilterMethodInterceptor.setTemplateDefaults(templateDefaults);
this.preAuthorizeAuthorizationManager.setTemplateDefaults(templateDefaults);
this.postAuthorizeAuthorizationManager.setTemplateDefaults(templateDefaults);
this.postFilterMethodInterceptor.setTemplateDefaults(templateDefaults);
}
@Autowired(required = false)
void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) {
this.preFilterMethodInterceptor.setExpressionHandler(expressionHandler);
this.preAuthorizeAuthorizationManager.setExpressionHandler(expressionHandler);
this.postAuthorizeAuthorizationManager.setExpressionHandler(expressionHandler);
this.postFilterMethodInterceptor.setExpressionHandler(expressionHandler);
}
@Autowired(required = false)
void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
this.preFilterMethodInterceptor.setSecurityContextHolderStrategy(securityContextHolderStrategy);
this.preAuthorizeMethodInterceptor.setSecurityContextHolderStrategy(securityContextHolderStrategy);
this.postAuthorizeMethodInterceptor.setSecurityContextHolderStrategy(securityContextHolderStrategy);
this.postFilterMethodInterceptor.setSecurityContextHolderStrategy(securityContextHolderStrategy);
}
@Autowired(required = false)
void setObservationRegistry(ObservationRegistry registry) {
if (registry.isNoop()) {
return;
}
this.preAuthorizeMethodInterceptor = AuthorizationManagerBeforeMethodInterceptor
.preAuthorize(new ObservationAuthorizationManager<>(registry, this.preAuthorizeAuthorizationManager));
this.postAuthorizeMethodInterceptor = AuthorizationManagerAfterMethodInterceptor
.postAuthorize(new ObservationAuthorizationManager<>(registry, this.postAuthorizeAuthorizationManager));
}
@Autowired(required = false)
void setAuthorizationEventPublisher(AuthorizationEventPublisher publisher) {
this.preAuthorizeMethodInterceptor.setAuthorizationEventPublisher(publisher);
this.postAuthorizeMethodInterceptor.setAuthorizationEventPublisher(publisher);
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static MethodInterceptor preFilterAuthorizationMethodInterceptor(
ObjectProvider<GrantedAuthorityDefaults> defaultsProvider,
ObjectProvider<PrePostTemplateDefaults> methodSecurityDefaultsProvider,
ObjectProvider<MethodSecurityExpressionHandler> expressionHandlerProvider,
ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
ObjectProvider<RoleHierarchy> roleHierarchyProvider, PrePostMethodSecurityConfiguration configuration,
ApplicationContext context) {
PreFilterAuthorizationMethodInterceptor preFilter = new PreFilterAuthorizationMethodInterceptor();
preFilter.setOrder(preFilter.getOrder() + configuration.interceptorOrderOffset);
return new DeferringMethodInterceptor<>(preFilter, (f) -> {
methodSecurityDefaultsProvider.ifAvailable(f::setTemplateDefaults);
f.setExpressionHandler(expressionHandlerProvider
.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, roleHierarchyProvider, context)));
strategyProvider.ifAvailable(f::setSecurityContextHolderStrategy);
});
ObjectProvider<PrePostMethodSecurityConfiguration> _prePostMethodSecurityConfiguration) {
return new DeferringMethodInterceptor<>(preFilterPointcut,
() -> _prePostMethodSecurityConfiguration.getObject().preFilterMethodInterceptor);
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static MethodInterceptor preAuthorizeAuthorizationMethodInterceptor(
ObjectProvider<GrantedAuthorityDefaults> defaultsProvider,
ObjectProvider<PrePostTemplateDefaults> methodSecurityDefaultsProvider,
ObjectProvider<MethodSecurityExpressionHandler> expressionHandlerProvider,
ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
ObjectProvider<AuthorizationEventPublisher> eventPublisherProvider,
ObjectProvider<ObservationRegistry> registryProvider, ObjectProvider<RoleHierarchy> roleHierarchyProvider,
PrePostMethodSecurityConfiguration configuration, ApplicationContext context) {
PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
manager.setApplicationContext(context);
AuthorizationManagerBeforeMethodInterceptor preAuthorize = AuthorizationManagerBeforeMethodInterceptor
.preAuthorize(manager(manager, registryProvider));
preAuthorize.setOrder(preAuthorize.getOrder() + configuration.interceptorOrderOffset);
return new DeferringMethodInterceptor<>(preAuthorize, (f) -> {
methodSecurityDefaultsProvider.ifAvailable(manager::setTemplateDefaults);
manager.setExpressionHandler(expressionHandlerProvider
.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, roleHierarchyProvider, context)));
strategyProvider.ifAvailable(f::setSecurityContextHolderStrategy);
eventPublisherProvider.ifAvailable(f::setAuthorizationEventPublisher);
});
ObjectProvider<PrePostMethodSecurityConfiguration> _prePostMethodSecurityConfiguration) {
return new DeferringMethodInterceptor<>(preAuthorizePointcut,
() -> _prePostMethodSecurityConfiguration.getObject().preAuthorizeMethodInterceptor);
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static MethodInterceptor postAuthorizeAuthorizationMethodInterceptor(
ObjectProvider<GrantedAuthorityDefaults> defaultsProvider,
ObjectProvider<PrePostTemplateDefaults> methodSecurityDefaultsProvider,
ObjectProvider<MethodSecurityExpressionHandler> expressionHandlerProvider,
ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
ObjectProvider<AuthorizationEventPublisher> eventPublisherProvider,
ObjectProvider<ObservationRegistry> registryProvider, ObjectProvider<RoleHierarchy> roleHierarchyProvider,
PrePostMethodSecurityConfiguration configuration, ApplicationContext context) {
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
manager.setApplicationContext(context);
AuthorizationManagerAfterMethodInterceptor postAuthorize = AuthorizationManagerAfterMethodInterceptor
.postAuthorize(manager(manager, registryProvider));
postAuthorize.setOrder(postAuthorize.getOrder() + configuration.interceptorOrderOffset);
return new DeferringMethodInterceptor<>(postAuthorize, (f) -> {
methodSecurityDefaultsProvider.ifAvailable(manager::setTemplateDefaults);
manager.setExpressionHandler(expressionHandlerProvider
.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, roleHierarchyProvider, context)));
strategyProvider.ifAvailable(f::setSecurityContextHolderStrategy);
eventPublisherProvider.ifAvailable(f::setAuthorizationEventPublisher);
});
ObjectProvider<PrePostMethodSecurityConfiguration> _prePostMethodSecurityConfiguration) {
return new DeferringMethodInterceptor<>(postAuthorizePointcut,
() -> _prePostMethodSecurityConfiguration.getObject().postAuthorizeMethodInterceptor);
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static MethodInterceptor postFilterAuthorizationMethodInterceptor(
ObjectProvider<GrantedAuthorityDefaults> defaultsProvider,
ObjectProvider<PrePostTemplateDefaults> methodSecurityDefaultsProvider,
ObjectProvider<MethodSecurityExpressionHandler> expressionHandlerProvider,
ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
ObjectProvider<RoleHierarchy> roleHierarchyProvider, PrePostMethodSecurityConfiguration configuration,
ApplicationContext context) {
PostFilterAuthorizationMethodInterceptor postFilter = new PostFilterAuthorizationMethodInterceptor();
postFilter.setOrder(postFilter.getOrder() + configuration.interceptorOrderOffset);
return new DeferringMethodInterceptor<>(postFilter, (f) -> {
methodSecurityDefaultsProvider.ifAvailable(f::setTemplateDefaults);
f.setExpressionHandler(expressionHandlerProvider
.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, roleHierarchyProvider, context)));
strategyProvider.ifAvailable(f::setSecurityContextHolderStrategy);
});
}
private static MethodSecurityExpressionHandler defaultExpressionHandler(
ObjectProvider<GrantedAuthorityDefaults> defaultsProvider,
ObjectProvider<RoleHierarchy> roleHierarchyProvider, ApplicationContext context) {
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
RoleHierarchy roleHierarchy = roleHierarchyProvider.getIfAvailable(NullRoleHierarchy::new);
handler.setRoleHierarchy(roleHierarchy);
defaultsProvider.ifAvailable((d) -> handler.setDefaultRolePrefix(d.getRolePrefix()));
handler.setApplicationContext(context);
return handler;
}
static <T> AuthorizationManager<T> manager(AuthorizationManager<T> delegate,
ObjectProvider<ObservationRegistry> registryProvider) {
return new DeferringObservationAuthorizationManager<>(registryProvider, delegate);
ObjectProvider<PrePostMethodSecurityConfiguration> _prePostMethodSecurityConfiguration) {
return new DeferringMethodInterceptor<>(postFilterPointcut,
() -> _prePostMethodSecurityConfiguration.getObject().postFilterMethodInterceptor);
}
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
EnableMethodSecurity annotation = importMetadata.getAnnotations().get(EnableMethodSecurity.class).synthesize();
this.interceptorOrderOffset = annotation.offset();
}
private static final class DeferringMethodInterceptor<M extends AuthorizationAdvisor>
implements AuthorizationAdvisor {
private final Pointcut pointcut;
private final int order;
private final Supplier<M> delegate;
DeferringMethodInterceptor(M delegate, Consumer<M> supplier) {
this.pointcut = delegate.getPointcut();
this.order = delegate.getOrder();
this.delegate = SingletonSupplier.of(() -> {
supplier.accept(delegate);
return delegate;
});
}
@Nullable
@Override
public Object invoke(@NotNull MethodInvocation invocation) throws Throwable {
return this.delegate.get().invoke(invocation);
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
@Override
public Advice getAdvice() {
return this;
}
@Override
public int getOrder() {
return this.order;
}
@Override
public boolean isPerInstance() {
return true;
}
this.preFilterMethodInterceptor.setOrder(this.preFilterMethodInterceptor.getOrder() + annotation.offset());
this.preAuthorizeMethodInterceptor
.setOrder(this.preAuthorizeMethodInterceptor.getOrder() + annotation.offset());
this.postAuthorizeMethodInterceptor
.setOrder(this.postAuthorizeMethodInterceptor.getOrder() + annotation.offset());
this.postFilterMethodInterceptor.setOrder(this.postFilterMethodInterceptor.getOrder() + annotation.offset());
}
}

View File

@ -16,12 +16,16 @@
package org.springframework.security.config.annotation.method.configuration;
import java.util.function.Supplier;
import io.micrometer.observation.ObservationRegistry;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.AopInfrastructureBean;
import org.springframework.beans.factory.ObjectProvider;
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;
@ -29,14 +33,13 @@ import org.springframework.context.annotation.ImportAware;
import org.springframework.context.annotation.Role;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.authorization.AuthoritiesAuthorizationManager;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.ObservationAuthorizationManager;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.authorization.method.SecuredAuthorizationManager;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
/**
@ -47,40 +50,59 @@ import org.springframework.security.core.context.SecurityContextHolderStrategy;
* @since 5.6
* @see EnableMethodSecurity
*/
@Configuration(proxyBeanMethods = false)
@Configuration(value = "_securedMethodSecurityConfiguration", proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
final class SecuredMethodSecurityConfiguration implements ImportAware, AopInfrastructureBean {
private int interceptorOrderOffset;
private static final Pointcut pointcut = AuthorizationManagerBeforeMethodInterceptor.secured().getPointcut();
private final SecuredAuthorizationManager authorizationManager = new SecuredAuthorizationManager();
private AuthorizationManagerBeforeMethodInterceptor methodInterceptor = AuthorizationManagerBeforeMethodInterceptor
.secured(this.authorizationManager);
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static MethodInterceptor securedAuthorizationMethodInterceptor(
ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
ObjectProvider<AuthorizationEventPublisher> eventPublisherProvider,
ObjectProvider<ObservationRegistry> registryProvider, ObjectProvider<RoleHierarchy> roleHierarchyProvider,
SecuredMethodSecurityConfiguration configuration) {
SecuredAuthorizationManager secured = new SecuredAuthorizationManager();
AuthoritiesAuthorizationManager authoritiesAuthorizationManager = new AuthoritiesAuthorizationManager();
RoleHierarchy roleHierarchy = roleHierarchyProvider.getIfAvailable(NullRoleHierarchy::new);
authoritiesAuthorizationManager.setRoleHierarchy(roleHierarchy);
secured.setAuthoritiesAuthorizationManager(authoritiesAuthorizationManager);
SecurityContextHolderStrategy strategy = strategyProvider
.getIfAvailable(SecurityContextHolder::getContextHolderStrategy);
AuthorizationManager<MethodInvocation> manager = new DeferringObservationAuthorizationManager<>(
registryProvider, secured);
AuthorizationManagerBeforeMethodInterceptor interceptor = AuthorizationManagerBeforeMethodInterceptor
.secured(manager);
interceptor.setOrder(interceptor.getOrder() + configuration.interceptorOrderOffset);
interceptor.setSecurityContextHolderStrategy(strategy);
eventPublisherProvider.ifAvailable(interceptor::setAuthorizationEventPublisher);
return interceptor;
ObjectProvider<SecuredMethodSecurityConfiguration> securedMethodSecurityConfiguration) {
Supplier<AuthorizationManagerBeforeMethodInterceptor> supplier = () -> {
SecuredMethodSecurityConfiguration configuration = securedMethodSecurityConfiguration.getObject();
return configuration.methodInterceptor;
};
return new DeferringMethodInterceptor<>(pointcut, supplier);
}
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
EnableMethodSecurity annotation = importMetadata.getAnnotations().get(EnableMethodSecurity.class).synthesize();
this.interceptorOrderOffset = annotation.offset();
this.methodInterceptor.setOrder(this.methodInterceptor.getOrder() + annotation.offset());
}
@Autowired(required = false)
void setRoleHierarchy(RoleHierarchy roleHierarchy) {
AuthoritiesAuthorizationManager authoritiesAuthorizationManager = new AuthoritiesAuthorizationManager();
authoritiesAuthorizationManager.setRoleHierarchy(roleHierarchy);
this.authorizationManager.setAuthoritiesAuthorizationManager(authoritiesAuthorizationManager);
}
@Autowired(required = false)
void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
this.methodInterceptor.setSecurityContextHolderStrategy(securityContextHolderStrategy);
}
@Autowired(required = false)
void setObservationRegistry(ObservationRegistry registry) {
if (registry.isNoop()) {
return;
}
AuthorizationManager<MethodInvocation> observed = new ObservationAuthorizationManager<>(registry,
this.authorizationManager);
this.methodInterceptor = AuthorizationManagerBeforeMethodInterceptor.secured(observed);
}
@Autowired(required = false)
void setEventPublisher(AuthorizationEventPublisher eventPublisher) {
this.methodInterceptor.setAuthorizationEventPublisher(eventPublisher);
}
}