-
Notifications
You must be signed in to change notification settings - Fork 6k
RoleHierarchy Comments are misleading #6954
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
Comments
Can you you think the issue is? I have added tests to demonstrate this works as expected See 1f7ba47 for the tests |
Sorry, I may not have stated it clearly. I mean, in the comments on the "RoleHierarchy" interface, the expression "role inheritance" needs to have the "and" connector to connect, but in fact, it is not correct to use the "and" connection. (or not exactly right, it was correct in earlier versions)
Please pay attention to the "and" in the comment above.
Unit testing also shows that it is wrong to connect with "and":
|
Or, to put it another way, perhaps the current version of "RoleHierarchyImpl" is not compatible with the definition rules of the old version of the "role inheritance" expression. |
With the previous version (forgot the specific version number, maybe 4.x), the "and" connector is supported in the "role inheritance" expression. |
Thanks for the clarification.
Can you clarify why you believe |
I reviewed my previous code these two days and learned that I used the version 4.2.2 before. /**
* Parse input and build the map for the roles reachable in one step: the higher role
* will become a key that references a set of the reachable lower roles.
*/
private void buildRolesReachableInOneStepMap() {
Pattern pattern = Pattern.compile("(\\s*([^\\s>]+)\\s*>\\s*([^\\s>]+))");
Matcher roleHierarchyMatcher = pattern
.matcher(this.roleHierarchyStringRepresentation);
this.rolesReachableInOneStepMap = new HashMap<GrantedAuthority, Set<GrantedAuthority>>();
while (roleHierarchyMatcher.find()) {
GrantedAuthority higherRole = new SimpleGrantedAuthority(
roleHierarchyMatcher.group(2));
GrantedAuthority lowerRole = new SimpleGrantedAuthority(
roleHierarchyMatcher.group(3));
Set<GrantedAuthority> rolesReachableInOneStepSet;
if (!this.rolesReachableInOneStepMap.containsKey(higherRole)) {
rolesReachableInOneStepSet = new HashSet<GrantedAuthority>();
this.rolesReachableInOneStepMap.put(higherRole,
rolesReachableInOneStepSet);
}
else {
rolesReachableInOneStepSet = this.rolesReachableInOneStepMap
.get(higherRole);
}
addReachableRoles(rolesReachableInOneStepSet, lowerRole);
logger.debug("buildRolesReachableInOneStepMap() - From role " + higherRole
+ " one can reach role " + lowerRole + " in one step.");
}
} In this code, a regular expression grouping match is used to find a group that matches the rule. In fact, the string to be matched can contain any kind of connector. Any kind of connector will not affect the result of the expression "roleHierarchyMatcher.find()" equal to true. @Test
public void testRegexForRoleHierarchyString() {
Pattern pattern = Pattern.compile("(\\s*([^\\s>]+)\\s*>\\s*([^\\s>]+))");
String roleHierarchyStringSplitByAnd = "ROLE_HIGHEST > ROLE_HIGHER and ROLE_HIGHER > ROLE_LOW and ROLE_LOW > ROLE_LOWER";
String roleHierarchyStringSplitByOr = "ROLE_HIGHEST > ROLE_HIGHER or ROLE_HIGHER > ROLE_LOW or ROLE_LOW > ROLE_LOWER";
String roleHierarchyStringSplitBySpace = "ROLE_HIGHEST > ROLE_HIGHER ROLE_HIGHER > ROLE_LOW ROLE_LOW > ROLE_LOWER";
String roleHierarchyStringSplitByWhatever = "ROLE_HIGHEST > ROLE_HIGHER xxx ROLE_HIGHER > ROLE_LOW xxx ROLE_LOW > ROLE_LOWER";
List<String> roleHierarchyStrings = new LinkedList<String>();
roleHierarchyStrings.add(roleHierarchyStringSplitByAnd);
roleHierarchyStrings.add(roleHierarchyStringSplitByOr);
roleHierarchyStrings.add(roleHierarchyStringSplitBySpace);
roleHierarchyStrings.add(roleHierarchyStringSplitByWhatever);
for (String roleHierarchyString : roleHierarchyStrings) {
Matcher roleHierarchyMatcher = pattern.matcher(roleHierarchyString);
if (!roleHierarchyMatcher.find()) {
throw new RuntimeException("I'm dead. X﹏X");
}
}
System.out.println("All pass");
}
That is to say, in the version 4.2.2 or the adjacent version, the "RoleHierarchy" comment is neither an error nor a correct one, XD. /**
* The simple interface of a role hierarchy.
*
* @author Michael Mayr
*/
public interface RoleHierarchy {
/**
* Returns an array of all reachable authorities.
* <p>
* Reachable authorities are the directly assigned authorities plus all authorities
* that are (transitively) reachable from them in the role hierarchy.
* <p>
* Example:<br>
* Role hierarchy: ROLE_A > ROLE_B and ROLE_B > ROLE_C.<br>
* Directly assigned authority: ROLE_A.<br>
* Reachable authorities: ROLE_A, ROLE_B, ROLE_C.
*
* @param authorities - List of the directly assigned authorities.
* @return List of all reachable authorities given the assigned authorities.
*/
public Collection<? extends GrantedAuthority> getReachableGrantedAuthorities(
Collection<? extends GrantedAuthority> authorities);
} |
It should be said that the current version of "role inheritance" is more rigorous than before, I think it would be better if the "RoleHierarchy" comment is more rigorous. I will submit a PR. |
Thanks for the clarification and PR! This is now in master |
Summary
In the current version (5.1.5), the comments in the
org.springframework.security.access.hierarchicalroles.RoleHierarchy
class do not indicate their true behavior and are misleading.Actual Behavior
The correct expression for "role inheritance" should be defined like this: "ROLE_HIGHEST > ROLE_HIGHER > ROLE_LOW > ROLE_LOWER > ROLE_LOWEST".
Expected Behavior
But the comment says it needs to be defined like this: "ROLE_HIGHEST > ROLE_HIGHER and ROLE_HIGHER > ROLE_LOW and ROLE_LOW > ROLE_LOWER and ROLE_LOWER > ROLE_LOWEST". This way of defining expressions is fine in earlier versions, but it is wrong in the current version (I learned from debugging source code).
Configuration
Version
5.1.5
Sample
Please focus on two places:
org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl#buildRolesReachableInOneStepMap
org.springframework.security.access.expression.SecurityExpressionRoot#hasAnyAuthorityName
The text was updated successfully, but these errors were encountered: