mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-23 20:42:14 +00:00
Use addAdvisors in Reactive Proxy Configuration
Issue gh-15497
This commit is contained in:
parent
3ee973de77
commit
2bb3787d2b
@ -16,22 +16,17 @@
|
|||||||
|
|
||||||
package org.springframework.security.config.annotation.method.configuration;
|
package org.springframework.security.config.annotation.method.configuration;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
import io.micrometer.observation.ObservationRegistry;
|
||||||
import org.aopalliance.aop.Advice;
|
|
||||||
import org.aopalliance.intercept.MethodInterceptor;
|
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.Pointcut;
|
||||||
import org.springframework.aop.framework.AopInfrastructureBean;
|
import org.springframework.aop.framework.AopInfrastructureBean;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Fallback;
|
import org.springframework.context.annotation.Fallback;
|
||||||
@ -39,18 +34,15 @@ import org.springframework.context.annotation.Role;
|
|||||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||||
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||||
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||||
import org.springframework.security.authorization.ReactiveAuthorizationManager;
|
import org.springframework.security.authorization.ObservationReactiveAuthorizationManager;
|
||||||
import org.springframework.security.authorization.method.AuthorizationAdvisor;
|
|
||||||
import org.springframework.security.authorization.method.AuthorizationManagerAfterReactiveMethodInterceptor;
|
import org.springframework.security.authorization.method.AuthorizationManagerAfterReactiveMethodInterceptor;
|
||||||
import org.springframework.security.authorization.method.AuthorizationManagerBeforeReactiveMethodInterceptor;
|
import org.springframework.security.authorization.method.AuthorizationManagerBeforeReactiveMethodInterceptor;
|
||||||
import org.springframework.security.authorization.method.MethodInvocationResult;
|
|
||||||
import org.springframework.security.authorization.method.PostAuthorizeReactiveAuthorizationManager;
|
import org.springframework.security.authorization.method.PostAuthorizeReactiveAuthorizationManager;
|
||||||
import org.springframework.security.authorization.method.PostFilterAuthorizationReactiveMethodInterceptor;
|
import org.springframework.security.authorization.method.PostFilterAuthorizationReactiveMethodInterceptor;
|
||||||
import org.springframework.security.authorization.method.PreAuthorizeReactiveAuthorizationManager;
|
import org.springframework.security.authorization.method.PreAuthorizeReactiveAuthorizationManager;
|
||||||
import org.springframework.security.authorization.method.PreFilterAuthorizationReactiveMethodInterceptor;
|
import org.springframework.security.authorization.method.PreFilterAuthorizationReactiveMethodInterceptor;
|
||||||
import org.springframework.security.authorization.method.PrePostTemplateDefaults;
|
import org.springframework.security.authorization.method.PrePostTemplateDefaults;
|
||||||
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
||||||
import org.springframework.util.function.SingletonSupplier;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration for a {@link ReactiveAuthenticationManager} based Method Security.
|
* Configuration for a {@link ReactiveAuthenticationManager} based Method Security.
|
||||||
@ -58,59 +50,105 @@ import org.springframework.util.function.SingletonSupplier;
|
|||||||
* @author Evgeniy Cheban
|
* @author Evgeniy Cheban
|
||||||
* @since 5.8
|
* @since 5.8
|
||||||
*/
|
*/
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(value = "_reactiveMethodSecurityConfiguration", proxyBeanMethods = false)
|
||||||
final class ReactiveAuthorizationManagerMethodSecurityConfiguration implements AopInfrastructureBean {
|
final class ReactiveAuthorizationManagerMethodSecurityConfiguration
|
||||||
|
implements AopInfrastructureBean, ApplicationContextAware {
|
||||||
|
|
||||||
|
private static final Pointcut preFilterPointcut = new PreFilterAuthorizationReactiveMethodInterceptor()
|
||||||
|
.getPointcut();
|
||||||
|
|
||||||
|
private static final Pointcut preAuthorizePointcut = AuthorizationManagerBeforeReactiveMethodInterceptor
|
||||||
|
.preAuthorize()
|
||||||
|
.getPointcut();
|
||||||
|
|
||||||
|
private static final Pointcut postAuthorizePointcut = AuthorizationManagerAfterReactiveMethodInterceptor
|
||||||
|
.postAuthorize()
|
||||||
|
.getPointcut();
|
||||||
|
|
||||||
|
private static final Pointcut postFilterPointcut = new PostFilterAuthorizationReactiveMethodInterceptor()
|
||||||
|
.getPointcut();
|
||||||
|
|
||||||
|
private PreFilterAuthorizationReactiveMethodInterceptor preFilterMethodInterceptor = new PreFilterAuthorizationReactiveMethodInterceptor();
|
||||||
|
|
||||||
|
private PreAuthorizeReactiveAuthorizationManager preAuthorizeAuthorizationManager = new PreAuthorizeReactiveAuthorizationManager();
|
||||||
|
|
||||||
|
private PostAuthorizeReactiveAuthorizationManager postAuthorizeAuthorizationManager = new PostAuthorizeReactiveAuthorizationManager();
|
||||||
|
|
||||||
|
private PostFilterAuthorizationReactiveMethodInterceptor postFilterMethodInterceptor = new PostFilterAuthorizationReactiveMethodInterceptor();
|
||||||
|
|
||||||
|
private AuthorizationManagerBeforeReactiveMethodInterceptor preAuthorizeMethodInterceptor;
|
||||||
|
|
||||||
|
private AuthorizationManagerAfterReactiveMethodInterceptor postAuthorizeMethodInterceptor;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
ReactiveAuthorizationManagerMethodSecurityConfiguration(MethodSecurityExpressionHandler expressionHandler) {
|
||||||
|
if (expressionHandler != null) {
|
||||||
|
this.preFilterMethodInterceptor = new PreFilterAuthorizationReactiveMethodInterceptor(expressionHandler);
|
||||||
|
this.preAuthorizeAuthorizationManager = new PreAuthorizeReactiveAuthorizationManager(expressionHandler);
|
||||||
|
this.postFilterMethodInterceptor = new PostFilterAuthorizationReactiveMethodInterceptor(expressionHandler);
|
||||||
|
this.postAuthorizeAuthorizationManager = new PostAuthorizeReactiveAuthorizationManager(expressionHandler);
|
||||||
|
}
|
||||||
|
this.preAuthorizeMethodInterceptor = AuthorizationManagerBeforeReactiveMethodInterceptor
|
||||||
|
.preAuthorize(this.preAuthorizeAuthorizationManager);
|
||||||
|
this.postAuthorizeMethodInterceptor = AuthorizationManagerAfterReactiveMethodInterceptor
|
||||||
|
.postAuthorize(this.postAuthorizeAuthorizationManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(ApplicationContext context) throws BeansException {
|
||||||
|
this.preAuthorizeAuthorizationManager.setApplicationContext(context);
|
||||||
|
this.postAuthorizeAuthorizationManager.setApplicationContext(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 setObservationRegistry(ObservationRegistry registry) {
|
||||||
|
if (registry.isNoop()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.preAuthorizeMethodInterceptor = AuthorizationManagerBeforeReactiveMethodInterceptor.preAuthorize(
|
||||||
|
new ObservationReactiveAuthorizationManager<>(registry, this.preAuthorizeAuthorizationManager));
|
||||||
|
this.postAuthorizeMethodInterceptor = AuthorizationManagerAfterReactiveMethodInterceptor.postAuthorize(
|
||||||
|
new ObservationReactiveAuthorizationManager<>(registry, this.postAuthorizeAuthorizationManager));
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
static MethodInterceptor preFilterAuthorizationMethodInterceptor(MethodSecurityExpressionHandler expressionHandler,
|
static MethodInterceptor preFilterAuthorizationMethodInterceptor(
|
||||||
ObjectProvider<PrePostTemplateDefaults> defaultsObjectProvider) {
|
ObjectProvider<ReactiveAuthorizationManagerMethodSecurityConfiguration> _reactiveMethodSecurityConfiguration) {
|
||||||
PreFilterAuthorizationReactiveMethodInterceptor interceptor = new PreFilterAuthorizationReactiveMethodInterceptor(
|
return new DeferringMethodInterceptor<>(preFilterPointcut,
|
||||||
expressionHandler);
|
() -> _reactiveMethodSecurityConfiguration.getObject().preFilterMethodInterceptor);
|
||||||
return new DeferringMethodInterceptor<>(interceptor,
|
|
||||||
(i) -> defaultsObjectProvider.ifAvailable(i::setTemplateDefaults));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
static MethodInterceptor preAuthorizeAuthorizationMethodInterceptor(
|
static MethodInterceptor preAuthorizeAuthorizationMethodInterceptor(
|
||||||
MethodSecurityExpressionHandler expressionHandler,
|
ObjectProvider<ReactiveAuthorizationManagerMethodSecurityConfiguration> _reactiveMethodSecurityConfiguration) {
|
||||||
ObjectProvider<PrePostTemplateDefaults> defaultsObjectProvider,
|
return new DeferringMethodInterceptor<>(preAuthorizePointcut,
|
||||||
ObjectProvider<ObservationRegistry> registryProvider, ApplicationContext context) {
|
() -> _reactiveMethodSecurityConfiguration.getObject().preAuthorizeMethodInterceptor);
|
||||||
PreAuthorizeReactiveAuthorizationManager manager = new PreAuthorizeReactiveAuthorizationManager(
|
|
||||||
expressionHandler);
|
|
||||||
manager.setApplicationContext(context);
|
|
||||||
ReactiveAuthorizationManager<MethodInvocation> authorizationManager = manager(manager, registryProvider);
|
|
||||||
AuthorizationAdvisor interceptor = AuthorizationManagerBeforeReactiveMethodInterceptor
|
|
||||||
.preAuthorize(authorizationManager);
|
|
||||||
return new DeferringMethodInterceptor<>(interceptor,
|
|
||||||
(i) -> defaultsObjectProvider.ifAvailable(manager::setTemplateDefaults));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
static MethodInterceptor postFilterAuthorizationMethodInterceptor(MethodSecurityExpressionHandler expressionHandler,
|
static MethodInterceptor postFilterAuthorizationMethodInterceptor(
|
||||||
ObjectProvider<PrePostTemplateDefaults> defaultsObjectProvider) {
|
ObjectProvider<ReactiveAuthorizationManagerMethodSecurityConfiguration> _reactiveMethodSecurityConfiguration) {
|
||||||
PostFilterAuthorizationReactiveMethodInterceptor interceptor = new PostFilterAuthorizationReactiveMethodInterceptor(
|
return new DeferringMethodInterceptor<>(postFilterPointcut,
|
||||||
expressionHandler);
|
() -> _reactiveMethodSecurityConfiguration.getObject().postFilterMethodInterceptor);
|
||||||
return new DeferringMethodInterceptor<>(interceptor,
|
|
||||||
(i) -> defaultsObjectProvider.ifAvailable(i::setTemplateDefaults));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
static MethodInterceptor postAuthorizeAuthorizationMethodInterceptor(
|
static MethodInterceptor postAuthorizeAuthorizationMethodInterceptor(
|
||||||
MethodSecurityExpressionHandler expressionHandler,
|
ObjectProvider<ReactiveAuthorizationManagerMethodSecurityConfiguration> _reactiveMethodSecurityConfiguration) {
|
||||||
ObjectProvider<PrePostTemplateDefaults> defaultsObjectProvider,
|
return new DeferringMethodInterceptor<>(postAuthorizePointcut,
|
||||||
ObjectProvider<ObservationRegistry> registryProvider, ApplicationContext context) {
|
() -> _reactiveMethodSecurityConfiguration.getObject().postAuthorizeMethodInterceptor);
|
||||||
PostAuthorizeReactiveAuthorizationManager manager = new PostAuthorizeReactiveAuthorizationManager(
|
|
||||||
expressionHandler);
|
|
||||||
manager.setApplicationContext(context);
|
|
||||||
ReactiveAuthorizationManager<MethodInvocationResult> authorizationManager = manager(manager, registryProvider);
|
|
||||||
AuthorizationAdvisor interceptor = AuthorizationManagerAfterReactiveMethodInterceptor
|
|
||||||
.postAuthorize(authorizationManager);
|
|
||||||
return new DeferringMethodInterceptor<>(interceptor,
|
|
||||||
(i) -> defaultsObjectProvider.ifAvailable(manager::setTemplateDefaults));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ -125,55 +163,4 @@ final class ReactiveAuthorizationManagerMethodSecurityConfiguration implements A
|
|||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
static <T> ReactiveAuthorizationManager<T> manager(ReactiveAuthorizationManager<T> delegate,
|
|
||||||
ObjectProvider<ObservationRegistry> registryProvider) {
|
|
||||||
return new DeferringObservationReactiveAuthorizationManager<>(registryProvider, delegate);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.aopalliance.intercept.MethodInterceptor;
|
|
||||||
|
|
||||||
import org.springframework.aop.framework.AopInfrastructureBean;
|
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.Role;
|
|
||||||
import org.springframework.security.authorization.method.AuthorizationAdvisor;
|
|
||||||
import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory;
|
|
||||||
import org.springframework.security.authorization.method.AuthorizeReturnObjectMethodInterceptor;
|
|
||||||
import org.springframework.security.config.Customizer;
|
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
|
||||||
final class ReactiveAuthorizationProxyConfiguration implements AopInfrastructureBean {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
|
||||||
static AuthorizationAdvisorProxyFactory authorizationProxyFactory(ObjectProvider<AuthorizationAdvisor> provider,
|
|
||||||
ObjectProvider<Customizer<AuthorizationAdvisorProxyFactory>> customizers) {
|
|
||||||
List<AuthorizationAdvisor> advisors = new ArrayList<>();
|
|
||||||
provider.forEach(advisors::add);
|
|
||||||
AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withReactiveDefaults();
|
|
||||||
customizers.forEach((c) -> c.customize(factory));
|
|
||||||
factory.setAdvisors(advisors);
|
|
||||||
return factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
|
||||||
static MethodInterceptor authorizeReturnObjectMethodInterceptor(ObjectProvider<AuthorizationAdvisor> provider,
|
|
||||||
AuthorizationAdvisorProxyFactory authorizationProxyFactory) {
|
|
||||||
AuthorizeReturnObjectMethodInterceptor interceptor = new AuthorizeReturnObjectMethodInterceptor(
|
|
||||||
authorizationProxyFactory);
|
|
||||||
List<AuthorizationAdvisor> advisors = new ArrayList<>();
|
|
||||||
provider.forEach(advisors::add);
|
|
||||||
advisors.add(interceptor);
|
|
||||||
authorizationProxyFactory.setAdvisors(advisors);
|
|
||||||
return interceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -51,7 +51,7 @@ class ReactiveMethodSecuritySelector implements ImportSelector {
|
|||||||
else {
|
else {
|
||||||
imports.add(ReactiveMethodSecurityConfiguration.class.getName());
|
imports.add(ReactiveMethodSecurityConfiguration.class.getName());
|
||||||
}
|
}
|
||||||
imports.add(ReactiveAuthorizationProxyConfiguration.class.getName());
|
imports.add(AuthorizationProxyConfiguration.class.getName());
|
||||||
return imports.toArray(new String[0]);
|
return imports.toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user