diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfiguration.java index c3bb88c8f4c..be9dcfbb433 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfiguration.java @@ -16,8 +16,11 @@ package org.springframework.security.config.annotation.method.configuration; +import java.util.function.Supplier; + import io.micrometer.observation.ObservationRegistry; import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.config.BeanDefinition; @@ -25,6 +28,9 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Role; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler; import org.springframework.security.authorization.AuthorizationEventPublisher; @@ -36,7 +42,9 @@ import org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager; import org.springframework.security.authorization.method.PreFilterAuthorizationMethodInterceptor; import org.springframework.security.config.core.GrantedAuthorityDefaults; +import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolderStrategy; +import org.springframework.util.function.SingletonSupplier; /** * Base {@link Configuration} for enabling Spring Security Method Security. @@ -59,7 +67,7 @@ static MethodInterceptor preFilterAuthorizationMethodInterceptor( PreFilterAuthorizationMethodInterceptor preFilter = new PreFilterAuthorizationMethodInterceptor(); strategyProvider.ifAvailable(preFilter::setSecurityContextHolderStrategy); preFilter.setExpressionHandler( - expressionHandlerProvider.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, context))); + new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider, defaultsProvider, context)); return preFilter; } @@ -73,7 +81,7 @@ static MethodInterceptor preAuthorizeAuthorizationMethodInterceptor( ObjectProvider registryProvider, ApplicationContext context) { PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager(); manager.setExpressionHandler( - expressionHandlerProvider.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, context))); + new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider, defaultsProvider, context)); AuthorizationManagerBeforeMethodInterceptor preAuthorize = AuthorizationManagerBeforeMethodInterceptor .preAuthorize(manager(manager, registryProvider)); strategyProvider.ifAvailable(preAuthorize::setSecurityContextHolderStrategy); @@ -91,7 +99,7 @@ static MethodInterceptor postAuthorizeAuthorizationMethodInterceptor( ObjectProvider registryProvider, ApplicationContext context) { PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager(); manager.setExpressionHandler( - expressionHandlerProvider.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, context))); + new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider, defaultsProvider, context)); AuthorizationManagerAfterMethodInterceptor postAuthorize = AuthorizationManagerAfterMethodInterceptor .postAuthorize(manager(manager, registryProvider)); strategyProvider.ifAvailable(postAuthorize::setSecurityContextHolderStrategy); @@ -108,7 +116,7 @@ static MethodInterceptor postFilterAuthorizationMethodInterceptor( PostFilterAuthorizationMethodInterceptor postFilter = new PostFilterAuthorizationMethodInterceptor(); strategyProvider.ifAvailable(postFilter::setSecurityContextHolderStrategy); postFilter.setExpressionHandler( - expressionHandlerProvider.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, context))); + new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider, defaultsProvider, context)); return postFilter; } @@ -125,4 +133,43 @@ static AuthorizationManager manager(AuthorizationManager delegate, return new DeferringObservationAuthorizationManager<>(registryProvider, delegate); } + private static final class DeferringMethodSecurityExpressionHandler implements MethodSecurityExpressionHandler { + + private final Supplier expressionHandler; + + private DeferringMethodSecurityExpressionHandler( + ObjectProvider expressionHandlerProvider, + ObjectProvider defaultsProvider, ApplicationContext applicationContext) { + this.expressionHandler = SingletonSupplier.of(() -> expressionHandlerProvider + .getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, applicationContext))); + } + + @Override + public ExpressionParser getExpressionParser() { + return this.expressionHandler.get().getExpressionParser(); + } + + @Override + public EvaluationContext createEvaluationContext(Authentication authentication, MethodInvocation invocation) { + return this.expressionHandler.get().createEvaluationContext(authentication, invocation); + } + + @Override + public EvaluationContext createEvaluationContext(Supplier authentication, + MethodInvocation invocation) { + return this.expressionHandler.get().createEvaluationContext(authentication, invocation); + } + + @Override + public Object filter(Object filterTarget, Expression filterExpression, EvaluationContext ctx) { + return this.expressionHandler.get().filter(filterTarget, filterExpression, ctx); + } + + @Override + public void setReturnObject(Object returnObject, EvaluationContext ctx) { + this.expressionHandler.get().setReturnObject(returnObject, ctx); + } + + } + }