All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy