org.springframework.security.access.hierarchicalroles.RoleHierarchyImplCustom Maven / Gradle / Ivy
package org.springframework.security.access.hierarchicalroles;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.util.StringUtils;
public class RoleHierarchyImplCustom extends org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl {
protected final Log logger = LogFactory.getLog(getClass());
private String roleHierarchyStringRepresentation = null;
private Map> rolesReachableInOneStepMap = null;
private Map> rolesReachableInOneOrMoreStepsMap = null;
private long timeout = 10000L;
/**
* @see java.util.concurrent.Executors#newSingleThreadExecutor()
* @see java.util.concurrent.Executors#newCachedThreadPool()
* @see java.lang.Thread#currentThread()
* @see java.lang.Thread#interrupt()
*/
@Override
public synchronized void setHierarchy(String roleHierarchyStringRepresentation) {
this.roleHierarchyStringRepresentation = roleHierarchyStringRepresentation;
logger.debug("setHierarchy() - The following role hierarchy was set: " + roleHierarchyStringRepresentation);
buildRolesReachableInOneStepMap();
Future future = Executors.newSingleThreadExecutor().submit(new Runnable() {
@Override
public void run() {
buildRolesReachableInOneOrMoreStepsMap();
}
});
try {
if (timeout < 0) {
future.get();
}
else {
future.get(this.timeout, TimeUnit.MILLISECONDS);
}
}
catch (InterruptedException | TimeoutException e) {
future.cancel(true);
throw new IllegalStateException(e);
}
catch (ExecutionException e) {
if (e.getCause() instanceof CycleInRoleHierarchyException) {
StackTraceElement[] causeStackTrace = e.getCause().getStackTrace();
StackTraceElement[] stackTrace = e.getStackTrace();
StackTraceElement[] stackTraceElements = (StackTraceElement[]) Array.newInstance(StackTraceElement.class, causeStackTrace.length + stackTrace.length);
System.arraycopy(causeStackTrace, 0, stackTraceElements, 0, causeStackTrace.length);
System.arraycopy(stackTrace, 0, stackTraceElements, causeStackTrace.length, stackTrace.length);
e.getCause().setStackTrace(stackTraceElements);
throw (CycleInRoleHierarchyException) e.getCause();
}
throw new IllegalStateException(e);
}
}
@Override
public Collection getReachableGrantedAuthorities(Collection authorities) {
if (authorities == null || authorities.isEmpty()) {
return AuthorityUtils.NO_AUTHORITIES;
}
Set reachableRoles = new HashSet();
for (GrantedAuthority authority : authorities) {
addReachableRoles(reachableRoles, authority);
Set additionalReachableRoles = getRolesReachableInOneOrMoreSteps(authority);
if (additionalReachableRoles != null) {
reachableRoles.addAll(additionalReachableRoles);
}
}
if (logger.isDebugEnabled()) {
logger.debug("getReachableGrantedAuthorities() - From the roles " + authorities + " one can reach " + reachableRoles + " in zero or more steps.");
}
List reachableRoleList = new ArrayList(reachableRoles.size());
reachableRoleList.addAll(reachableRoles);
return reachableRoleList;
}
// SEC-863
private void addReachableRoles(Set reachableRoles, GrantedAuthority authority) {
for (GrantedAuthority testAuthority : reachableRoles) {
String testKey = testAuthority.getAuthority();
if ((testKey != null) && (testKey.equals(authority.getAuthority()))) {
return;
}
}
reachableRoles.add(authority);
}
// SEC-863
private Set getRolesReachableInOneOrMoreSteps(GrantedAuthority authority) {
if (authority.getAuthority() == null) {
return null;
}
for (GrantedAuthority testAuthority : this.rolesReachableInOneOrMoreStepsMap.keySet()) {
String testKey = testAuthority.getAuthority();
if ((testKey != null) && (testKey.equals(authority.getAuthority()))) {
return this.rolesReachableInOneOrMoreStepsMap.get(testAuthority);
}
}
return null;
}
/**
*
* Pattern pattern = Pattern.compile("(\\s*([^\\s>]+)\\s*>\\s*([^\\s>]+))");
*
*/
private void buildRolesReachableInOneStepMap() {
this.rolesReachableInOneStepMap = new HashMap>();
if (StringUtils.hasText(this.roleHierarchyStringRepresentation)) {
try (BufferedReader bufferedReader = new BufferedReader(new StringReader(this.roleHierarchyStringRepresentation))) {
for (String readLine; StringUtils.hasText(readLine = bufferedReader.readLine());) {
for (String roleHierarchyStringRepresentation : readLine.split(" and ")) {
if (StringUtils.hasText(roleHierarchyStringRepresentation)) {
String[] strings = roleHierarchyStringRepresentation.split(" > ");
for (int i = 1; i < strings.length; i++) {
String higherRoleString = strings[i - 1].replaceAll("^\\s+|\\s+$", "");
String lowerRoleString = strings[i].replaceAll("^\\s+|\\s+$", "");
if (StringUtils.hasText(higherRoleString) && StringUtils.hasText(lowerRoleString)) {
GrantedAuthority higherRole = new SimpleGrantedAuthority(higherRoleString);
GrantedAuthority lowerRole = new SimpleGrantedAuthority(lowerRoleString);
Set rolesReachableInOneStepSet;
if (!this.rolesReachableInOneStepMap.containsKey(higherRole)) {
rolesReachableInOneStepSet = new HashSet();
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.");
}
}
}
}
}
}
catch (IOException e) {
throw new IllegalStateException(e);
}
}
}
private void buildRolesReachableInOneOrMoreStepsMap() {
this.rolesReachableInOneOrMoreStepsMap = new HashMap>();
for (GrantedAuthority role : this.rolesReachableInOneStepMap.keySet()) {
Set rolesToVisitSet = new HashSet();
if (this.rolesReachableInOneStepMap.containsKey(role)) {
rolesToVisitSet.addAll(this.rolesReachableInOneStepMap.get(role));
}
Set visitedRolesSet = new HashSet();
while (!rolesToVisitSet.isEmpty()) {
GrantedAuthority aRole = rolesToVisitSet.iterator().next();
rolesToVisitSet.remove(aRole);
addReachableRoles(visitedRolesSet, aRole);
if (this.rolesReachableInOneStepMap.containsKey(aRole)) {
Set newReachableRoles = this.rolesReachableInOneStepMap.get(aRole);
if (rolesToVisitSet.contains(role) || visitedRolesSet.contains(role)) {
throw new CycleInRoleHierarchyException();
}
else {
rolesToVisitSet.addAll(newReachableRoles);
}
}
}
this.rolesReachableInOneOrMoreStepsMap.put(role, visitedRolesSet);
logger.debug("buildRolesReachableInOneOrMoreStepsMap() - From role " + role + " one can reach " + visitedRolesSet + " in one or more steps.");
}
}
public long getTimeout() {
return timeout;
}
public void setTimeout(long timeout) {
this.timeout = timeout;
}
}