diff --git a/core/src/main/java/org/springframework/security/access/hierarchicalroles/RoleHierarchyImpl.java b/core/src/main/java/org/springframework/security/access/hierarchicalroles/RoleHierarchyImpl.java index d64ad57e9d..759227be7e 100755 --- a/core/src/main/java/org/springframework/security/access/hierarchicalroles/RoleHierarchyImpl.java +++ b/core/src/main/java/org/springframework/security/access/hierarchicalroles/RoleHierarchyImpl.java @@ -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. @@ -295,11 +295,11 @@ public RoleHierarchyImpl build() { } private Builder addHierarchy(String role, String... impliedRoles) { - Set withPrefix = new HashSet<>(); + Set withPrefix = this.hierarchy.computeIfAbsent(this.rolePrefix.concat(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; } diff --git a/core/src/test/java/org/springframework/security/access/hierarchicalroles/RoleHierarchyImplTests.java b/core/src/test/java/org/springframework/security/access/hierarchicalroles/RoleHierarchyImplTests.java index f6a48ea7a7..b4cf14b6f5 100644 --- a/core/src/test/java/org/springframework/security/access/hierarchicalroles/RoleHierarchyImplTests.java +++ b/core/src/test/java/org/springframework/security/access/hierarchicalroles/RoleHierarchyImplTests.java @@ -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. @@ -259,6 +259,24 @@ public void testBuilderWithDefaultRolePrefix() { .containsExactlyInAnyOrderElementsOf(allAuthorities); } + @Test + public void testBuilderWithRepeatedRoleBuilder() { + RoleHierarchyImpl roleHierarchyImpl = RoleHierarchyImpl.withDefaultRolePrefix() + .role("A") + .implies("B") + .role("A") // Adding more implied roles to the existing role 'A' + .implies("C", "D") + .build(); + + List flatAuthorities = AuthorityUtils.createAuthorityList("ROLE_A"); + List allAuthorities = AuthorityUtils.createAuthorityList("ROLE_A", "ROLE_B", "ROLE_C", + "ROLE_D"); + + assertThat(roleHierarchyImpl).isNotNull(); + assertThat(roleHierarchyImpl.getReachableGrantedAuthorities(flatAuthorities)) + .containsExactlyInAnyOrderElementsOf(allAuthorities); + } + @Test public void testBuilderWithRolePrefix() { RoleHierarchyImpl roleHierarchyImpl = RoleHierarchyImpl.withRolePrefix("CUSTOM_PREFIX_")