Describe the bug

When using RoleHierarchy to inherit multiple roles, AuthorizationManagers.allOf() does not take inherited roles into account when making the decision.

To Reproduce

ROLE_ROOT can't access /test/**.

AuthorityAuthorizationManager.hasRole doesn't apply withRoleHierarchy.

Expected behavior

ROLE_ROOT can access /test/**.

Sample

@Bean
static RoleHierarchy roleHierarchy() {
    RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();
    hierarchy.setHierarchy("ROLE_ROOT > ROLE_ADMIN\n" +
            "ROLE_ADMIN > ROLE_USER");
    return hierarchy;
}

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests((authorize) -> authorize
               .requestMatchers("/test/**").access(
                        AuthorizationManagers.allOf(
                                AuthorityAuthorizationManager.hasRole("ADMIN"),
                                AuthorityAuthorizationManager.hasRole("USER")
                        )
                ) 
                .anyRequest().authenticated()
            );
    return http.build();
}

Comment From: marcusdacoregio

Hi, @gotounix. I do not think that AuthorizationManagers should be aware of the RoleHierarchy since it does not support only AuthorityAuthorizationManager. Each individual AuthorityAuthorizationManager should be made aware of the role hierarchy. For example, you can do:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http, RoleHierarchy roleHierearchy) throws Exception {
    AuthorityAuthorizationManager<RequestAuthorizationContext> isAdmin = AuthorityAuthorizationManager.hasRole("ADMIN");
    AuthorityAuthorizationManager<RequestAuthorizationContext> isUser = AuthorityAuthorizationManager.hasRole("USER");
    isAdmin.setRoleHierarchy(roleHierarchy);
    isUser.setRoleHierarchy(roleHierarchy);
    http.authorizeHttpRequests((authorize) -> authorize
               .requestMatchers("/test/**").access(
                        AuthorizationManagers.allOf(isAdmin, isUser)
                ) 
                .anyRequest().authenticated()
            );
    return http.build();
}

You can also create a bean that does that work for you. It might not look ideal and we are open to suggestions on improving this.

Comment From: spring-projects-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.