Skip to content

Easier way to define Role Hierarchy #13300

Closed
@bwgjoseph

Description

@bwgjoseph

Disclaimer: I'm hesitant to create this issue for sometime as this is quite subjective, but I thought that I still want to make the suggestion to see if there's any other ways to achieve it (that I've perhaps missed out on)


Currently, if I want to define a RoleHierarchy, I can do it like

@Bean
public RoleHierarchy roleHierarchy() {
    RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
    String roleHierarchyFromMap = "ROLE_ADMIN > ROLE_STAFF \n ROLE_STAFF > ROLE_USER \n ROLE_STAFF > ROLE_GUEST";
    roleHierarchy.setHierarchy(roleHierarchyFromMap);
    return roleHierarchy;
}

The result would be something like

2023-06-09 21:17:39.881 DEBUG 20580 --- [  restartedMain] o.s.s.a.h.RoleHierarchyImpl              : setHierarchy() - The following role hierarchy was set: ROLE_ADMIN > ROLE_STAFF
 ROLE_STAFF > ROLE_USER
 ROLE_STAFF > ROLE_GUEST
2023-06-09 21:17:39.884 DEBUG 20580 --- [  restartedMain] o.s.s.a.h.RoleHierarchyImpl              : buildRolesReachableInOneStepMap() - From role ROLE_ADMIN one 
can reach role ROLE_STAFF in one step.
2023-06-09 21:17:39.885 DEBUG 20580 --- [  restartedMain] o.s.s.a.h.RoleHierarchyImpl              : buildRolesReachableInOneStepMap() - From role ROLE_STAFF one 
can reach role ROLE_USER in one step.
2023-06-09 21:17:39.885 DEBUG 20580 --- [  restartedMain] o.s.s.a.h.RoleHierarchyImpl              : buildRolesReachableInOneStepMap() - From role ROLE_STAFF one 
can reach role ROLE_GUEST in one step.
2023-06-09 21:17:39.886 DEBUG 20580 --- [  restartedMain] o.s.s.a.h.RoleHierarchyImpl              : buildRolesReachableInOneOrMoreStepsMap() - From role ROLE_STAFF one can reach [ROLE_USER, ROLE_GUEST] in one or more steps.
2023-06-09 21:17:39.888 DEBUG 20580 --- [  restartedMain] o.s.s.a.h.RoleHierarchyImpl              : buildRolesReachableInOneOrMoreStepsMap() - From role ROLE_ADMIN one can reach [ROLE_USER, ROLE_STAFF, ROLE_GUEST] in one or more steps.

Which is correct, but it is more prone to mistake (with more complex setup), and "uglier" to declare this way via \n

Luckily, for most use case, I can replace it with RoleHierarchyUtils.roleHierarchyFromMap but not for this case where there's a repeated key. And since we are using Map, key has to be unique.

@Bean
public RoleHierarchy roleHierarchy() {
    RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
    Map<String, List<String>> roleHierarchyMap = new HashMap<>();

    roleHierarchyMap.put("ROLE_ADMIN", List.of("ROLE_STAFF"));
    roleHierarchyMap.put("ROLE_STAFF", List.of("ROLE_USER"));
    // Because it is Map, I can't quite define this
    // roleHierarchyMap.put("ROLE_STAFF", List.of("ROLE_GUEST"));
    String roleHierarchyFromMap = RoleHierarchyUtils.roleHierarchyFromMap(roleHierarchyMap);

    roleHierarchy.setHierarchy(roleHierarchyFromMap);
    return roleHierarchy;
}

Note that for this use case, ROLE_STAFF inherit ROLE_USER AND inherit ROLE_GUEST but ROLE_USER does not inherit ROLE_GUEST. Hence, I can't simply do the following

@Bean
public RoleHierarchy roleHierarchy() {
    RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
    Map<String, List<String>> roleHierarchyMap = new HashMap<>();

    roleHierarchyMap.put("ROLE_ADMIN", List.of("ROLE_STAFF"));
    roleHierarchyMap.put("ROLE_STAFF", List.of("ROLE_USER", "ROLE_GUEST"));
    String roleHierarchyFromMap = RoleHierarchyUtils.roleHierarchyFromMap(roleHierarchyMap);

    roleHierarchy.setHierarchy(roleHierarchyFromMap);
    return roleHierarchy;
}

Which is a limitation for this use case.

I have another way to declare. Since Java now supports TextBlock, I can still define as

@Bean
public RoleHierarchy roleHierarchy() {
    RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
    Map<String, List<String>> roleHierarchyMap = new HashMap<>();

    String roleHierarchyFromMap = """
            ROLE_ADMIN > ROLE_STAFF
            ROLE_STAFF > ROLE_USER
            ROLE_STAFF > ROLE_GUEST
            """;

    roleHierarchy.setHierarchy(roleHierarchyFromMap);
    return roleHierarchy;
}

Which still works. But I do still like the way that I use Map to define my hierarchy, which is still clearer, better and straightforward IMO. And I think it's easier to support the declaration via application.yaml and construct through @ConfigurationProperties and set it.

I wonder if there's any way to support my use case which make the declaration easier.

Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    in: coreAn issue in spring-security-corestatus: ideal-for-contributionAn issue that we actively are looking for someone to help us withtype: enhancementA general enhancement

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions