/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.security.impl; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; /** * Helper class for querying the * role hierarchy * * @author mcr * */ public class RoleHierarchyHelper { Map<String,String> parentMappings; public RoleHierarchyHelper(Map<String,String> parentMappings) { this.parentMappings=parentMappings; } /** * Test if roleName is known * * @param roleName * */ public boolean containsRole(String roleName) { return parentMappings.containsKey(roleName); } /** * return the parent role name, null if * role has no parent * * @param roleName * */ public String getParent(String roleName) { checkRole(roleName); String parentRole = parentMappings.get(roleName); if (roleName.equals(parentRole)) cycleDetected(roleName, null); return parentRole; } /** * Calculate an ordered list of ancestors, * starting with the parent * * @param roleName * */ public List<String> getAncestors(String roleName) { checkRole(roleName); List<String> ancestors = new ArrayList<String>(); fillAncestors(parentMappings.get(roleName), ancestors); return ancestors; } /** * recursive method to fill the ancestor list * * @param roleName * @param ancestors */ protected void fillAncestors(String roleName,List<String> ancestors) { if (roleName == null || roleName.length()==0) return; // end recursion ancestors.add(roleName); String parentName=parentMappings.get(roleName); if (ancestors.contains(parentName)) { cycleDetected(roleName, parentName); } fillAncestors(parentMappings.get(roleName), ancestors); } /** * Return child roles * * @param roleName * */ public List<String> getChildren(String roleName) { checkRole(roleName); List<String> children = new ArrayList<String>(); for (Entry<String,String> entry :parentMappings.entrySet()) { if (entry.getValue()!= null && entry.getValue().equals(roleName)) { if (roleName.equals(entry.getKey())) cycleDetected(roleName,null); children.add(entry.getKey()); } } return children; } /** * Get all descendant roles, the order is * randomly * * @param roleName * */ public List<String> getDescendants(String roleName) { checkRole(roleName); Set<String> descendants = new HashSet<String>(); fillDescendents(getChildren(roleName), descendants); List<String> result=new ArrayList<String>(); result.addAll(descendants); return result; } /** * recursive method to fill the descendant list * * @param children * @param descendants */ protected void fillDescendents(List<String> children,Set<String> descendants) { if ( children == null || children.size()==0) return; // end recursion for (String childName : children) { if (descendants.contains(childName)) // cycle cycleDetected(childName, null); descendants.add(childName); } for (String childName: children) { List<String> grandchildren = getChildren(childName); fillDescendents(grandchildren, descendants); } } /** * throws a {@link RuntimeException} for a * non existing role. * * @param roleName */ protected void checkRole(String roleName) { if (parentMappings.containsKey(roleName)==false) throw new RuntimeException("Not extistend role: "+roleName); } /** * Throws a {@link RuntimeException} due to * a cyclic parent relationship between the two roles * * @param roleName1 * @param roleName2 */ protected void cycleDetected(String roleName1,String roleName2) { if (roleName2==null) throw new RuntimeException("Cycle detected for "+roleName1); else throw new RuntimeException("Cycle detected between "+roleName1+ " and " + roleName2); } /** * Check if the role is a root role * * @param roleName * */ public boolean isRoot(String roleName) { checkRole(roleName); return parentMappings.get(roleName)==null; } /** * Get a list of root roles * * */ public List<String> getRootRoles() { List<String> result = new ArrayList<String>(); for ( String roleName : parentMappings.keySet() ) { if (isRoot(roleName)) result.add(roleName); } return result; } /** * get a list of leaf roles * * */ public List<String> getLeafRoles() { List<String> result = new ArrayList<String>(); Set<String> leafRoles = new HashSet<String>(); leafRoles.addAll(parentMappings.keySet()); for ( String parentRoleName : parentMappings.values()) { if (parentRoleName!=null) leafRoles.remove(parentRoleName); } result.addAll(leafRoles); return result; } /** * returns true if parentName is a valid * parent for roleName (avoiding cycles) * * @param roleName * @param parentName * */ public boolean isValidParent(String roleName,String parentName) { if (parentName==null || parentName.length()==0) return true; if (roleName.equals(parentName)) return false; if (getDescendants(roleName).contains(parentName)) return false; return true; } }