Expected Behavior

HttpSecurity's authorizeHttpRequests() uses role hierarchy defined as a bean or defined as a separate method like setRoleHierarchy(RoleHierarchy rh) {...}

so the flow will be like

@Bean
public SecurityFilterChain filterChain(@NotNull HttpSecurity http) {
...
http.authorizeHttpRequests()
  .setRoleHierarchy(getRoleHierarchy())
  .requestMatchers("my.site/admin")
  .hasRole("ADMIN")
...
}

Current Behavior

HttpSecurity's authorizeHttpRequests() uses role hierarchy by .access() method using redefined AuthorityAuthorizationManager<RequestAuthorizationContext>. it is quite inconvenient and quite a lot of code.

so i need to do

@Bean
public AuthorityAuthorizationManager<RequestAuthorizationContext> adminAuthorityAuthorizationManager() {
  AuthorityAuthorizationManager<RequestAuthorizationContext> objectAuthorityAuthorizationManager = AuthorityAuthorizationManager.hasAuthority("ROLE_ADMIN");
  objectAuthorityAuthorizationManager.setRoleHierarchy(getRoleHierarchy());
  return objectAuthorityAuthorizationManager;
}

and then use this

http.authorizeHttpRequests()
  .requestMatchers("my.site/admin")
  .access(adminAuthorityAuthorizationManager())

Context

i found that AuthorityAuthorizationManager has a non-static RoleHierarchy field. well, i propose: 1) make a private static RoleHierarchy field in AuthorizeHttpRequestsConfigurer.AuthorizedUrl defaulted to NullRoleHierarchy 2) set it by a static method setRoleHierarchy() 3) pass it to hasRole... methods under-the-hood 4) pass it to hasRole... methods of AuthorityAuthorizationManager in 3) 5) set it to inner field roleHierarchy (!) 6) continue as it is now

so, we will have an easy setter for roleHierarchy without clumsy use of redefined classes for each custom role

Comment From: evgeniycheban

Hi, @esselesse, I think what you are looking for is already implemented, the RoleHierarchy can be defined as a @Bean and propagated to AuthorityAuthorizationManager, here is an example of how it can be achieved:

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    return http
        .authorizeHttpRequests((requests) -> requests
        .anyRequest().hasRole("USER")
        )
        .build();
}

@Bean
RoleHierarchy roleHierarchy() {
    RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
    roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");
    return roleHierarchy;
}

This was added in https://github.com/spring-projects/spring-security/issues/12473, so you may need to consider updating Spring Security version in your project.

@jzheaux Could you please remind in which release it was included?

Comment From: esselesse

@evgeniycheban if i use these plugins in build.gradle:

id 'org.springframework.boot' version '3.0.6'
id 'io.spring.dependency-management' version '1.1.0'

(that are latest versions of plugins at this momentum) and use implementation 'org.springframework.boot:spring-boot-starter-security' in the body of dependencies - well, it is not working.

i assume that maybe something wrong in versions, cuz the problem seems exactly the same as You mentioned (https://github.com/spring-projects/spring-security/issues/12473). should i use explicit version of spring security?

------- my problem is below this line, just as example ----------

i do this:

    @Bean
    public RoleHierarchy roleHierarchy() {
        RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();
        hierarchy.setHierarchy(
                "ROLE_ADMIN"
                        + " > "
                        + "ROLE_USER"
                        + " > "
                        + "ROLE_GUEST");
        return hierarchy;
    }

and in filterchain

http.authorizeHttpRequests()
                .requestMatchers(ADMIN_URL_PATTERN, API_URL_PATTERN, MAILING_URL_PATTERN)
                .hasRole("GUEST")
                .anyRequest()
                .authenticated();

when i try to access any URL matches ADMIN_URL_PATTERN using a client with ROLE_USER role, i get 403 error (access denied).
but if i change "GUEST" to "USER" - everything fine.


Comment From: jzheaux

This feature was released in 6.1.0-M1 and subsequently 6.1.0. If you update to Spring Boot 3.1.0 once it is out, then this dependency will be managed for you. Until then, yes, you can manage Spring Security up to 6.1.0 in your pom.

Can you try using Spring Security 6.1.0 and see if this works for you?

Comment From: esselesse

tried out boot 3.1.0. it's amazing! works!

thank You!

Comment From: jzheaux

Glad the latest is working for you, @esselesse! I'll close this in favor of https://github.com/spring-projects/spring-security/pull/12505, then.