SEC-863: Hierarchical roles should use the interface GrantedAuthority. Applied submitted patch.

This commit is contained in:
Luke Taylor 2009-04-22 05:53:59 +00:00
parent d7f202a111
commit 305ce125fb
4 changed files with 596 additions and 407 deletions

View File

@ -1,198 +1,233 @@
/* /*
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.security.access.hierarchicalroles; package org.springframework.security.access.hierarchicalroles;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl; import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.*; import java.util.*;
/** /**
* <p> * <p>
* This class defines a role hierarchy for use with the UserDetailsServiceWrapper. * This class defines a role hierarchy for use with the UserDetailsServiceWrapper.
* </p> * </p>
* <p> * <p>
* Here is an example configuration of a role hierarchy (hint: read the "&gt;" sign as "includes"): * Here is an example configuration of a role hierarchy (hint: read the "&gt;" sign as "includes"):
<pre> <pre>
&lt;property name="hierarchy"&gt; &lt;property name="hierarchy"&gt;
&lt;value&gt; &lt;value&gt;
ROLE_A &gt; ROLE_B ROLE_A &gt; ROLE_B
ROLE_B &gt; ROLE_AUTHENTICATED ROLE_B &gt; ROLE_AUTHENTICATED
ROLE_AUTHENTICATED &gt; ROLE_UNAUTHENTICATED ROLE_AUTHENTICATED &gt; ROLE_UNAUTHENTICATED
&lt;/value&gt; &lt;/value&gt;
&lt;/property&gt; &lt;/property&gt;
</pre> </pre>
</p> </p>
* <p> * <p>
* Explanation of the above:<br> * Explanation of the above:<br>
* In effect every user with ROLE_A also has ROLE_B, ROLE_AUTHENTICATED and ROLE_UNAUTHENTICATED;<br> * In effect every user with ROLE_A also has ROLE_B, ROLE_AUTHENTICATED and ROLE_UNAUTHENTICATED;<br>
* every user with ROLE_B also has ROLE_AUTHENTICATED and ROLE_UNAUTHENTICATED;<br> * every user with ROLE_B also has ROLE_AUTHENTICATED and ROLE_UNAUTHENTICATED;<br>
* every user with ROLE_AUTHENTICATED also has ROLE_UNAUTHENTICATED. * every user with ROLE_AUTHENTICATED also has ROLE_UNAUTHENTICATED.
* </p> * </p>
* <p> * <p>
* Hierarchical Roles will dramatically shorten your access rules (and also make the access rules much more elegant). * Hierarchical Roles will dramatically shorten your access rules (and also make the access rules much more elegant).
* </p> * </p>
* <p> * <p>
* Consider this access rule for Spring Security's RoleVoter (background: every user that is authenticated should be * Consider this access rule for Spring Security's RoleVoter (background: every user that is authenticated should be
* able to log out):<br> * able to log out):<br>
* /logout.html=ROLE_A,ROLE_B,ROLE_AUTHENTICATED<br> * /logout.html=ROLE_A,ROLE_B,ROLE_AUTHENTICATED<br>
* With hierarchical roles this can now be shortened to:<br> * With hierarchical roles this can now be shortened to:<br>
* /logout.html=ROLE_AUTHENTICATED<br> * /logout.html=ROLE_AUTHENTICATED<br>
* In addition to shorter rules this will also make your access rules more readable and your intentions clearer. * In addition to shorter rules this will also make your access rules more readable and your intentions clearer.
* </p> * </p>
* *
* @author Michael Mayr * @author Michael Mayr
* *
*/ */
public class RoleHierarchyImpl implements RoleHierarchy { public class RoleHierarchyImpl implements RoleHierarchy {
private static final Log logger = LogFactory.getLog(RoleHierarchyImpl.class); private static final Log logger = LogFactory.getLog(RoleHierarchyImpl.class);
private String roleHierarchyStringRepresentation = null; private String roleHierarchyStringRepresentation = null;
/** /**
* rolesReachableInOneStepMap is a Map that under the key of a specific role name contains a set of all roles * rolesReachableInOneStepMap is a Map that under the key of a specific role name contains a set of all roles
* reachable from this role in 1 step * reachable from this role in 1 step
*/ */
private Map<GrantedAuthority, Set<GrantedAuthority>> rolesReachableInOneStepMap = null; private Map<GrantedAuthority, Set<GrantedAuthority>> rolesReachableInOneStepMap = null;
/** /**
* rolesReachableInOneOrMoreStepsMap is a Map that under the key of a specific role name contains a set of all * rolesReachableInOneOrMoreStepsMap is a Map that under the key of a specific role name contains a set of all
* roles reachable from this role in 1 or more steps * roles reachable from this role in 1 or more steps
*/ */
private Map<GrantedAuthority, Set<GrantedAuthority>> rolesReachableInOneOrMoreStepsMap = null; private Map<GrantedAuthority, Set<GrantedAuthority>> rolesReachableInOneOrMoreStepsMap = null;
/** /**
* Set the role hierarchy and pre-calculate for every role the set of all reachable roles, i.e. all roles lower in * Set the role hierarchy and pre-calculate for every role the set of all reachable roles, i.e. all roles lower in
* the hierarchy of every given role. Pre-calculation is done for performance reasons (reachable roles can then be * the hierarchy of every given role. Pre-calculation is done for performance reasons (reachable roles can then be
* calculated in O(1) time). * calculated in O(1) time).
* During pre-calculation, cycles in role hierarchy are detected and will cause a * During pre-calculation, cycles in role hierarchy are detected and will cause a
* <tt>CycleInRoleHierarchyException</tt> to be thrown. * <tt>CycleInRoleHierarchyException</tt> to be thrown.
* *
* @param roleHierarchyStringRepresentation - String definition of the role hierarchy. * @param roleHierarchyStringRepresentation - String definition of the role hierarchy.
*/ */
public void setHierarchy(String roleHierarchyStringRepresentation) { public void setHierarchy(String roleHierarchyStringRepresentation) {
this.roleHierarchyStringRepresentation = roleHierarchyStringRepresentation; this.roleHierarchyStringRepresentation = roleHierarchyStringRepresentation;
logger.debug("setHierarchy() - The following role hierarchy was set: " + roleHierarchyStringRepresentation); logger.debug("setHierarchy() - The following role hierarchy was set: " + roleHierarchyStringRepresentation);
buildRolesReachableInOneStepMap(); buildRolesReachableInOneStepMap();
buildRolesReachableInOneOrMoreStepsMap(); buildRolesReachableInOneOrMoreStepsMap();
} }
public List<GrantedAuthority> getReachableGrantedAuthorities(List<GrantedAuthority> authorities) { public List<GrantedAuthority> getReachableGrantedAuthorities(List<GrantedAuthority> authorities) {
if (authorities == null || authorities.isEmpty()) { if (authorities == null || authorities.isEmpty()) {
return null; return null;
} }
Set<GrantedAuthority> reachableRoles = new HashSet<GrantedAuthority>(); Set<GrantedAuthority> reachableRoles = new HashSet<GrantedAuthority>();
for (GrantedAuthority authority : authorities) { for (GrantedAuthority authority : authorities) {
reachableRoles.add(authority); addReachableRoles(reachableRoles, authority);
Set<GrantedAuthority> additionalReachableRoles = rolesReachableInOneOrMoreStepsMap.get(authority); Set<GrantedAuthority> additionalReachableRoles = getRolesReachableInOneOrMoreSteps(authority);
if (additionalReachableRoles != null) { if (additionalReachableRoles != null) {
reachableRoles.addAll(additionalReachableRoles); reachableRoles.addAll(additionalReachableRoles);
} }
} }
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("getReachableGrantedAuthorities() - From the roles " + authorities logger.debug("getReachableGrantedAuthorities() - From the roles " + authorities
+ " one can reach " + reachableRoles + " in zero or more steps."); + " one can reach " + reachableRoles + " in zero or more steps.");
} }
List<GrantedAuthority> reachableRoleList = new ArrayList<GrantedAuthority>(reachableRoles.size()); List<GrantedAuthority> reachableRoleList = new ArrayList<GrantedAuthority>(reachableRoles.size());
reachableRoleList.addAll(reachableRoles); reachableRoleList.addAll(reachableRoles);
return reachableRoleList; return reachableRoleList;
} }
/** // SEC-863
* Parse input and build the map for the roles reachable in one step: the higher role will become a key that private void addReachableRoles(Set<GrantedAuthority> reachableRoles,
* references a set of the reachable lower roles. GrantedAuthority authority) {
*/
private void buildRolesReachableInOneStepMap() { Iterator<GrantedAuthority> iterator = reachableRoles.iterator();
Pattern pattern = Pattern.compile("(\\s*([^\\s>]+)\\s*\\>\\s*([^\\s>]+))"); while (iterator.hasNext()) {
GrantedAuthority testAuthority = iterator.next();
Matcher roleHierarchyMatcher = pattern.matcher(roleHierarchyStringRepresentation); String testKey = testAuthority.getAuthority();
rolesReachableInOneStepMap = new HashMap<GrantedAuthority, Set<GrantedAuthority>>(); if ((testKey != null) && (testKey.equals(authority.getAuthority()))) {
return;
while (roleHierarchyMatcher.find()) { }
GrantedAuthority higherRole = new GrantedAuthorityImpl(roleHierarchyMatcher.group(2)); }
GrantedAuthority lowerRole = new GrantedAuthorityImpl(roleHierarchyMatcher.group(3)); reachableRoles.add(authority);
Set<GrantedAuthority> rolesReachableInOneStepSet = null; }
if (!rolesReachableInOneStepMap.containsKey(higherRole)) { // SEC-863
rolesReachableInOneStepSet = new HashSet<GrantedAuthority>(); private Set<GrantedAuthority> getRolesReachableInOneOrMoreSteps(
rolesReachableInOneStepMap.put(higherRole, rolesReachableInOneStepSet); GrantedAuthority authority) {
} else {
rolesReachableInOneStepSet = rolesReachableInOneStepMap.get(higherRole); if (authority.getAuthority() == null) {
} return null;
rolesReachableInOneStepSet.add(lowerRole); }
logger.debug("buildRolesReachableInOneStepMap() - From role " Iterator<GrantedAuthority> iterator = rolesReachableInOneOrMoreStepsMap.keySet().iterator();
+ higherRole + " one can reach role " + lowerRole + " in one step."); while (iterator.hasNext()) {
} GrantedAuthority testAuthority = iterator.next();
} String testKey = testAuthority.getAuthority();
if ((testKey != null) && (testKey.equals(authority.getAuthority()))) {
/** return rolesReachableInOneOrMoreStepsMap.get(testAuthority);
* For every higher role from rolesReachableInOneStepMap store all roles that are reachable from it in the map of }
* roles reachable in one or more steps. (Or throw a CycleInRoleHierarchyException if a cycle in the role }
* hierarchy definition is detected)
*/ return null;
private void buildRolesReachableInOneOrMoreStepsMap() { }
rolesReachableInOneOrMoreStepsMap = new HashMap<GrantedAuthority, Set<GrantedAuthority>>();
// iterate over all higher roles from rolesReachableInOneStepMap /**
* Parse input and build the map for the roles reachable in one step: the higher role will become a key that
for(GrantedAuthority role : rolesReachableInOneStepMap.keySet()) { * references a set of the reachable lower roles.
Set<GrantedAuthority> rolesToVisitSet = new HashSet<GrantedAuthority>(); */
private void buildRolesReachableInOneStepMap() {
if (rolesReachableInOneStepMap.containsKey(role)) { Pattern pattern = Pattern.compile("(\\s*([^\\s>]+)\\s*\\>\\s*([^\\s>]+))");
rolesToVisitSet.addAll(rolesReachableInOneStepMap.get(role));
} Matcher roleHierarchyMatcher = pattern.matcher(roleHierarchyStringRepresentation);
rolesReachableInOneStepMap = new HashMap<GrantedAuthority, Set<GrantedAuthority>>();
Set<GrantedAuthority> visitedRolesSet = new HashSet<GrantedAuthority>();
while (roleHierarchyMatcher.find()) {
while (!rolesToVisitSet.isEmpty()) { GrantedAuthority higherRole = new GrantedAuthorityImpl(roleHierarchyMatcher.group(2));
// take a role from the rolesToVisit set GrantedAuthority lowerRole = new GrantedAuthorityImpl(roleHierarchyMatcher.group(3));
GrantedAuthority aRole = (GrantedAuthority) rolesToVisitSet.iterator().next(); Set<GrantedAuthority> rolesReachableInOneStepSet = null;
rolesToVisitSet.remove(aRole);
visitedRolesSet.add(aRole); if (!rolesReachableInOneStepMap.containsKey(higherRole)) {
if (rolesReachableInOneStepMap.containsKey(aRole)) { rolesReachableInOneStepSet = new HashSet<GrantedAuthority>();
Set<GrantedAuthority> newReachableRoles = rolesReachableInOneStepMap.get(aRole); rolesReachableInOneStepMap.put(higherRole, rolesReachableInOneStepSet);
} else {
// definition of a cycle: you can reach the role you are starting from rolesReachableInOneStepSet = rolesReachableInOneStepMap.get(higherRole);
if (rolesToVisitSet.contains(role) || visitedRolesSet.contains(role)) { }
throw new CycleInRoleHierarchyException(); addReachableRoles(rolesReachableInOneStepSet, lowerRole);
} else {
// no cycle logger.debug("buildRolesReachableInOneStepMap() - From role "
rolesToVisitSet.addAll(newReachableRoles); + higherRole + " one can reach role " + lowerRole + " in one step.");
} }
} }
}
rolesReachableInOneOrMoreStepsMap.put(role, visitedRolesSet); /**
* For every higher role from rolesReachableInOneStepMap store all roles that are reachable from it in the map of
logger.debug("buildRolesReachableInOneOrMoreStepsMap() - From role " * roles reachable in one or more steps. (Or throw a CycleInRoleHierarchyException if a cycle in the role
+ role + " one can reach " + visitedRolesSet + " in one or more steps."); * hierarchy definition is detected)
} */
private void buildRolesReachableInOneOrMoreStepsMap() {
} rolesReachableInOneOrMoreStepsMap = new HashMap<GrantedAuthority, Set<GrantedAuthority>>();
// iterate over all higher roles from rolesReachableInOneStepMap
}
for(GrantedAuthority role : rolesReachableInOneStepMap.keySet()) {
Set<GrantedAuthority> rolesToVisitSet = new HashSet<GrantedAuthority>();
if (rolesReachableInOneStepMap.containsKey(role)) {
rolesToVisitSet.addAll(rolesReachableInOneStepMap.get(role));
}
Set<GrantedAuthority> visitedRolesSet = new HashSet<GrantedAuthority>();
while (!rolesToVisitSet.isEmpty()) {
// take a role from the rolesToVisit set
GrantedAuthority aRole = (GrantedAuthority) rolesToVisitSet.iterator().next();
rolesToVisitSet.remove(aRole);
addReachableRoles(visitedRolesSet, aRole);
if (rolesReachableInOneStepMap.containsKey(aRole)) {
Set<GrantedAuthority> newReachableRoles = rolesReachableInOneStepMap.get(aRole);
// definition of a cycle: you can reach the role you are starting from
if (rolesToVisitSet.contains(role) || visitedRolesSet.contains(role)) {
throw new CycleInRoleHierarchyException();
} else {
// no cycle
rolesToVisitSet.addAll(newReachableRoles);
}
}
}
rolesReachableInOneOrMoreStepsMap.put(role, visitedRolesSet);
logger.debug("buildRolesReachableInOneOrMoreStepsMap() - From role "
+ role + " one can reach " + visitedRolesSet + " in one or more steps.");
}
}
}

View File

@ -1,40 +1,92 @@
/* /*
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.security.access.hierarchicalroles; package org.springframework.security.access.hierarchicalroles;
import java.util.List; import java.util.ArrayList;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.apache.commons.collections.CollectionUtils; import org.springframework.security.core.GrantedAuthority;
import org.apache.commons.collections.CollectionUtils;
/**
* Test helper class for the hierarchical roles tests. /**
* * Test helper class for the hierarchical roles tests.
* @author Michael Mayr *
*/ * @author Michael Mayr
public abstract class HierarchicalRolesTestHelper { */
public abstract class HierarchicalRolesTestHelper {
public static boolean containTheSameGrantedAuthorities(List<GrantedAuthority> authorities1, List<GrantedAuthority> authorities2) {
if (authorities1 == null && authorities2 == null) { public static boolean containTheSameGrantedAuthorities(List<GrantedAuthority> authorities1, List<GrantedAuthority> authorities2) {
return true; if (authorities1 == null && authorities2 == null) {
} return true;
}
if (authorities1 == null || authorities2 == null) {
return false; if (authorities1 == null || authorities2 == null) {
} return false;
return CollectionUtils.isEqualCollection(authorities1, authorities2); }
} return CollectionUtils.isEqualCollection(authorities1, authorities2);
}
}
public static boolean containTheSameGrantedAuthoritiesCompareByAuthorityString(List<GrantedAuthority> authorities1, List<GrantedAuthority> authorities2) {
if (authorities1 == null && authorities2 == null) {
return true;
}
if (authorities1 == null || authorities2 == null) {
return false;
}
return CollectionUtils.isEqualCollection(toListOfAuthorityStrings(authorities1), toListOfAuthorityStrings(authorities2));
}
public static List<String> toListOfAuthorityStrings(List<GrantedAuthority> authorities) {
if (authorities == null) {
return null;
}
List<String> result = new ArrayList<String>(authorities.size());
for (GrantedAuthority authority : authorities) {
result.add(authority.getAuthority());
}
return result;
}
public static List<GrantedAuthority> createAuthorityList(final String... roles) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(roles.length);
for (final String role : roles) {
// Use non GrantedAuthorityImpl (SEC-863)
authorities.add(new GrantedAuthority() {
public String getAuthority() {
return role;
}
public int compareTo(GrantedAuthority ga) {
if (ga != null) {
String rhsRole = ga.getAuthority();
if (rhsRole == null) {
return -1;
}
return role.compareTo(rhsRole);
}
return -1;
}
});
}
return authorities;
}
}

View File

@ -1,114 +1,128 @@
/* /*
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.security.access.hierarchicalroles; package org.springframework.security.access.hierarchicalroles;
import java.util.List; import java.util.List;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException; import org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl; import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.AuthorityUtils;
/** /**
* Tests for {@link RoleHierarchyImpl}. * Tests for {@link RoleHierarchyImpl}.
* *
* @author Michael Mayr * @author Michael Mayr
*/ */
public class RoleHierarchyImplTests extends TestCase { public class RoleHierarchyImplTests extends TestCase {
public void testSimpleRoleHierarchy() { public void testSimpleRoleHierarchy() {
List<GrantedAuthority> authorities0 = AuthorityUtils.createAuthorityList("ROLE_0"); List<GrantedAuthority> authorities0 = AuthorityUtils.createAuthorityList("ROLE_0");
List<GrantedAuthority> authorities1 = AuthorityUtils.createAuthorityList("ROLE_A"); List<GrantedAuthority> authorities1 = AuthorityUtils.createAuthorityList("ROLE_A");
List<GrantedAuthority> authorities2 = AuthorityUtils.createAuthorityList("ROLE_A","ROLE_B"); List<GrantedAuthority> authorities2 = AuthorityUtils.createAuthorityList("ROLE_A","ROLE_B");
RoleHierarchyImpl roleHierarchyImpl = new RoleHierarchyImpl(); RoleHierarchyImpl roleHierarchyImpl = new RoleHierarchyImpl();
roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B"); roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B");
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authorities0), authorities0)); assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authorities0), authorities0));
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authorities1), authorities2)); assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authorities1), authorities2));
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authorities2), authorities2)); assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authorities2), authorities2));
} }
public void testTransitiveRoleHierarchies() { public void testTransitiveRoleHierarchies() {
List<GrantedAuthority> authorities1 = AuthorityUtils.createAuthorityList("ROLE_A"); List<GrantedAuthority> authorities1 = AuthorityUtils.createAuthorityList("ROLE_A");
List<GrantedAuthority> authorities2 = AuthorityUtils.createAuthorityList("ROLE_A","ROLE_B","ROLE_C"); List<GrantedAuthority> authorities2 = AuthorityUtils.createAuthorityList("ROLE_A","ROLE_B","ROLE_C");
List<GrantedAuthority> authorities3 = AuthorityUtils.createAuthorityList("ROLE_A","ROLE_B","ROLE_C","ROLE_D"); List<GrantedAuthority> authorities3 = AuthorityUtils.createAuthorityList("ROLE_A","ROLE_B","ROLE_C","ROLE_D");
RoleHierarchyImpl roleHierarchyImpl = new RoleHierarchyImpl(); RoleHierarchyImpl roleHierarchyImpl = new RoleHierarchyImpl();
roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B\nROLE_B > ROLE_C"); roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B\nROLE_B > ROLE_C");
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authorities1), authorities2)); assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authorities1), authorities2));
roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B\nROLE_B > ROLE_C\nROLE_C > ROLE_D"); roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B\nROLE_B > ROLE_C\nROLE_C > ROLE_D");
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authorities1), authorities3)); assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authorities1), authorities3));
} }
public void testComplexRoleHierarchy() { public void testComplexRoleHierarchy() {
List<GrantedAuthority> authoritiesInput1 = AuthorityUtils.createAuthorityList("ROLE_A"); List<GrantedAuthority> authoritiesInput1 = AuthorityUtils.createAuthorityList("ROLE_A");
List<GrantedAuthority> authoritiesOutput1 = AuthorityUtils.createAuthorityList("ROLE_A", "ROLE_B","ROLE_C", "ROLE_D"); List<GrantedAuthority> authoritiesOutput1 = AuthorityUtils.createAuthorityList("ROLE_A", "ROLE_B","ROLE_C", "ROLE_D");
List<GrantedAuthority> authoritiesInput2 = AuthorityUtils.createAuthorityList("ROLE_B"); List<GrantedAuthority> authoritiesInput2 = AuthorityUtils.createAuthorityList("ROLE_B");
List<GrantedAuthority> authoritiesOutput2 = AuthorityUtils.createAuthorityList("ROLE_B","ROLE_D"); List<GrantedAuthority> authoritiesOutput2 = AuthorityUtils.createAuthorityList("ROLE_B","ROLE_D");
List<GrantedAuthority> authoritiesInput3 = AuthorityUtils.createAuthorityList("ROLE_C"); List<GrantedAuthority> authoritiesInput3 = AuthorityUtils.createAuthorityList("ROLE_C");
List<GrantedAuthority> authoritiesOutput3 = AuthorityUtils.createAuthorityList("ROLE_C","ROLE_D"); List<GrantedAuthority> authoritiesOutput3 = AuthorityUtils.createAuthorityList("ROLE_C","ROLE_D");
List<GrantedAuthority> authoritiesInput4 = AuthorityUtils.createAuthorityList("ROLE_D"); List<GrantedAuthority> authoritiesInput4 = AuthorityUtils.createAuthorityList("ROLE_D");
List<GrantedAuthority> authoritiesOutput4 = AuthorityUtils.createAuthorityList("ROLE_D"); List<GrantedAuthority> authoritiesOutput4 = AuthorityUtils.createAuthorityList("ROLE_D");
RoleHierarchyImpl roleHierarchyImpl = new RoleHierarchyImpl(); RoleHierarchyImpl roleHierarchyImpl = new RoleHierarchyImpl();
roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B\nROLE_A > ROLE_C\nROLE_C > ROLE_D\nROLE_B > ROLE_D"); roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B\nROLE_A > ROLE_C\nROLE_C > ROLE_D\nROLE_B > ROLE_D");
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authoritiesInput1), authoritiesOutput1)); assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authoritiesInput1), authoritiesOutput1));
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authoritiesInput2), authoritiesOutput2)); assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authoritiesInput2), authoritiesOutput2));
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authoritiesInput3), authoritiesOutput3)); assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authoritiesInput3), authoritiesOutput3));
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authoritiesInput4), authoritiesOutput4)); assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authoritiesInput4), authoritiesOutput4));
} }
public void testCyclesInRoleHierarchy() { public void testCyclesInRoleHierarchy() {
RoleHierarchyImpl roleHierarchyImpl = new RoleHierarchyImpl(); RoleHierarchyImpl roleHierarchyImpl = new RoleHierarchyImpl();
try { try {
roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_A"); roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_A");
fail("Cycle in role hierarchy was not detected!"); fail("Cycle in role hierarchy was not detected!");
} catch (CycleInRoleHierarchyException e) {} } catch (CycleInRoleHierarchyException e) {}
try { try {
roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B\nROLE_B > ROLE_A"); roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B\nROLE_B > ROLE_A");
fail("Cycle in role hierarchy was not detected!"); fail("Cycle in role hierarchy was not detected!");
} catch (CycleInRoleHierarchyException e) {} } catch (CycleInRoleHierarchyException e) {}
try { try {
roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B\nROLE_B > ROLE_C\nROLE_C > ROLE_A"); roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B\nROLE_B > ROLE_C\nROLE_C > ROLE_A");
fail("Cycle in role hierarchy was not detected!"); fail("Cycle in role hierarchy was not detected!");
} catch (CycleInRoleHierarchyException e) {} } catch (CycleInRoleHierarchyException e) {}
try { try {
roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B\nROLE_B > ROLE_C\nROLE_C > ROLE_E\nROLE_E > ROLE_D\nROLE_D > ROLE_B"); roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B\nROLE_B > ROLE_C\nROLE_C > ROLE_E\nROLE_E > ROLE_D\nROLE_D > ROLE_B");
fail("Cycle in role hierarchy was not detected!"); fail("Cycle in role hierarchy was not detected!");
} catch (CycleInRoleHierarchyException e) {} } catch (CycleInRoleHierarchyException e) {}
} }
public void testNoCyclesInRoleHierarchy() { public void testNoCyclesInRoleHierarchy() {
RoleHierarchyImpl roleHierarchyImpl = new RoleHierarchyImpl(); RoleHierarchyImpl roleHierarchyImpl = new RoleHierarchyImpl();
try { try {
roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B\nROLE_A > ROLE_C\nROLE_C > ROLE_D\nROLE_B > ROLE_D"); roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B\nROLE_A > ROLE_C\nROLE_C > ROLE_D\nROLE_B > ROLE_D");
} catch (CycleInRoleHierarchyException e) { } catch (CycleInRoleHierarchyException e) {
fail("A cycle in role hierarchy was incorrectly detected!"); fail("A cycle in role hierarchy was incorrectly detected!");
} }
} }
} // SEC-863
public void testSimpleRoleHierarchyWithCustomGrantedAuthorityImplementation() {
List<GrantedAuthority> authorities0 = HierarchicalRolesTestHelper.createAuthorityList("ROLE_0");
List<GrantedAuthority> authorities1 = HierarchicalRolesTestHelper.createAuthorityList("ROLE_A");
List<GrantedAuthority> authorities2 = HierarchicalRolesTestHelper.createAuthorityList("ROLE_A","ROLE_B");
RoleHierarchyImpl roleHierarchyImpl = new RoleHierarchyImpl();
roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B");
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthoritiesCompareByAuthorityString(roleHierarchyImpl.getReachableGrantedAuthorities(authorities0), authorities0));
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthoritiesCompareByAuthorityString(roleHierarchyImpl.getReachableGrantedAuthorities(authorities1), authorities2));
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthoritiesCompareByAuthorityString(roleHierarchyImpl.getReachableGrantedAuthorities(authorities2), authorities2));
}
}

View File

@ -1,55 +1,143 @@
/* /*
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.security.access.hierarchicalroles; package org.springframework.security.access.hierarchicalroles;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.*;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.junit.Test; import org.apache.commons.collections.CollectionUtils;
import org.springframework.security.core.GrantedAuthority; import org.junit.Test;
import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
/**
* Tests for {@link HierarchicalRolesTestHelper}. /**
* * Tests for {@link HierarchicalRolesTestHelper}.
* @author Michael Mayr *
*/ * @author Michael Mayr
public class TestHelperTests { */
public class TestHelperTests {
@Test
public void testContainTheSameGrantedAuthorities() { @Test
List<GrantedAuthority> authorities1 = AuthorityUtils.createAuthorityList("ROLE_A","ROLE_B"); public void testContainTheSameGrantedAuthorities() {
List<GrantedAuthority> authorities2 = AuthorityUtils.createAuthorityList("ROLE_B","ROLE_A"); List<GrantedAuthority> authorities1 = AuthorityUtils.createAuthorityList("ROLE_A","ROLE_B");
List<GrantedAuthority> authorities3 = AuthorityUtils.createAuthorityList("ROLE_A","ROLE_C"); List<GrantedAuthority> authorities2 = AuthorityUtils.createAuthorityList("ROLE_B","ROLE_A");
List<GrantedAuthority> authorities4 = AuthorityUtils.createAuthorityList("ROLE_A"); List<GrantedAuthority> authorities3 = AuthorityUtils.createAuthorityList("ROLE_A","ROLE_C");
List<GrantedAuthority> authorities5 = AuthorityUtils.createAuthorityList("ROLE_A","ROLE_A"); List<GrantedAuthority> authorities4 = AuthorityUtils.createAuthorityList("ROLE_A");
List<GrantedAuthority> authorities5 = AuthorityUtils.createAuthorityList("ROLE_A","ROLE_A");
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(null, null));
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, authorities1)); assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(null, null));
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, authorities2)); assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, authorities1));
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities2, authorities1)); assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, authorities2));
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities2, authorities1));
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(null, authorities1));
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, null)); assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(null, authorities1));
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, authorities3)); assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, null));
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities3, authorities1)); assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, authorities3));
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, authorities4)); assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities3, authorities1));
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities4, authorities1)); assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, authorities4));
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities4, authorities5)); assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities4, authorities1));
} assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities4, authorities5));
}
}
// SEC-863
@Test
public void testToListOfAuthorityStrings() {
List<GrantedAuthority> authorities1 = AuthorityUtils.createAuthorityList("ROLE_A", "ROLE_B");
List<GrantedAuthority> authorities2 = AuthorityUtils.createAuthorityList("ROLE_B", "ROLE_A");
List<GrantedAuthority> authorities3 = AuthorityUtils.createAuthorityList("ROLE_A", "ROLE_C");
List<GrantedAuthority> authorities4 = AuthorityUtils.createAuthorityList("ROLE_A");
List<GrantedAuthority> authorities5 = AuthorityUtils.createAuthorityList("ROLE_A", "ROLE_A");
List<String> authoritiesStrings1 = new ArrayList<String>();
authoritiesStrings1.add("ROLE_A");
authoritiesStrings1.add("ROLE_B");
List<String> authoritiesStrings2 = new ArrayList<String>();
authoritiesStrings2.add("ROLE_B");
authoritiesStrings2.add("ROLE_A");
List<String> authoritiesStrings3 = new ArrayList<String>();
authoritiesStrings3.add("ROLE_A");
authoritiesStrings3.add("ROLE_C");
List<String> authoritiesStrings4 = new ArrayList<String>();
authoritiesStrings4.add("ROLE_A");
List<String> authoritiesStrings5 = new ArrayList<String>();
authoritiesStrings5.add("ROLE_A");
authoritiesStrings5.add("ROLE_A");
assertTrue(CollectionUtils.isEqualCollection(
HierarchicalRolesTestHelper.toListOfAuthorityStrings(authorities1), authoritiesStrings1));
assertTrue(CollectionUtils.isEqualCollection(
HierarchicalRolesTestHelper.toListOfAuthorityStrings(authorities2), authoritiesStrings2));
assertTrue(CollectionUtils.isEqualCollection(
HierarchicalRolesTestHelper.toListOfAuthorityStrings(authorities3), authoritiesStrings3));
assertTrue(CollectionUtils.isEqualCollection(
HierarchicalRolesTestHelper.toListOfAuthorityStrings(authorities4), authoritiesStrings4));
assertTrue(CollectionUtils.isEqualCollection(
HierarchicalRolesTestHelper.toListOfAuthorityStrings(authorities5), authoritiesStrings5));
}
// SEC-863
@Test
public void testContainTheSameGrantedAuthoritiesCompareByAuthorityString() {
List<GrantedAuthority> authorities1 = AuthorityUtils.createAuthorityList("ROLE_A", "ROLE_B");
List<GrantedAuthority> authorities2 = AuthorityUtils.createAuthorityList("ROLE_B", "ROLE_A");
List<GrantedAuthority> authorities3 = AuthorityUtils.createAuthorityList("ROLE_A", "ROLE_C");
List<GrantedAuthority> authorities4 = AuthorityUtils.createAuthorityList("ROLE_A");
List<GrantedAuthority> authorities5 = AuthorityUtils.createAuthorityList("ROLE_A", "ROLE_A");
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(null, null));
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, authorities1));
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, authorities2));
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities2, authorities1));
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(null, authorities1));
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, null));
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, authorities3));
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities3, authorities1));
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, authorities4));
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities4, authorities1));
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities4, authorities5));
}
// SEC-863
@Test
public void testContainTheSameGrantedAuthoritiesCompareByAuthorityStringWithAuthorityLists() {
List<GrantedAuthority> authorities1 = HierarchicalRolesTestHelper.createAuthorityList("ROLE_A", "ROLE_B");
List<GrantedAuthority> authorities2 = AuthorityUtils.createAuthorityList("ROLE_A", "ROLE_B");
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthoritiesCompareByAuthorityString(authorities1, authorities2));
}
// SEC-863
@Test
public void testCreateAuthorityList() {
List<GrantedAuthority> authorities1 = HierarchicalRolesTestHelper.createAuthorityList("ROLE_A");
assertEquals(authorities1.size(), 1);
assertEquals("ROLE_A", authorities1.get(0).getAuthority());
List<GrantedAuthority> authorities2 = HierarchicalRolesTestHelper.createAuthorityList("ROLE_A", "ROLE_C");
assertEquals(authorities2.size(), 2);
assertEquals("ROLE_A", authorities2.get(0).getAuthority());
assertEquals("ROLE_C", authorities2.get(1).getAuthority());
}
}