Expected Behavior
The method with the name defaultExpressionHandler of class PrePostMethodSecurityConfiguration should initialize the following dependencies of MethodSecurityExpressionHandler
PermissionEvaluator, RoleHierarchy, AuthenticationTrustResolver, GrantedAuthorityDefaults
Current Behavior
The method with the name defaultExpressionHandler of class PrePostMethodSecurityConfiguration initialized only GrantedAuthorityDefaults
Context
My customized RoleHierarchy is not working When I migrate the @EnableGlobalMethodSecurity to @EnableMethodSecurity.
After looking at the source code of the implementation class GlobalMethodSecurityConfiguration associated with @EnableGlobalMethodSecurity, I found it will initialize the dependencies of defaultMethodExpressionHandler as much as possible.
But @EnableMethodSecurity's associated implementation class PrePostMethodSecurityConfiguration is not like this.
I think the behavior should be as consistent as possible so there are no issues when migrating.
Comment From: orange-guo
PrePostMethodSecurityConfiguration.java
private static MethodSecurityExpressionHandler defaultExpressionHandler(
ObjectProvider<GrantedAuthorityDefaults> defaultsProvider, ApplicationContext context) {
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
defaultsProvider.ifAvailable((d) -> handler.setDefaultRolePrefix(d.getRolePrefix()));
handler.setApplicationContext(context);
return handler;
}
GlobalMethodSecurityConfiguration.java
@Override
public void afterSingletonsInstantiated() {
try {
initializeMethodSecurityInterceptor();
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
PermissionEvaluator permissionEvaluator = getSingleBeanOrNull(PermissionEvaluator.class);
if (permissionEvaluator != null) {
this.defaultMethodExpressionHandler.setPermissionEvaluator(permissionEvaluator);
}
RoleHierarchy roleHierarchy = getSingleBeanOrNull(RoleHierarchy.class);
if (roleHierarchy != null) {
this.defaultMethodExpressionHandler.setRoleHierarchy(roleHierarchy);
}
AuthenticationTrustResolver trustResolver = getSingleBeanOrNull(AuthenticationTrustResolver.class);
if (trustResolver != null) {
this.defaultMethodExpressionHandler.setTrustResolver(trustResolver);
}
GrantedAuthorityDefaults grantedAuthorityDefaults = getSingleBeanOrNull(GrantedAuthorityDefaults.class);
if (grantedAuthorityDefaults != null) {
this.defaultMethodExpressionHandler.setDefaultRolePrefix(grantedAuthorityDefaults.getRolePrefix());
}
this.defaultMethodExpressionHandler = this.objectPostProcessor.postProcess(this.defaultMethodExpressionHandler);
}
Comment From: jzheaux
Hi, @orange-guo, thanks for the detailed report and PR. Please see https://docs.spring.io/spring-security/reference/5.8/migration/servlet/authorization.html#servlet-replace-permissionevaluator-bean-with-methodsecurityexpression-handler which explains that it is intended to keep the API simple for the time being. If you have a role hierarchy, please specify it and publish a MethodSecurityExpressionHandler @Bean like so:
@Bean
static MethodSecurityExpressionHandler expressionHandler() {
var expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setRoleHierarhcy(myRoleHierarchy);
return expressionHandler;
}