5

In Spring Boot 2.7.x , I used the RoleHierarchyVoter

public RoleHierarchy roleHierarchy() {
    RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
    roleHierarchy.setHierarchy("ROLE_ADMINISTRATOR > ROLE_USER > ROLE_GUEST");
    return roleHierarchy;
}

@Bean
public RoleHierarchyVoter roleVoter() {
    return new RoleHierarchyVoter(roleHierarchy());
}

In Spring Boot 3.x AccessDecisionVoter are deprecated - the use of AuthorizationManager is recommended. Is there any posibility to use an AuthorizationManager-Implementation to set a role hierarchy? The usage of

@Bean
AccessDecisionVoter hierarchyVoter() {
    RoleHierarchy hierarchy = new RoleHierarchyImpl();
    hierarchy.setHierarchy("ROLE_ADMIN > ROLE_STAFF > ROLE_USER" +
            "ROLE_USER > ROLE_GUEST");
    return new RoleHierarchyVoter(hierarchy);
}

did not work since I use the AuthorizationFilter.

Yann39
  • 14,285
  • 11
  • 56
  • 84
  • This might help you https://docs.spring.io/spring-security/reference/5.8/migration/servlet/authorization.html#_replace_any_custom_method_security_accessdecisionmanagers – Marcus Hert da Coregio Dec 12 '22 at 17:52

2 Answers2

2

Simply exposing a expressionHandler bean should do the job.

If you use method security (@EnableMethodSecurity) :

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

@Bean
public DefaultMethodSecurityExpressionHandler expressionHandler() {
    DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
    expressionHandler.setRoleHierarchy(roleHierarchy());
    return expressionHandler;
}

If you use web security (@EnableWebSecurity) :

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

@Bean
public DefaultWebSecurityExpressionHandler expressionHandler() {
    DefaultWebSecurityExpressionHandler expressionHandler = new DefaultWebSecurityExpressionHandler();
    expressionHandler.setRoleHierarchy(roleHierarchy());
    return expressionHandler;
}
Yann39
  • 14,285
  • 11
  • 56
  • 84
  • This does not work. I filed an issue in spring security team https://github.com/spring-projects/spring-security/issues/12473 – david Dec 28 '22 at 14:43
  • I implemented this solution which is working in spring security 6.0.0 and spring boot 3.0.0 https://stackoverflow.com/a/74942274/910598 – david Dec 28 '22 at 15:52
  • Thanks for the feedback. Actually this is what I use with Spring Boot 3 and Spring Security 6 and it works totally fine, at least for method security (`@PreAuthorize`). – Yann39 Dec 28 '22 at 22:11
  • It works fine (Spring Boot 3.0.2) but I had to annotate the class also with @Configuration; which it was not necessary in Spring Boot 2.7.x – user1323562 Feb 02 '23 at 12:53
0

First, you create and instance of AuthorizationManager:

var access = AuthorityAuthorizationManager.<RequestAuthorizationContext>hasRole("USER");

This instance will be used to authorize our endpoints. So in the hasRole method, provide the name of your role or roles you want to use to protect a specific endpoint.

Second, you define your role hierarchy:

var hierarchy = new RoleHierarchyImpl();
hierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");

In this case we are defining that ROLE_ADMIN is above ROLE_USER, so ROLE_ADMIN has the same role as an ROLE_USER.

Third, we set the RoleHierarcy instance in the AuthorizationManager instance:

access.setRoleHierarchy(hierarchy);

Finally, we set the AuthorizationManager instance in our route protection configuration. So all the code togheter would look like this:

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        var access = AuthorityAuthorizationManager.<RequestAuthorizationContext>hasRole("USER");
        var hierarchy = new RoleHierarchyImpl();
        hierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");
        access.setRoleHierarchy(hierarchy);

        http.authorizeHttpRequests(authorize -> authorize.anyRequest().access(access));

        return http.build();

    }
Artenes Nogueira
  • 1,422
  • 1
  • 14
  • 23