Abstract ObservationRegistry Behind ObjectPostProcessor
Issue gh-15678
This commit is contained in:
parent
1ed20aa210
commit
69e3c248fa
|
@ -31,6 +31,15 @@ import org.springframework.beans.factory.InitializingBean;
|
||||||
*/
|
*/
|
||||||
public interface ObjectPostProcessor<T> {
|
public interface ObjectPostProcessor<T> {
|
||||||
|
|
||||||
|
static <S> ObjectPostProcessor<S> identity() {
|
||||||
|
return new ObjectPostProcessor<>() {
|
||||||
|
@Override
|
||||||
|
public <O extends S> O postProcess(O object) {
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the object possibly returning a modified instance that should be used
|
* Initialize the object possibly returning a modified instance that should be used
|
||||||
* instead.
|
* instead.
|
||||||
|
|
|
@ -18,7 +18,6 @@ package org.springframework.security.config.annotation.method.configuration;
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
|
||||||
import org.aopalliance.intercept.MethodInterceptor;
|
import org.aopalliance.intercept.MethodInterceptor;
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
|
||||||
|
@ -36,9 +35,9 @@ import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||||
import org.springframework.security.authorization.AuthoritiesAuthorizationManager;
|
import org.springframework.security.authorization.AuthoritiesAuthorizationManager;
|
||||||
import org.springframework.security.authorization.AuthorizationEventPublisher;
|
import org.springframework.security.authorization.AuthorizationEventPublisher;
|
||||||
import org.springframework.security.authorization.AuthorizationManager;
|
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.AuthorizationManagerBeforeMethodInterceptor;
|
||||||
import org.springframework.security.authorization.method.Jsr250AuthorizationManager;
|
import org.springframework.security.authorization.method.Jsr250AuthorizationManager;
|
||||||
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
||||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
|
|
||||||
|
@ -58,8 +57,15 @@ final class Jsr250MethodSecurityConfiguration implements ImportAware, AopInfrast
|
||||||
|
|
||||||
private final Jsr250AuthorizationManager authorizationManager = new Jsr250AuthorizationManager();
|
private final Jsr250AuthorizationManager authorizationManager = new Jsr250AuthorizationManager();
|
||||||
|
|
||||||
private AuthorizationManagerBeforeMethodInterceptor methodInterceptor = AuthorizationManagerBeforeMethodInterceptor
|
private final AuthorizationManagerBeforeMethodInterceptor methodInterceptor;
|
||||||
.jsr250(this.authorizationManager);
|
|
||||||
|
Jsr250MethodSecurityConfiguration(
|
||||||
|
ObjectProvider<ObjectPostProcessor<AuthorizationManager<MethodInvocation>>> postProcessors) {
|
||||||
|
ObjectPostProcessor<AuthorizationManager<MethodInvocation>> postProcessor = postProcessors
|
||||||
|
.getIfUnique(ObjectPostProcessor::identity);
|
||||||
|
AuthorizationManager<MethodInvocation> manager = postProcessor.postProcess(this.authorizationManager);
|
||||||
|
this.methodInterceptor = AuthorizationManagerBeforeMethodInterceptor.jsr250(manager);
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
@ -95,16 +101,6 @@ final class Jsr250MethodSecurityConfiguration implements ImportAware, AopInfrast
|
||||||
this.methodInterceptor.setSecurityContextHolderStrategy(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)
|
@Autowired(required = false)
|
||||||
void setEventPublisher(AuthorizationEventPublisher eventPublisher) {
|
void setEventPublisher(AuthorizationEventPublisher eventPublisher) {
|
||||||
this.methodInterceptor.setAuthorizationEventPublisher(eventPublisher);
|
this.methodInterceptor.setAuthorizationEventPublisher(eventPublisher);
|
||||||
|
|
|
@ -41,6 +41,9 @@ final class MethodSecuritySelector implements ImportSelector {
|
||||||
private static final boolean isDataPresent = ClassUtils
|
private static final boolean isDataPresent = ClassUtils
|
||||||
.isPresent("org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar", null);
|
.isPresent("org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar", null);
|
||||||
|
|
||||||
|
private static final boolean isObservabilityPresent = ClassUtils
|
||||||
|
.isPresent("io.micrometer.observation.ObservationRegistry", null);
|
||||||
|
|
||||||
private final ImportSelector autoProxy = new AutoProxyRegistrarSelector();
|
private final ImportSelector autoProxy = new AutoProxyRegistrarSelector();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -64,6 +67,10 @@ final class MethodSecuritySelector implements ImportSelector {
|
||||||
if (isDataPresent) {
|
if (isDataPresent) {
|
||||||
imports.add(AuthorizationProxyDataConfiguration.class.getName());
|
imports.add(AuthorizationProxyDataConfiguration.class.getName());
|
||||||
}
|
}
|
||||||
|
if (isObservabilityPresent) {
|
||||||
|
imports.add(
|
||||||
|
"org.springframework.security.config.annotation.observation.configuration.ObservationConfiguration");
|
||||||
|
}
|
||||||
return imports.toArray(new String[0]);
|
return imports.toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.security.config.annotation.method.configuration;
|
package org.springframework.security.config.annotation.method.configuration;
|
||||||
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
|
||||||
import org.aopalliance.intercept.MethodInterceptor;
|
import org.aopalliance.intercept.MethodInterceptor;
|
||||||
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
|
||||||
import org.springframework.aop.Pointcut;
|
import org.springframework.aop.Pointcut;
|
||||||
import org.springframework.aop.framework.AopInfrastructureBean;
|
import org.springframework.aop.framework.AopInfrastructureBean;
|
||||||
|
@ -38,14 +38,16 @@ import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||||
import org.springframework.security.aot.hint.PrePostAuthorizeHintsRegistrar;
|
import org.springframework.security.aot.hint.PrePostAuthorizeHintsRegistrar;
|
||||||
import org.springframework.security.aot.hint.SecurityHintsRegistrar;
|
import org.springframework.security.aot.hint.SecurityHintsRegistrar;
|
||||||
import org.springframework.security.authorization.AuthorizationEventPublisher;
|
import org.springframework.security.authorization.AuthorizationEventPublisher;
|
||||||
import org.springframework.security.authorization.ObservationAuthorizationManager;
|
import org.springframework.security.authorization.AuthorizationManager;
|
||||||
import org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor;
|
import org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor;
|
||||||
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
|
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
|
||||||
|
import org.springframework.security.authorization.method.MethodInvocationResult;
|
||||||
import org.springframework.security.authorization.method.PostAuthorizeAuthorizationManager;
|
import org.springframework.security.authorization.method.PostAuthorizeAuthorizationManager;
|
||||||
import org.springframework.security.authorization.method.PostFilterAuthorizationMethodInterceptor;
|
import org.springframework.security.authorization.method.PostFilterAuthorizationMethodInterceptor;
|
||||||
import org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager;
|
import org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager;
|
||||||
import org.springframework.security.authorization.method.PreFilterAuthorizationMethodInterceptor;
|
import org.springframework.security.authorization.method.PreFilterAuthorizationMethodInterceptor;
|
||||||
import org.springframework.security.authorization.method.PrePostTemplateDefaults;
|
import org.springframework.security.authorization.method.PrePostTemplateDefaults;
|
||||||
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
||||||
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
|
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
|
||||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
|
@ -78,21 +80,29 @@ final class PrePostMethodSecurityConfiguration implements ImportAware, Applicati
|
||||||
|
|
||||||
private final PreFilterAuthorizationMethodInterceptor preFilterMethodInterceptor = new PreFilterAuthorizationMethodInterceptor();
|
private final PreFilterAuthorizationMethodInterceptor preFilterMethodInterceptor = new PreFilterAuthorizationMethodInterceptor();
|
||||||
|
|
||||||
private AuthorizationManagerBeforeMethodInterceptor preAuthorizeMethodInterceptor = AuthorizationManagerBeforeMethodInterceptor
|
private final AuthorizationManagerBeforeMethodInterceptor preAuthorizeMethodInterceptor;
|
||||||
.preAuthorize(this.preAuthorizeAuthorizationManager);
|
|
||||||
|
|
||||||
private AuthorizationManagerAfterMethodInterceptor postAuthorizeMethodInterceptor = AuthorizationManagerAfterMethodInterceptor
|
private final AuthorizationManagerAfterMethodInterceptor postAuthorizeMethodInterceptor;
|
||||||
.postAuthorize(this.postAuthorizeAuthorizationManager);
|
|
||||||
|
|
||||||
private final PostFilterAuthorizationMethodInterceptor postFilterMethodInterceptor = new PostFilterAuthorizationMethodInterceptor();
|
private final PostFilterAuthorizationMethodInterceptor postFilterMethodInterceptor = new PostFilterAuthorizationMethodInterceptor();
|
||||||
|
|
||||||
private final DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
private final DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||||
|
|
||||||
{
|
PrePostMethodSecurityConfiguration(
|
||||||
|
ObjectProvider<ObjectPostProcessor<AuthorizationManager<MethodInvocation>>> preAuthorizeProcessor,
|
||||||
|
ObjectProvider<ObjectPostProcessor<AuthorizationManager<MethodInvocationResult>>> postAuthorizeProcessor) {
|
||||||
this.preFilterMethodInterceptor.setExpressionHandler(this.expressionHandler);
|
this.preFilterMethodInterceptor.setExpressionHandler(this.expressionHandler);
|
||||||
this.preAuthorizeAuthorizationManager.setExpressionHandler(this.expressionHandler);
|
this.preAuthorizeAuthorizationManager.setExpressionHandler(this.expressionHandler);
|
||||||
this.postAuthorizeAuthorizationManager.setExpressionHandler(this.expressionHandler);
|
this.postAuthorizeAuthorizationManager.setExpressionHandler(this.expressionHandler);
|
||||||
this.postFilterMethodInterceptor.setExpressionHandler(this.expressionHandler);
|
this.postFilterMethodInterceptor.setExpressionHandler(this.expressionHandler);
|
||||||
|
AuthorizationManager<MethodInvocation> preAuthorize = preAuthorizeProcessor
|
||||||
|
.getIfUnique(ObjectPostProcessor::identity)
|
||||||
|
.postProcess(this.preAuthorizeAuthorizationManager);
|
||||||
|
this.preAuthorizeMethodInterceptor = AuthorizationManagerBeforeMethodInterceptor.preAuthorize(preAuthorize);
|
||||||
|
AuthorizationManager<MethodInvocationResult> postAuthorize = postAuthorizeProcessor
|
||||||
|
.getIfUnique(ObjectPostProcessor::identity)
|
||||||
|
.postProcess(this.postAuthorizeAuthorizationManager);
|
||||||
|
this.postAuthorizeMethodInterceptor = AuthorizationManagerAfterMethodInterceptor.postAuthorize(postAuthorize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -144,17 +154,6 @@ final class PrePostMethodSecurityConfiguration implements ImportAware, Applicati
|
||||||
this.postFilterMethodInterceptor.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)
|
@Autowired(required = false)
|
||||||
void setAuthorizationEventPublisher(AuthorizationEventPublisher publisher) {
|
void setAuthorizationEventPublisher(AuthorizationEventPublisher publisher) {
|
||||||
this.preAuthorizeMethodInterceptor.setAuthorizationEventPublisher(publisher);
|
this.preAuthorizeMethodInterceptor.setAuthorizationEventPublisher(publisher);
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.security.config.annotation.method.configuration;
|
package org.springframework.security.config.annotation.method.configuration;
|
||||||
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
|
||||||
import org.aopalliance.intercept.MethodInterceptor;
|
import org.aopalliance.intercept.MethodInterceptor;
|
||||||
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
|
||||||
import org.springframework.aop.Pointcut;
|
import org.springframework.aop.Pointcut;
|
||||||
import org.springframework.aop.framework.AopInfrastructureBean;
|
import org.springframework.aop.framework.AopInfrastructureBean;
|
||||||
|
@ -34,14 +34,16 @@ 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.ObservationReactiveAuthorizationManager;
|
import org.springframework.security.authorization.ReactiveAuthorizationManager;
|
||||||
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.annotation.ObjectPostProcessor;
|
||||||
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
||||||
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
|
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
|
||||||
|
|
||||||
|
@ -77,22 +79,30 @@ final class ReactiveAuthorizationManagerMethodSecurityConfiguration
|
||||||
|
|
||||||
private PostFilterAuthorizationReactiveMethodInterceptor postFilterMethodInterceptor = new PostFilterAuthorizationReactiveMethodInterceptor();
|
private PostFilterAuthorizationReactiveMethodInterceptor postFilterMethodInterceptor = new PostFilterAuthorizationReactiveMethodInterceptor();
|
||||||
|
|
||||||
private AuthorizationManagerBeforeReactiveMethodInterceptor preAuthorizeMethodInterceptor;
|
private final AuthorizationManagerBeforeReactiveMethodInterceptor preAuthorizeMethodInterceptor;
|
||||||
|
|
||||||
private AuthorizationManagerAfterReactiveMethodInterceptor postAuthorizeMethodInterceptor;
|
private final AuthorizationManagerAfterReactiveMethodInterceptor postAuthorizeMethodInterceptor;
|
||||||
|
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
ReactiveAuthorizationManagerMethodSecurityConfiguration(MethodSecurityExpressionHandler expressionHandler) {
|
ReactiveAuthorizationManagerMethodSecurityConfiguration(MethodSecurityExpressionHandler expressionHandler,
|
||||||
|
ObjectProvider<ObjectPostProcessor<ReactiveAuthorizationManager<MethodInvocation>>> preAuthorizePostProcessor,
|
||||||
|
ObjectProvider<ObjectPostProcessor<ReactiveAuthorizationManager<MethodInvocationResult>>> postAuthorizePostProcessor) {
|
||||||
if (expressionHandler != null) {
|
if (expressionHandler != null) {
|
||||||
this.preFilterMethodInterceptor = new PreFilterAuthorizationReactiveMethodInterceptor(expressionHandler);
|
this.preFilterMethodInterceptor = new PreFilterAuthorizationReactiveMethodInterceptor(expressionHandler);
|
||||||
this.preAuthorizeAuthorizationManager = new PreAuthorizeReactiveAuthorizationManager(expressionHandler);
|
this.preAuthorizeAuthorizationManager = new PreAuthorizeReactiveAuthorizationManager(expressionHandler);
|
||||||
this.postFilterMethodInterceptor = new PostFilterAuthorizationReactiveMethodInterceptor(expressionHandler);
|
this.postFilterMethodInterceptor = new PostFilterAuthorizationReactiveMethodInterceptor(expressionHandler);
|
||||||
this.postAuthorizeAuthorizationManager = new PostAuthorizeReactiveAuthorizationManager(expressionHandler);
|
this.postAuthorizeAuthorizationManager = new PostAuthorizeReactiveAuthorizationManager(expressionHandler);
|
||||||
}
|
}
|
||||||
|
ReactiveAuthorizationManager<MethodInvocation> preAuthorize = preAuthorizePostProcessor
|
||||||
|
.getIfUnique(ObjectPostProcessor::identity)
|
||||||
|
.postProcess(this.preAuthorizeAuthorizationManager);
|
||||||
this.preAuthorizeMethodInterceptor = AuthorizationManagerBeforeReactiveMethodInterceptor
|
this.preAuthorizeMethodInterceptor = AuthorizationManagerBeforeReactiveMethodInterceptor
|
||||||
.preAuthorize(this.preAuthorizeAuthorizationManager);
|
.preAuthorize(preAuthorize);
|
||||||
|
ReactiveAuthorizationManager<MethodInvocationResult> postAuthorize = postAuthorizePostProcessor
|
||||||
|
.getIfAvailable(ObjectPostProcessor::identity)
|
||||||
|
.postProcess(this.postAuthorizeAuthorizationManager);
|
||||||
this.postAuthorizeMethodInterceptor = AuthorizationManagerAfterReactiveMethodInterceptor
|
this.postAuthorizeMethodInterceptor = AuthorizationManagerAfterReactiveMethodInterceptor
|
||||||
.postAuthorize(this.postAuthorizeAuthorizationManager);
|
.postAuthorize(postAuthorize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -117,17 +127,6 @@ final class ReactiveAuthorizationManagerMethodSecurityConfiguration
|
||||||
this.postFilterMethodInterceptor.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(
|
static MethodInterceptor preFilterAuthorizationMethodInterceptor(
|
||||||
|
|
|
@ -38,6 +38,9 @@ class ReactiveMethodSecuritySelector implements ImportSelector {
|
||||||
private static final boolean isDataPresent = ClassUtils
|
private static final boolean isDataPresent = ClassUtils
|
||||||
.isPresent("org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar", null);
|
.isPresent("org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar", null);
|
||||||
|
|
||||||
|
private static final boolean isObservabilityPresent = ClassUtils
|
||||||
|
.isPresent("io.micrometer.observation.ObservationRegistry", null);
|
||||||
|
|
||||||
private final ImportSelector autoProxy = new AutoProxyRegistrarSelector();
|
private final ImportSelector autoProxy = new AutoProxyRegistrarSelector();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -58,6 +61,10 @@ class ReactiveMethodSecuritySelector implements ImportSelector {
|
||||||
if (isDataPresent) {
|
if (isDataPresent) {
|
||||||
imports.add(AuthorizationProxyDataConfiguration.class.getName());
|
imports.add(AuthorizationProxyDataConfiguration.class.getName());
|
||||||
}
|
}
|
||||||
|
if (isObservabilityPresent) {
|
||||||
|
imports.add(
|
||||||
|
"org.springframework.security.config.annotation.observation.configuration.ReactiveObservationConfiguration");
|
||||||
|
}
|
||||||
imports.add(AuthorizationProxyConfiguration.class.getName());
|
imports.add(AuthorizationProxyConfiguration.class.getName());
|
||||||
return imports.toArray(new String[0]);
|
return imports.toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ package org.springframework.security.config.annotation.method.configuration;
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
|
||||||
import org.aopalliance.intercept.MethodInterceptor;
|
import org.aopalliance.intercept.MethodInterceptor;
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
|
||||||
|
@ -37,9 +36,9 @@ import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||||
import org.springframework.security.authorization.AuthoritiesAuthorizationManager;
|
import org.springframework.security.authorization.AuthoritiesAuthorizationManager;
|
||||||
import org.springframework.security.authorization.AuthorizationEventPublisher;
|
import org.springframework.security.authorization.AuthorizationEventPublisher;
|
||||||
import org.springframework.security.authorization.AuthorizationManager;
|
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.AuthorizationManagerBeforeMethodInterceptor;
|
||||||
import org.springframework.security.authorization.method.SecuredAuthorizationManager;
|
import org.springframework.security.authorization.method.SecuredAuthorizationManager;
|
||||||
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,8 +57,15 @@ final class SecuredMethodSecurityConfiguration implements ImportAware, AopInfras
|
||||||
|
|
||||||
private final SecuredAuthorizationManager authorizationManager = new SecuredAuthorizationManager();
|
private final SecuredAuthorizationManager authorizationManager = new SecuredAuthorizationManager();
|
||||||
|
|
||||||
private AuthorizationManagerBeforeMethodInterceptor methodInterceptor = AuthorizationManagerBeforeMethodInterceptor
|
private final AuthorizationManagerBeforeMethodInterceptor methodInterceptor;
|
||||||
.secured(this.authorizationManager);
|
|
||||||
|
SecuredMethodSecurityConfiguration(
|
||||||
|
ObjectProvider<ObjectPostProcessor<AuthorizationManager<MethodInvocation>>> postProcessors) {
|
||||||
|
ObjectPostProcessor<AuthorizationManager<MethodInvocation>> postProcessor = postProcessors
|
||||||
|
.getIfUnique(ObjectPostProcessor::identity);
|
||||||
|
AuthorizationManager<MethodInvocation> manager = postProcessor.postProcess(this.authorizationManager);
|
||||||
|
this.methodInterceptor = AuthorizationManagerBeforeMethodInterceptor.secured(manager);
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
@ -90,16 +96,6 @@ final class SecuredMethodSecurityConfiguration implements ImportAware, AopInfras
|
||||||
this.methodInterceptor.setSecurityContextHolderStrategy(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)
|
@Autowired(required = false)
|
||||||
void setEventPublisher(AuthorizationEventPublisher eventPublisher) {
|
void setEventPublisher(AuthorizationEventPublisher eventPublisher) {
|
||||||
this.methodInterceptor.setAuthorizationEventPublisher(eventPublisher);
|
this.methodInterceptor.setAuthorizationEventPublisher(eventPublisher);
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* 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.observation.configuration;
|
||||||
|
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import io.micrometer.observation.ObservationRegistry;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
|
|
||||||
|
abstract class AbstractObservationObjectPostProcessor<O> implements ObjectPostProcessor<O> {
|
||||||
|
|
||||||
|
private final ObjectProvider<ObservationRegistry> observationRegistry;
|
||||||
|
|
||||||
|
private final BiFunction<ObservationRegistry, O, O> wrapper;
|
||||||
|
|
||||||
|
AbstractObservationObjectPostProcessor(ObjectProvider<ObservationRegistry> observationRegistry,
|
||||||
|
Function<ObservationRegistry, O> constructor) {
|
||||||
|
this(observationRegistry, (registry, object) -> constructor.apply(registry));
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractObservationObjectPostProcessor(ObjectProvider<ObservationRegistry> observationRegistry,
|
||||||
|
BiFunction<ObservationRegistry, O, O> constructor) {
|
||||||
|
this.observationRegistry = observationRegistry;
|
||||||
|
this.wrapper = constructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <O1 extends O> O1 postProcess(O1 object) {
|
||||||
|
ObservationRegistry registry = this.observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP);
|
||||||
|
if (registry.isNoop()) {
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
return (O1) this.wrapper.apply(registry, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* 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.observation.configuration;
|
||||||
|
|
||||||
|
import io.micrometer.observation.ObservationRegistry;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
|
||||||
|
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.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.ObservationAuthenticationManager;
|
||||||
|
import org.springframework.security.authorization.AuthorizationManager;
|
||||||
|
import org.springframework.security.authorization.ObservationAuthorizationManager;
|
||||||
|
import org.springframework.security.authorization.method.MethodInvocationResult;
|
||||||
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
|
import org.springframework.security.web.FilterChainProxy;
|
||||||
|
import org.springframework.security.web.ObservationFilterChainDecorator;
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
class ObservationConfiguration {
|
||||||
|
|
||||||
|
private final ObjectProvider<ObservationRegistry> observationRegistry;
|
||||||
|
|
||||||
|
ObservationConfiguration(ObjectProvider<ObservationRegistry> observationRegistry) {
|
||||||
|
this.observationRegistry = observationRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
ObjectPostProcessor<AuthorizationManager<MethodInvocation>> methodAuthorizationManagerPostProcessor() {
|
||||||
|
return new AbstractObservationObjectPostProcessor<>(this.observationRegistry,
|
||||||
|
ObservationAuthorizationManager::new) {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
ObjectPostProcessor<AuthorizationManager<MethodInvocationResult>> methodResultAuthorizationManagerPostProcessor() {
|
||||||
|
return new AbstractObservationObjectPostProcessor<>(this.observationRegistry,
|
||||||
|
ObservationAuthorizationManager::new) {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
ObjectPostProcessor<AuthorizationManager<HttpServletRequest>> webAuthorizationManagerPostProcessor() {
|
||||||
|
return new AbstractObservationObjectPostProcessor<>(this.observationRegistry,
|
||||||
|
ObservationAuthorizationManager::new) {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
ObjectPostProcessor<AuthenticationManager> authenticationManagerPostProcessor() {
|
||||||
|
return new AbstractObservationObjectPostProcessor<>(this.observationRegistry,
|
||||||
|
ObservationAuthenticationManager::new) {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
ObjectPostProcessor<FilterChainProxy.FilterChainDecorator> filterChainDecoratorPostProcessor() {
|
||||||
|
return new AbstractObservationObjectPostProcessor<>(this.observationRegistry,
|
||||||
|
ObservationFilterChainDecorator::new) {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* 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.observation.configuration;
|
||||||
|
|
||||||
|
import io.micrometer.observation.ObservationRegistry;
|
||||||
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
|
||||||
|
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.authentication.ObservationReactiveAuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||||
|
import org.springframework.security.authorization.ObservationReactiveAuthorizationManager;
|
||||||
|
import org.springframework.security.authorization.ReactiveAuthorizationManager;
|
||||||
|
import org.springframework.security.authorization.method.MethodInvocationResult;
|
||||||
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
|
import org.springframework.security.web.server.ObservationWebFilterChainDecorator;
|
||||||
|
import org.springframework.security.web.server.WebFilterChainProxy;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
class ReactiveObservationConfiguration {
|
||||||
|
|
||||||
|
private final ObjectProvider<ObservationRegistry> observationRegistry;
|
||||||
|
|
||||||
|
ReactiveObservationConfiguration(ObjectProvider<ObservationRegistry> observationRegistry) {
|
||||||
|
this.observationRegistry = observationRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
ObjectPostProcessor<ReactiveAuthorizationManager<MethodInvocation>> methodAuthorizationManagerPostProcessor() {
|
||||||
|
return new AbstractObservationObjectPostProcessor<>(this.observationRegistry,
|
||||||
|
ObservationReactiveAuthorizationManager::new) {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
ObjectPostProcessor<ReactiveAuthorizationManager<MethodInvocationResult>> methodResultAuthorizationManagerPostProcessor() {
|
||||||
|
return new AbstractObservationObjectPostProcessor<>(this.observationRegistry,
|
||||||
|
ObservationReactiveAuthorizationManager::new) {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
ObjectPostProcessor<ReactiveAuthorizationManager<ServerWebExchange>> webAuthorizationManagerPostProcessor() {
|
||||||
|
return new AbstractObservationObjectPostProcessor<>(this.observationRegistry,
|
||||||
|
ObservationReactiveAuthorizationManager::new) {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
ObjectPostProcessor<ReactiveAuthenticationManager> authenticationManagerPostProcessor() {
|
||||||
|
return new AbstractObservationObjectPostProcessor<>(this.observationRegistry,
|
||||||
|
ObservationReactiveAuthenticationManager::new) {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
ObjectPostProcessor<WebFilterChainProxy.WebFilterChainDecorator> filterChainDecoratorPostProcessor() {
|
||||||
|
return new AbstractObservationObjectPostProcessor<>(this.observationRegistry,
|
||||||
|
ObservationWebFilterChainDecorator::new) {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* 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.observation.configuration;
|
||||||
|
|
||||||
|
import io.micrometer.observation.ObservationRegistry;
|
||||||
|
|
||||||
|
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.messaging.Message;
|
||||||
|
import org.springframework.security.authorization.AuthorizationManager;
|
||||||
|
import org.springframework.security.authorization.ObservationAuthorizationManager;
|
||||||
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
class WebSocketObservationConfiguration {
|
||||||
|
|
||||||
|
private final ObjectProvider<ObservationRegistry> observationRegistry;
|
||||||
|
|
||||||
|
WebSocketObservationConfiguration(ObjectProvider<ObservationRegistry> observationRegistry) {
|
||||||
|
this.observationRegistry = observationRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
ObjectPostProcessor<AuthorizationManager<Message<?>>> messageAuthorizationManagerPostProcessor() {
|
||||||
|
return new AbstractObservationObjectPostProcessor<>(this.observationRegistry,
|
||||||
|
ObservationAuthorizationManager::new) {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -35,7 +35,8 @@ import org.springframework.context.annotation.Import;
|
||||||
@Documented
|
@Documented
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Import({ RSocketSecurityConfiguration.class, SecuritySocketAcceptorInterceptorConfiguration.class })
|
@Import({ RSocketSecurityConfiguration.class, SecuritySocketAcceptorInterceptorConfiguration.class,
|
||||||
|
ReactiveObservationImportSelector.class })
|
||||||
public @interface EnableRSocketSecurity {
|
public @interface EnableRSocketSecurity {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,16 +16,14 @@
|
||||||
|
|
||||||
package org.springframework.security.config.annotation.rsocket;
|
package org.springframework.security.config.annotation.rsocket;
|
||||||
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
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.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.security.authentication.ObservationReactiveAuthenticationManager;
|
|
||||||
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||||
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
|
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
|
||||||
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
|
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
|
||||||
|
@ -46,7 +44,7 @@ class RSocketSecurityConfiguration {
|
||||||
|
|
||||||
private PasswordEncoder passwordEncoder;
|
private PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
private ObservationRegistry observationRegistry = ObservationRegistry.NOOP;
|
private ObjectPostProcessor<ReactiveAuthenticationManager> postProcessor = ObjectPostProcessor.identity();
|
||||||
|
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
void setAuthenticationManager(ReactiveAuthenticationManager authenticationManager) {
|
void setAuthenticationManager(ReactiveAuthenticationManager authenticationManager) {
|
||||||
|
@ -64,8 +62,8 @@ class RSocketSecurityConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
void setObservationRegistry(ObservationRegistry observationRegistry) {
|
void setAuthenticationManagerPostProcessor(ObjectPostProcessor<ReactiveAuthenticationManager> postProcessor) {
|
||||||
this.observationRegistry = observationRegistry;
|
this.postProcessor = postProcessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(name = RSOCKET_SECURITY_BEAN_NAME)
|
@Bean(name = RSOCKET_SECURITY_BEAN_NAME)
|
||||||
|
@ -86,10 +84,7 @@ class RSocketSecurityConfiguration {
|
||||||
if (this.passwordEncoder != null) {
|
if (this.passwordEncoder != null) {
|
||||||
manager.setPasswordEncoder(this.passwordEncoder);
|
manager.setPasswordEncoder(this.passwordEncoder);
|
||||||
}
|
}
|
||||||
if (!this.observationRegistry.isNoop()) {
|
return this.postProcessor.postProcess(manager);
|
||||||
return new ObservationReactiveAuthenticationManager(this.observationRegistry, manager);
|
|
||||||
}
|
|
||||||
return manager;
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2013 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.rsocket;
|
||||||
|
|
||||||
|
import io.micrometer.observation.ObservationRegistry;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.ImportSelector;
|
||||||
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
|
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by {@link EnableWebFluxSecurity} to conditionally import observation configuration
|
||||||
|
* when {@link ObservationRegistry} is present.
|
||||||
|
*
|
||||||
|
* @author Josh Cummings
|
||||||
|
* @since 6.4
|
||||||
|
*/
|
||||||
|
class ReactiveObservationImportSelector implements ImportSelector {
|
||||||
|
|
||||||
|
private static final boolean observabilityPresent;
|
||||||
|
|
||||||
|
static {
|
||||||
|
ClassLoader classLoader = ReactiveObservationImportSelector.class.getClassLoader();
|
||||||
|
observabilityPresent = ClassUtils.isPresent("io.micrometer.observation.ObservationRegistry", classLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
|
||||||
|
if (!observabilityPresent) {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
return new String[] {
|
||||||
|
"org.springframework.security.config.annotation.observation.configuration.ReactiveObservationConfiguration" };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -21,7 +21,6 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
|
||||||
import jakarta.servlet.Filter;
|
import jakarta.servlet.Filter;
|
||||||
import jakarta.servlet.FilterChain;
|
import jakarta.servlet.FilterChain;
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
|
@ -30,12 +29,13 @@ import jakarta.servlet.ServletResponse;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.core.OrderComparator;
|
import org.springframework.core.OrderComparator;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.authentication.ObservationAuthenticationManager;
|
|
||||||
import org.springframework.security.config.Customizer;
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
|
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
|
@ -3279,13 +3279,10 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||||
setSharedObject(AuthenticationManager.class, this.authenticationManager);
|
setSharedObject(AuthenticationManager.class, this.authenticationManager);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ObservationRegistry registry = getObservationRegistry();
|
ObjectPostProcessor<AuthenticationManager> postProcessor = getAuthenticationManagerPostProcessor();
|
||||||
AuthenticationManager manager = getAuthenticationRegistry().build();
|
AuthenticationManager manager = getAuthenticationRegistry().build();
|
||||||
if (!registry.isNoop() && manager != null) {
|
if (manager != null) {
|
||||||
setSharedObject(AuthenticationManager.class, new ObservationAuthenticationManager(registry, manager));
|
setSharedObject(AuthenticationManager.class, postProcessor.postProcess(manager));
|
||||||
}
|
|
||||||
else {
|
|
||||||
setSharedObject(AuthenticationManager.class, manager);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3723,8 +3720,12 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||||
return apply(configurer);
|
return apply(configurer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ObservationRegistry getObservationRegistry() {
|
private ObjectPostProcessor<AuthenticationManager> getAuthenticationManagerPostProcessor() {
|
||||||
return getContext().getBeanProvider(ObservationRegistry.class).getIfUnique(() -> ObservationRegistry.NOOP);
|
ApplicationContext context = getContext();
|
||||||
|
ResolvableType type = ResolvableType.forClassWithGenerics(ObjectPostProcessor.class,
|
||||||
|
AuthenticationManager.class);
|
||||||
|
ObjectProvider<ObjectPostProcessor<AuthenticationManager>> manager = context.getBeanProvider(type);
|
||||||
|
return manager.getIfUnique(ObjectPostProcessor::identity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -28,8 +28,10 @@ import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.security.access.PermissionEvaluator;
|
import org.springframework.security.access.PermissionEvaluator;
|
||||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||||
|
@ -45,8 +47,8 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
|
||||||
import org.springframework.security.core.context.SecurityContext;
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||||
import org.springframework.security.web.FilterChainProxy;
|
import org.springframework.security.web.FilterChainProxy;
|
||||||
|
import org.springframework.security.web.FilterChainProxy.FilterChainDecorator;
|
||||||
import org.springframework.security.web.FilterInvocation;
|
import org.springframework.security.web.FilterInvocation;
|
||||||
import org.springframework.security.web.ObservationFilterChainDecorator;
|
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator;
|
import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator;
|
||||||
import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer;
|
import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator.HttpServletRequestTransformer;
|
||||||
|
@ -110,6 +112,9 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||||
|
|
||||||
private ObservationRegistry observationRegistry = ObservationRegistry.NOOP;
|
private ObservationRegistry observationRegistry = ObservationRegistry.NOOP;
|
||||||
|
|
||||||
|
private ObjectPostProcessor<FilterChainDecorator> filterChainDecoratorPostProcessor = ObjectPostProcessor
|
||||||
|
.identity();
|
||||||
|
|
||||||
private HttpServletRequestTransformer privilegeEvaluatorRequestTransformer;
|
private HttpServletRequestTransformer privilegeEvaluatorRequestTransformer;
|
||||||
|
|
||||||
private DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
|
private DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
|
||||||
|
@ -403,6 +408,11 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||||
}
|
}
|
||||||
catch (NoSuchBeanDefinitionException ex) {
|
catch (NoSuchBeanDefinitionException ex) {
|
||||||
}
|
}
|
||||||
|
ResolvableType type = ResolvableType.forClassWithGenerics(ObjectPostProcessor.class,
|
||||||
|
FilterChainDecorator.class);
|
||||||
|
ObjectProvider<ObjectPostProcessor<FilterChainDecorator>> postProcessor = applicationContext
|
||||||
|
.getBeanProvider(type);
|
||||||
|
this.filterChainDecoratorPostProcessor = postProcessor.getIfUnique(ObjectPostProcessor::identity);
|
||||||
Class<HttpServletRequestTransformer> requestTransformerClass = HttpServletRequestTransformer.class;
|
Class<HttpServletRequestTransformer> requestTransformerClass = HttpServletRequestTransformer.class;
|
||||||
this.privilegeEvaluatorRequestTransformer = applicationContext.getBeanProvider(requestTransformerClass)
|
this.privilegeEvaluatorRequestTransformer = applicationContext.getBeanProvider(requestTransformerClass)
|
||||||
.getIfUnique();
|
.getIfUnique();
|
||||||
|
@ -413,11 +423,8 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||||
this.servletContext = servletContext;
|
this.servletContext = servletContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
FilterChainProxy.FilterChainDecorator getFilterChainDecorator() {
|
FilterChainDecorator getFilterChainDecorator() {
|
||||||
if (this.observationRegistry.isNoop()) {
|
return this.filterChainDecoratorPostProcessor.postProcess(new FilterChainProxy.VirtualFilterChainDecorator());
|
||||||
return new FilterChainProxy.VirtualFilterChainDecorator();
|
|
||||||
}
|
|
||||||
return new ObservationFilterChainDecorator(this.observationRegistry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -82,7 +82,7 @@ import org.springframework.security.web.SecurityFilterChain;
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Documented
|
@Documented
|
||||||
@Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,
|
@Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,
|
||||||
HttpSecurityConfiguration.class })
|
HttpSecurityConfiguration.class, ObservationImportSelector.class })
|
||||||
@EnableGlobalAuthentication
|
@EnableGlobalAuthentication
|
||||||
public @interface EnableWebSecurity {
|
public @interface EnableWebSecurity {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2013 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.web.configuration;
|
||||||
|
|
||||||
|
import io.micrometer.observation.ObservationRegistry;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.ImportSelector;
|
||||||
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by {@link EnableWebSecurity} to conditionally import observation configuration
|
||||||
|
* when {@link ObservationRegistry} is present.
|
||||||
|
*
|
||||||
|
* @author Josh Cummings
|
||||||
|
* @since 6.4
|
||||||
|
*/
|
||||||
|
class ObservationImportSelector implements ImportSelector {
|
||||||
|
|
||||||
|
private static final boolean observabilityPresent;
|
||||||
|
|
||||||
|
static {
|
||||||
|
ClassLoader classLoader = ObservationImportSelector.class.getClassLoader();
|
||||||
|
observabilityPresent = ClassUtils.isPresent("io.micrometer.observation.ObservationRegistry", classLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
|
||||||
|
if (!observabilityPresent) {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
return new String[] {
|
||||||
|
"org.springframework.security.config.annotation.observation.configuration.ObservationConfiguration" };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -20,10 +20,11 @@ import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
|
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
|
||||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||||
import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
|
import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
|
||||||
|
@ -32,7 +33,6 @@ import org.springframework.security.authorization.AuthorizationDecision;
|
||||||
import org.springframework.security.authorization.AuthorizationEventPublisher;
|
import org.springframework.security.authorization.AuthorizationEventPublisher;
|
||||||
import org.springframework.security.authorization.AuthorizationManager;
|
import org.springframework.security.authorization.AuthorizationManager;
|
||||||
import org.springframework.security.authorization.AuthorizationManagers;
|
import org.springframework.security.authorization.AuthorizationManagers;
|
||||||
import org.springframework.security.authorization.ObservationAuthorizationManager;
|
|
||||||
import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
|
import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
|
||||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
|
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
|
||||||
|
@ -68,6 +68,9 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||||
|
|
||||||
private String rolePrefix = "ROLE_";
|
private String rolePrefix = "ROLE_";
|
||||||
|
|
||||||
|
private ObjectPostProcessor<AuthorizationManager<HttpServletRequest>> postProcessor = ObjectPostProcessor
|
||||||
|
.identity();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance.
|
* Creates an instance.
|
||||||
* @param context the {@link ApplicationContext} to use
|
* @param context the {@link ApplicationContext} to use
|
||||||
|
@ -87,6 +90,11 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||||
GrantedAuthorityDefaults grantedAuthorityDefaults = context.getBean(GrantedAuthorityDefaults.class);
|
GrantedAuthorityDefaults grantedAuthorityDefaults = context.getBean(GrantedAuthorityDefaults.class);
|
||||||
this.rolePrefix = grantedAuthorityDefaults.getRolePrefix();
|
this.rolePrefix = grantedAuthorityDefaults.getRolePrefix();
|
||||||
}
|
}
|
||||||
|
ResolvableType type = ResolvableType.forClassWithGenerics(ObjectPostProcessor.class,
|
||||||
|
ResolvableType.forClassWithGenerics(AuthorizationManager.class, HttpServletRequest.class));
|
||||||
|
ObjectProvider<ObjectPostProcessor<AuthorizationManager<HttpServletRequest>>> provider = context
|
||||||
|
.getBeanProvider(type);
|
||||||
|
provider.ifUnique((postProcessor) -> this.postProcessor = postProcessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -123,17 +131,6 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||||
return this.registry;
|
return this.registry;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ObservationRegistry getObservationRegistry() {
|
|
||||||
ApplicationContext context = getBuilder().getSharedObject(ApplicationContext.class);
|
|
||||||
String[] names = context.getBeanNamesForType(ObservationRegistry.class);
|
|
||||||
if (names.length == 1) {
|
|
||||||
return context.getBean(ObservationRegistry.class);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return ObservationRegistry.NOOP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registry for mapping a {@link RequestMatcher} to an {@link AuthorizationManager}.
|
* Registry for mapping a {@link RequestMatcher} to an {@link AuthorizationManager}.
|
||||||
*
|
*
|
||||||
|
@ -173,12 +170,8 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||||
+ ". Try completing it with something like requestUrls().<something>.hasRole('USER')");
|
+ ". Try completing it with something like requestUrls().<something>.hasRole('USER')");
|
||||||
Assert.state(this.mappingCount > 0,
|
Assert.state(this.mappingCount > 0,
|
||||||
"At least one mapping is required (for example, authorizeHttpRequests().anyRequest().authenticated())");
|
"At least one mapping is required (for example, authorizeHttpRequests().anyRequest().authenticated())");
|
||||||
ObservationRegistry registry = getObservationRegistry();
|
|
||||||
RequestMatcherDelegatingAuthorizationManager manager = postProcess(this.managerBuilder.build());
|
RequestMatcherDelegatingAuthorizationManager manager = postProcess(this.managerBuilder.build());
|
||||||
if (registry.isNoop()) {
|
return AuthorizeHttpRequestsConfigurer.this.postProcessor.postProcess(manager);
|
||||||
return manager;
|
|
||||||
}
|
|
||||||
return new ObservationAuthorizationManager<>(registry, manager);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -86,7 +86,7 @@ import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Documented
|
@Documented
|
||||||
@Import({ ServerHttpSecurityConfiguration.class, WebFluxSecurityConfiguration.class,
|
@Import({ ServerHttpSecurityConfiguration.class, WebFluxSecurityConfiguration.class,
|
||||||
ReactiveOAuth2ClientImportSelector.class })
|
ReactiveOAuth2ClientImportSelector.class, ReactiveObservationImportSelector.class })
|
||||||
public @interface EnableWebFluxSecurity {
|
public @interface EnableWebFluxSecurity {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2013 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.web.reactive;
|
||||||
|
|
||||||
|
import io.micrometer.observation.ObservationRegistry;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.ImportSelector;
|
||||||
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by {@link EnableWebFluxSecurity} to conditionally import observation configuration
|
||||||
|
* when {@link ObservationRegistry} is present.
|
||||||
|
*
|
||||||
|
* @author Josh Cummings
|
||||||
|
* @since 6.4
|
||||||
|
*/
|
||||||
|
class ReactiveObservationImportSelector implements ImportSelector {
|
||||||
|
|
||||||
|
private static final boolean observabilityPresent;
|
||||||
|
|
||||||
|
static {
|
||||||
|
ClassLoader classLoader = ReactiveObservationImportSelector.class.getClassLoader();
|
||||||
|
observabilityPresent = ClassUtils.isPresent("io.micrometer.observation.ObservationRegistry", classLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
|
||||||
|
if (!observabilityPresent) {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
return new String[] {
|
||||||
|
"org.springframework.security.config.annotation.observation.configuration.ReactiveObservationConfiguration" };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.security.config.annotation.web.reactive;
|
package org.springframework.security.config.annotation.web.reactive;
|
||||||
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
@ -29,10 +27,10 @@ import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.context.expression.BeanFactoryResolver;
|
import org.springframework.context.expression.BeanFactoryResolver;
|
||||||
import org.springframework.core.ReactiveAdapterRegistry;
|
import org.springframework.core.ReactiveAdapterRegistry;
|
||||||
import org.springframework.security.authentication.ObservationReactiveAuthenticationManager;
|
|
||||||
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||||
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
|
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
|
||||||
import org.springframework.security.authentication.password.ReactiveCompromisedPasswordChecker;
|
import org.springframework.security.authentication.password.ReactiveCompromisedPasswordChecker;
|
||||||
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||||
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
|
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
|
||||||
import org.springframework.security.core.userdetails.ReactiveUserDetailsPasswordService;
|
import org.springframework.security.core.userdetails.ReactiveUserDetailsPasswordService;
|
||||||
|
@ -67,7 +65,7 @@ class ServerHttpSecurityConfiguration {
|
||||||
|
|
||||||
private ReactiveCompromisedPasswordChecker compromisedPasswordChecker;
|
private ReactiveCompromisedPasswordChecker compromisedPasswordChecker;
|
||||||
|
|
||||||
private ObservationRegistry observationRegistry = ObservationRegistry.NOOP;
|
private ObjectPostProcessor<ReactiveAuthenticationManager> postProcessor = ObjectPostProcessor.identity();
|
||||||
|
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
private BeanFactory beanFactory;
|
private BeanFactory beanFactory;
|
||||||
|
@ -98,8 +96,8 @@ class ServerHttpSecurityConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
void setObservationRegistry(ObservationRegistry observationRegistry) {
|
void setAuthenticationManagerPostProcessor(ObjectPostProcessor<ReactiveAuthenticationManager> postProcessor) {
|
||||||
this.observationRegistry = observationRegistry;
|
this.postProcessor = postProcessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
|
@ -169,10 +167,7 @@ class ServerHttpSecurityConfiguration {
|
||||||
}
|
}
|
||||||
manager.setUserDetailsPasswordService(this.userDetailsPasswordService);
|
manager.setUserDetailsPasswordService(this.userDetailsPasswordService);
|
||||||
manager.setCompromisedPasswordChecker(this.compromisedPasswordChecker);
|
manager.setCompromisedPasswordChecker(this.compromisedPasswordChecker);
|
||||||
if (!this.observationRegistry.isNoop()) {
|
return this.postProcessor.postProcess(manager);
|
||||||
return new ObservationReactiveAuthenticationManager(this.observationRegistry, manager);
|
|
||||||
}
|
|
||||||
return manager;
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,20 +19,20 @@ package org.springframework.security.config.annotation.web.reactive;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
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.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
import org.springframework.security.config.crypto.RsaKeyConversionServicePostProcessor;
|
import org.springframework.security.config.crypto.RsaKeyConversionServicePostProcessor;
|
||||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||||
import org.springframework.security.web.reactive.result.view.CsrfRequestDataValueProcessor;
|
import org.springframework.security.web.reactive.result.view.CsrfRequestDataValueProcessor;
|
||||||
import org.springframework.security.web.server.ObservationWebFilterChainDecorator;
|
|
||||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||||
import org.springframework.security.web.server.WebFilterChainProxy;
|
import org.springframework.security.web.server.WebFilterChainProxy;
|
||||||
|
import org.springframework.security.web.server.WebFilterChainProxy.DefaultWebFilterChainDecorator;
|
||||||
|
import org.springframework.security.web.server.WebFilterChainProxy.WebFilterChainDecorator;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.web.reactive.result.view.AbstractView;
|
import org.springframework.web.reactive.result.view.AbstractView;
|
||||||
|
@ -57,7 +57,7 @@ class WebFluxSecurityConfiguration {
|
||||||
|
|
||||||
private List<SecurityWebFilterChain> securityWebFilterChains;
|
private List<SecurityWebFilterChain> securityWebFilterChains;
|
||||||
|
|
||||||
private ObservationRegistry observationRegistry = ObservationRegistry.NOOP;
|
private ObjectPostProcessor<WebFilterChainDecorator> postProcessor = ObjectPostProcessor.identity();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
isOAuth2Present = ClassUtils.isPresent(REACTIVE_CLIENT_REGISTRATION_REPOSITORY_CLASSNAME,
|
isOAuth2Present = ClassUtils.isPresent(REACTIVE_CLIENT_REGISTRATION_REPOSITORY_CLASSNAME,
|
||||||
|
@ -73,17 +73,16 @@ class WebFluxSecurityConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
void setObservationRegistry(ObservationRegistry observationRegistry) {
|
void setFilterChainPostProcessor(ObjectPostProcessor<WebFilterChainDecorator> postProcessor) {
|
||||||
this.observationRegistry = observationRegistry;
|
this.postProcessor = postProcessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(SPRING_SECURITY_WEBFILTERCHAINFILTER_BEAN_NAME)
|
@Bean(SPRING_SECURITY_WEBFILTERCHAINFILTER_BEAN_NAME)
|
||||||
@Order(WEB_FILTER_CHAIN_FILTER_ORDER)
|
@Order(WEB_FILTER_CHAIN_FILTER_ORDER)
|
||||||
WebFilterChainProxy springSecurityWebFilterChainFilter() {
|
WebFilterChainProxy springSecurityWebFilterChainFilter() {
|
||||||
WebFilterChainProxy proxy = new WebFilterChainProxy(getSecurityWebFilterChains());
|
WebFilterChainProxy proxy = new WebFilterChainProxy(getSecurityWebFilterChains());
|
||||||
if (!this.observationRegistry.isNoop()) {
|
WebFilterChainDecorator decorator = this.postProcessor.postProcess(new DefaultWebFilterChainDecorator());
|
||||||
proxy.setFilterChainDecorator(new ObservationWebFilterChainDecorator(this.observationRegistry));
|
proxy.setFilterChainDecorator(decorator);
|
||||||
}
|
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ import org.springframework.context.annotation.Import;
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Documented
|
@Documented
|
||||||
@Import(WebSocketMessageBrokerSecurityConfiguration.class)
|
@Import({ WebSocketMessageBrokerSecurityConfiguration.class, WebSocketObservationImportSelector.class })
|
||||||
public @interface EnableWebSocketSecurity {
|
public @interface EnableWebSocketSecurity {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,6 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
@ -33,8 +31,8 @@ import org.springframework.messaging.handler.invocation.HandlerMethodArgumentRes
|
||||||
import org.springframework.messaging.simp.config.ChannelRegistration;
|
import org.springframework.messaging.simp.config.ChannelRegistration;
|
||||||
import org.springframework.messaging.support.ChannelInterceptor;
|
import org.springframework.messaging.support.ChannelInterceptor;
|
||||||
import org.springframework.security.authorization.AuthorizationManager;
|
import org.springframework.security.authorization.AuthorizationManager;
|
||||||
import org.springframework.security.authorization.ObservationAuthorizationManager;
|
|
||||||
import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
|
import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
|
||||||
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
|
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
|
@ -79,7 +77,7 @@ final class WebSocketMessageBrokerSecurityConfiguration
|
||||||
|
|
||||||
private AuthorizationManager<Message<?>> authorizationManager = ANY_MESSAGE_AUTHENTICATED;
|
private AuthorizationManager<Message<?>> authorizationManager = ANY_MESSAGE_AUTHENTICATED;
|
||||||
|
|
||||||
private ObservationRegistry observationRegistry = ObservationRegistry.NOOP;
|
private ObjectPostProcessor<AuthorizationManager<Message<?>>> postProcessor = ObjectPostProcessor.identity();
|
||||||
|
|
||||||
private ApplicationContext context;
|
private ApplicationContext context;
|
||||||
|
|
||||||
|
@ -106,9 +104,7 @@ final class WebSocketMessageBrokerSecurityConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthorizationManager<Message<?>> manager = this.authorizationManager;
|
AuthorizationManager<Message<?>> manager = this.authorizationManager;
|
||||||
if (!this.observationRegistry.isNoop()) {
|
manager = this.postProcessor.postProcess(manager);
|
||||||
manager = new ObservationAuthorizationManager<>(this.observationRegistry, manager);
|
|
||||||
}
|
|
||||||
AuthorizationChannelInterceptor interceptor = new AuthorizationChannelInterceptor(manager);
|
AuthorizationChannelInterceptor interceptor = new AuthorizationChannelInterceptor(manager);
|
||||||
interceptor.setAuthorizationEventPublisher(new SpringAuthorizationEventPublisher(this.context));
|
interceptor.setAuthorizationEventPublisher(new SpringAuthorizationEventPublisher(this.context));
|
||||||
interceptor.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
|
interceptor.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
|
||||||
|
@ -128,8 +124,9 @@ final class WebSocketMessageBrokerSecurityConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
void setObservationRegistry(ObservationRegistry observationRegistry) {
|
void setMessageAuthorizationManagerPostProcessor(
|
||||||
this.observationRegistry = observationRegistry;
|
ObjectPostProcessor<AuthorizationManager<Message<?>>> postProcessor) {
|
||||||
|
this.postProcessor = postProcessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2013 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.web.socket;
|
||||||
|
|
||||||
|
import io.micrometer.observation.ObservationRegistry;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.ImportSelector;
|
||||||
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by {@link EnableWebSocketSecurity} to conditionally import observation
|
||||||
|
* configuration when {@link ObservationRegistry} is present.
|
||||||
|
*
|
||||||
|
* @author Josh Cummings
|
||||||
|
* @since 6.4
|
||||||
|
*/
|
||||||
|
class WebSocketObservationImportSelector implements ImportSelector {
|
||||||
|
|
||||||
|
private static final boolean observabilityPresent;
|
||||||
|
|
||||||
|
static {
|
||||||
|
ClassLoader classLoader = WebSocketObservationImportSelector.class.getClassLoader();
|
||||||
|
observabilityPresent = ClassUtils.isPresent("io.micrometer.observation.ObservationRegistry", classLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
|
||||||
|
if (!observabilityPresent) {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
return new String[] {
|
||||||
|
"org.springframework.security.config.annotation.observation.configuration.WebSocketObservationConfiguration" };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -33,13 +34,13 @@ import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.util.context.Context;
|
import reactor.util.context.Context;
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
|
@ -55,9 +56,9 @@ import org.springframework.security.authentication.ReactiveAuthenticationManager
|
||||||
import org.springframework.security.authorization.AuthenticatedReactiveAuthorizationManager;
|
import org.springframework.security.authorization.AuthenticatedReactiveAuthorizationManager;
|
||||||
import org.springframework.security.authorization.AuthorityReactiveAuthorizationManager;
|
import org.springframework.security.authorization.AuthorityReactiveAuthorizationManager;
|
||||||
import org.springframework.security.authorization.AuthorizationDecision;
|
import org.springframework.security.authorization.AuthorizationDecision;
|
||||||
import org.springframework.security.authorization.ObservationReactiveAuthorizationManager;
|
|
||||||
import org.springframework.security.authorization.ReactiveAuthorizationManager;
|
import org.springframework.security.authorization.ReactiveAuthorizationManager;
|
||||||
import org.springframework.security.config.Customizer;
|
import org.springframework.security.config.Customizer;
|
||||||
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
|
@ -1740,6 +1741,18 @@ public class ServerHttpSecurity {
|
||||||
return this.context.getBeanProvider(beanClass).getIfUnique(() -> defaultInstance);
|
return this.context.getBeanProvider(beanClass).getIfUnique(() -> defaultInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private <T> ObjectProvider<T> getBeanProvider(ResolvableType type) {
|
||||||
|
if (this.context == null) {
|
||||||
|
return new ObjectProvider<>() {
|
||||||
|
@Override
|
||||||
|
public Iterator<T> iterator() {
|
||||||
|
return Collections.emptyIterator();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return this.context.getBeanProvider(type);
|
||||||
|
}
|
||||||
|
|
||||||
private <T> T getBeanOrNull(Class<T> beanClass) {
|
private <T> T getBeanOrNull(Class<T> beanClass) {
|
||||||
return getBeanOrNull(ResolvableType.forClass(beanClass));
|
return getBeanOrNull(ResolvableType.forClass(beanClass));
|
||||||
}
|
}
|
||||||
|
@ -1795,6 +1808,17 @@ public class ServerHttpSecurity {
|
||||||
|
|
||||||
private PathPatternParser pathPatternParser;
|
private PathPatternParser pathPatternParser;
|
||||||
|
|
||||||
|
private ObjectPostProcessor<ReactiveAuthorizationManager<ServerWebExchange>> postProcessor = ObjectPostProcessor
|
||||||
|
.identity();
|
||||||
|
|
||||||
|
public AuthorizeExchangeSpec() {
|
||||||
|
ResolvableType type = ResolvableType.forClassWithGenerics(ObjectPostProcessor.class,
|
||||||
|
ResolvableType.forClassWithGenerics(ReactiveAuthorizationManager.class, ServerWebExchange.class));
|
||||||
|
ObjectProvider<ObjectPostProcessor<ReactiveAuthorizationManager<ServerWebExchange>>> postProcessor = getBeanProvider(
|
||||||
|
type);
|
||||||
|
postProcessor.ifUnique((p) -> this.postProcessor = p);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows method chaining to continue configuring the {@link ServerHttpSecurity}
|
* Allows method chaining to continue configuring the {@link ServerHttpSecurity}
|
||||||
* @return the {@link ServerHttpSecurity} to continue configuring
|
* @return the {@link ServerHttpSecurity} to continue configuring
|
||||||
|
@ -1847,10 +1871,7 @@ public class ServerHttpSecurity {
|
||||||
Assert.state(this.matcher == null,
|
Assert.state(this.matcher == null,
|
||||||
() -> "The matcher " + this.matcher + " does not have an access rule defined");
|
() -> "The matcher " + this.matcher + " does not have an access rule defined");
|
||||||
ReactiveAuthorizationManager<ServerWebExchange> manager = this.managerBldr.build();
|
ReactiveAuthorizationManager<ServerWebExchange> manager = this.managerBldr.build();
|
||||||
ObservationRegistry registry = getBeanOrDefault(ObservationRegistry.class, ObservationRegistry.NOOP);
|
manager = this.postProcessor.postProcess(manager);
|
||||||
if (!registry.isNoop()) {
|
|
||||||
manager = new ObservationReactiveAuthorizationManager<>(registry, manager);
|
|
||||||
}
|
|
||||||
AuthorizationWebFilter result = new AuthorizationWebFilter(manager);
|
AuthorizationWebFilter result = new AuthorizationWebFilter(manager);
|
||||||
http.addFilterAt(result, SecurityWebFiltersOrder.AUTHORIZATION);
|
http.addFilterAt(result, SecurityWebFiltersOrder.AUTHORIZATION);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue