Skip to content

Commit aeafcc1

Browse files
Defer MethodSecurityExpressionHandler Resolution
When using Spring Security ACL and compiling to Native, in order to create the '*AuthorizationMethodInterceptor' Proxy beans during build time, Spring tries to resolve the DataSource bean since the DataSource can be a dependency of some AclService implementations, and fails because some required data source properties are not available during build time. This commit defers the initialization of the MethodSecurityExpressionHandler to the runtime. Closes gh-12653
1 parent 48babb7 commit aeafcc1

File tree

1 file changed

+51
-4
lines changed

1 file changed

+51
-4
lines changed

config/src/main/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfiguration.java

+51-4
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,21 @@
1616

1717
package org.springframework.security.config.annotation.method.configuration;
1818

19+
import java.util.function.Supplier;
20+
1921
import io.micrometer.observation.ObservationRegistry;
2022
import org.aopalliance.intercept.MethodInterceptor;
23+
import org.aopalliance.intercept.MethodInvocation;
2124

2225
import org.springframework.beans.factory.ObjectProvider;
2326
import org.springframework.beans.factory.config.BeanDefinition;
2427
import org.springframework.context.ApplicationContext;
2528
import org.springframework.context.annotation.Bean;
2629
import org.springframework.context.annotation.Configuration;
2730
import org.springframework.context.annotation.Role;
31+
import org.springframework.expression.EvaluationContext;
32+
import org.springframework.expression.Expression;
33+
import org.springframework.expression.ExpressionParser;
2834
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
2935
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
3036
import org.springframework.security.authorization.AuthorizationEventPublisher;
@@ -36,7 +42,9 @@
3642
import org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager;
3743
import org.springframework.security.authorization.method.PreFilterAuthorizationMethodInterceptor;
3844
import org.springframework.security.config.core.GrantedAuthorityDefaults;
45+
import org.springframework.security.core.Authentication;
3946
import org.springframework.security.core.context.SecurityContextHolderStrategy;
47+
import org.springframework.util.function.SingletonSupplier;
4048

4149
/**
4250
* Base {@link Configuration} for enabling Spring Security Method Security.
@@ -59,7 +67,7 @@ static MethodInterceptor preFilterAuthorizationMethodInterceptor(
5967
PreFilterAuthorizationMethodInterceptor preFilter = new PreFilterAuthorizationMethodInterceptor();
6068
strategyProvider.ifAvailable(preFilter::setSecurityContextHolderStrategy);
6169
preFilter.setExpressionHandler(
62-
expressionHandlerProvider.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, context)));
70+
new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider, defaultsProvider, context));
6371
return preFilter;
6472
}
6573

@@ -73,7 +81,7 @@ static MethodInterceptor preAuthorizeAuthorizationMethodInterceptor(
7381
ObjectProvider<ObservationRegistry> registryProvider, ApplicationContext context) {
7482
PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
7583
manager.setExpressionHandler(
76-
expressionHandlerProvider.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, context)));
84+
new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider, defaultsProvider, context));
7785
AuthorizationManagerBeforeMethodInterceptor preAuthorize = AuthorizationManagerBeforeMethodInterceptor
7886
.preAuthorize(manager(manager, registryProvider));
7987
strategyProvider.ifAvailable(preAuthorize::setSecurityContextHolderStrategy);
@@ -91,7 +99,7 @@ static MethodInterceptor postAuthorizeAuthorizationMethodInterceptor(
9199
ObjectProvider<ObservationRegistry> registryProvider, ApplicationContext context) {
92100
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
93101
manager.setExpressionHandler(
94-
expressionHandlerProvider.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, context)));
102+
new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider, defaultsProvider, context));
95103
AuthorizationManagerAfterMethodInterceptor postAuthorize = AuthorizationManagerAfterMethodInterceptor
96104
.postAuthorize(manager(manager, registryProvider));
97105
strategyProvider.ifAvailable(postAuthorize::setSecurityContextHolderStrategy);
@@ -108,7 +116,7 @@ static MethodInterceptor postFilterAuthorizationMethodInterceptor(
108116
PostFilterAuthorizationMethodInterceptor postFilter = new PostFilterAuthorizationMethodInterceptor();
109117
strategyProvider.ifAvailable(postFilter::setSecurityContextHolderStrategy);
110118
postFilter.setExpressionHandler(
111-
expressionHandlerProvider.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, context)));
119+
new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider, defaultsProvider, context));
112120
return postFilter;
113121
}
114122

@@ -125,4 +133,43 @@ static <T> AuthorizationManager<T> manager(AuthorizationManager<T> delegate,
125133
return new DeferringObservationAuthorizationManager<>(registryProvider, delegate);
126134
}
127135

136+
private static final class DeferringMethodSecurityExpressionHandler implements MethodSecurityExpressionHandler {
137+
138+
private final Supplier<MethodSecurityExpressionHandler> expressionHandler;
139+
140+
private DeferringMethodSecurityExpressionHandler(
141+
ObjectProvider<MethodSecurityExpressionHandler> expressionHandlerProvider,
142+
ObjectProvider<GrantedAuthorityDefaults> defaultsProvider, ApplicationContext applicationContext) {
143+
this.expressionHandler = SingletonSupplier.of(() -> expressionHandlerProvider
144+
.getIfAvailable(() -> defaultExpressionHandler(defaultsProvider, applicationContext)));
145+
}
146+
147+
@Override
148+
public ExpressionParser getExpressionParser() {
149+
return this.expressionHandler.get().getExpressionParser();
150+
}
151+
152+
@Override
153+
public EvaluationContext createEvaluationContext(Authentication authentication, MethodInvocation invocation) {
154+
return this.expressionHandler.get().createEvaluationContext(authentication, invocation);
155+
}
156+
157+
@Override
158+
public EvaluationContext createEvaluationContext(Supplier<Authentication> authentication,
159+
MethodInvocation invocation) {
160+
return this.expressionHandler.get().createEvaluationContext(authentication, invocation);
161+
}
162+
163+
@Override
164+
public Object filter(Object filterTarget, Expression filterExpression, EvaluationContext ctx) {
165+
return this.expressionHandler.get().filter(filterTarget, filterExpression, ctx);
166+
}
167+
168+
@Override
169+
public void setReturnObject(Object returnObject, EvaluationContext ctx) {
170+
this.expressionHandler.get().setReturnObject(returnObject, ctx);
171+
}
172+
173+
}
174+
128175
}

0 commit comments

Comments
 (0)