Skip to content

Augment role hierarchy in RoleHierarchyImpl Builder #15307

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -282,7 +282,19 @@ private Builder(String rolePrefix) {
*/
public ImpliedRoles role(String role) {
Assert.hasText(role, "role must not be empty");
return new ImpliedRoles(role);
return new ImpliedRoles(this.rolePrefix.concat(role));
}

/**
* Creates a new hierarchy branch to define an authority and its child roles.
* @param authority the highest authority in this branch
* @return a {@link ImpliedRoles} to define the child roles for the
* <code>authority</code>
* @since 6.4
*/
public ImpliedRoles authority(String authority) {
Assert.hasText(authority, "authority must not be empty");
return new ImpliedRoles(authority);
}

/**
Expand All @@ -295,11 +307,10 @@ public RoleHierarchyImpl build() {
}

private Builder addHierarchy(String role, String... impliedRoles) {
Set<GrantedAuthority> withPrefix = new HashSet<>();
Set<GrantedAuthority> withPrefix = this.hierarchy.computeIfAbsent(role, r -> new HashSet<>());
for (String impliedRole : impliedRoles) {
withPrefix.add(new SimpleGrantedAuthority(this.rolePrefix.concat(impliedRole)));
}
this.hierarchy.put(this.rolePrefix.concat(role), withPrefix);
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

import org.springframework.security.core.GrantedAuthority;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Test helper class for the hierarchical roles tests.
*
Expand Down Expand Up @@ -74,4 +76,37 @@ public static List<GrantedAuthority> createAuthorityList(final String... roles)
return authorities;
}

// Usage example:
// assertHierarchy(roleHierarchyImpl)
// .givesToAuthorities("C")
// .theseAuthorities("C", "ROLE_B", "ROLE_C", "ROLE_D", "ROLE_E", "ROLE_F");

public static AssertingHierarchy assertHierarchy(RoleHierarchyImpl hierarchy) {
return new AssertingHierarchy(hierarchy);
}

public static class AssertingHierarchy {
RoleHierarchyImpl hierarchy;
public AssertingHierarchy(RoleHierarchyImpl hierarchy) {
assertThat(hierarchy).isNotNull();
this.hierarchy = hierarchy;
}
public GivenAuthorities givesToAuthorities(String... authorities) {
return new GivenAuthorities(hierarchy.getReachableGrantedAuthorities(createAuthorityList(authorities)));
}
}

public static class GivenAuthorities {
Collection<GrantedAuthority> authorities;
public GivenAuthorities(Collection<GrantedAuthority> authorities) {
this.authorities = authorities;
}
public void theseAuthorities(String... expectedAuthorities) {
List<GrantedAuthority> expectedGrantedAuthorities = createAuthorityList(expectedAuthorities);
assertThat(
containTheSameGrantedAuthoritiesCompareByAuthorityString(authorities, expectedGrantedAuthorities))
.isTrue();
}
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -28,6 +28,7 @@
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatNoException;
import static org.springframework.security.access.hierarchicalroles.HierarchicalRolesTestHelper.assertHierarchy;

/**
* Tests for {@link RoleHierarchyImpl}.
Expand Down Expand Up @@ -249,29 +250,53 @@ public void testBuilderWithDefaultRolePrefix() {
.implies("B")
.role("B")
.implies("C", "D")
.authority("C")
.implies("E", "F", "B")
.build();
List<GrantedAuthority> flatAuthorities = AuthorityUtils.createAuthorityList("ROLE_A");
List<GrantedAuthority> allAuthorities = AuthorityUtils.createAuthorityList("ROLE_A", "ROLE_B", "ROLE_C",
"ROLE_D");

assertThat(roleHierarchyImpl).isNotNull();
assertThat(roleHierarchyImpl.getReachableGrantedAuthorities(flatAuthorities))
.containsExactlyInAnyOrderElementsOf(allAuthorities);
assertHierarchy(roleHierarchyImpl).givesToAuthorities("ROLE_A")
.theseAuthorities("ROLE_A", "ROLE_B", "ROLE_C", "ROLE_D");

assertHierarchy(roleHierarchyImpl).givesToAuthorities("C")
.theseAuthorities("C", "ROLE_B", "ROLE_C", "ROLE_D", "ROLE_E", "ROLE_F");
}

@Test
public void testBuilderWithRolePrefix() {
RoleHierarchyImpl roleHierarchyImpl = RoleHierarchyImpl.withRolePrefix("CUSTOM_PREFIX_")
.role("A")
.implies("B")
.role("B")
.implies("C", "D")
.authority("C")
.implies("E", "F", "B")
.build();
List<GrantedAuthority> flatAuthorities = AuthorityUtils.createAuthorityList("CUSTOM_PREFIX_A");
List<GrantedAuthority> allAuthorities = AuthorityUtils.createAuthorityList("CUSTOM_PREFIX_A",
"CUSTOM_PREFIX_B");

assertThat(roleHierarchyImpl).isNotNull();
assertThat(roleHierarchyImpl.getReachableGrantedAuthorities(flatAuthorities))
.containsExactlyInAnyOrderElementsOf(allAuthorities);
assertHierarchy(roleHierarchyImpl).givesToAuthorities("CUSTOM_PREFIX_A")
.theseAuthorities("CUSTOM_PREFIX_A", "CUSTOM_PREFIX_B", "CUSTOM_PREFIX_C", "CUSTOM_PREFIX_D");

assertHierarchy(roleHierarchyImpl).givesToAuthorities("C")
.theseAuthorities("C", "CUSTOM_PREFIX_B", "CUSTOM_PREFIX_C", "CUSTOM_PREFIX_D", "CUSTOM_PREFIX_E",
"CUSTOM_PREFIX_F");
}

@Test
public void testBuilderWithRepeatedRoleBuilder() {
RoleHierarchyImpl roleHierarchyImpl = RoleHierarchyImpl.withDefaultRolePrefix()
.role("A")
.implies("B")
.role("A")
.implies("C", "D")
.authority("A")
.implies("E")
.authority("A")
.implies("F", "G")
.build();

assertHierarchy(roleHierarchyImpl).givesToAuthorities("ROLE_A")
.theseAuthorities("ROLE_A", "ROLE_B", "ROLE_C", "ROLE_D");

assertHierarchy(roleHierarchyImpl).givesToAuthorities("A").theseAuthorities("A", "ROLE_E", "ROLE_F", "ROLE_G");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ static RoleHierarchy roleHierarchy() {
.role("ADMIN").implies("STAFF")
.role("STAFF").implies("USER")
.role("USER").implies("GUEST")
.authority("TEAM_ABC").implies("STAFF")
.build();
}

Expand All @@ -280,6 +281,7 @@ Xml::
ROLE_ADMIN > ROLE_STAFF
ROLE_STAFF > ROLE_USER
ROLE_USER > ROLE_GUEST
TEAM_ABC > ROLE_STAFF
</value>
</constructor-arg>
</bean>
Expand Down