Simplify Method Interceptor Configuration
Simplifies to use only one ObjectProvider for easier future maintenance Issue gh-15592
This commit is contained in:
parent
24036578df
commit
27af1df87d
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue