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;
}