AnsweredAssumed Answered

Dynamic Access Rights on nodes in Alfresco?

Question asked by rtitov on Feb 12, 2014
Latest reply on Feb 13, 2014 by rtitov
We would like to store personnel files of our employees in Alfresco. Each file would contain many documents, such as contracts, passport scans, appraisal reports etc.. Each category of documents would have its own access rights based on metadata. Most of those access rights will be coming from our own role management system. They can be very complex and not always can be defined through LDAP or ACLs. For example, a Departmental Administrative Officer would have access to a sub-set of documents for employees of her department, a supervisor would have access to some documents of his supervisees and so on. If the person changes the group, the access rights should immediately change correspondingly. Sometimes access rights for a document will be coming from an external system.
The system would contain millions of documents, so synchronising ACLs for each document with our role management system (e.g. by a regular job) does not sound feasible.
To solve this dynamic access rights problem, we are planning to replace the default PermissionService bean with our own implementation, which would extend PermissionServiceImpl class and override the hasPermission(NodeRef, PermissionReference) method with our own implementation. The “Inherit permissions” flag will be switched off on the top of the hierarchy of documents so the permissions will not be inherited and will be controlled by our code.



public class MyPermissionServiceImpl extends PermissionServiceImpl
{
  public static final String PERSONNEL_FOLDER = "personnel-folder";

  private static SoftCache cacheAcls = new SoftCache();

  private static Log log = LogFactory.getLog(MyPermissionServiceImpl.class);

  @Override
  public AccessStatus hasPermission(NodeRef passedNodeRef, PermissionReference permIn)
  {
    String fileName = (String) nodeService.getProperty(passedNodeRef, ContentModel.PROP_NAME);
    String currentUser = AuthenticationUtil.getRunAsUser();
    AccessStatus status = super.hasPermission(passedNodeRef, permIn);

    if ((status != AccessStatus.ALLOWED) && (nodeService.getPath(passedNodeRef).toString().indexOf(PERSONNEL_FOLDER) > -1))
      status = hasPermission(currentUser, fileName, passedNodeRef, permIn);

    log.info("Permission: " + currentUser + ": " + fileName + " - " + permIn + ": " + status);
    return status;
  }

  private AccessStatus hasPermission(String currentUser, String fileName, NodeRef node, PermissionReference permIn)
  {
    AccessStatus status = (AccessStatus)cacheAcls.get(node.getId() + ":" + currentUser + ":" + permIn.getName());

    if (status == null)
    {
      if (permIn.getName().startsWith(READ))
        status = hasReadPermission(currentUser, fileName, node, permIn);
      else if (permIn.getName().startsWith(WRITE) || permIn.getName().startsWith(DELETE) || permIn.getName().startsWith(CREATE_CHILDREN) || permIn.getName().startsWith(CREATE_ASSOCIATIONS))
        status = hasWritePermission(currentUser, fileName, node, permIn);
      else if (permIn.getName().equals(CANCEL_CHECK_OUT))
        status = hasCancelCheckOutPermission(currentUser, fileName, node, permIn);
      else if (permIn.getName().equals(CHANGE_PERMISSIONS))
        status = hasChangePermPermission(currentUser, fileName, node, permIn);
      else
      {
        status = AccessStatus.DENIED;
        log.fatal("UNKNOWN PERMISSION: " + currentUser + ": " + fileName + " - " + permIn + ": " + status);
      }
      cacheAcls.put(node.getId() + ":" + currentUser + ":" + permIn.getName(), status);
    }
    return status;
  }
 
  private AccessStatus hasReadPermission(String currentUser, String fileName, NodeRef node, PermissionReference permIn)
  {
    // Do our own access control
  }
 
  // …
 
}




We would like to know whether there are better ways to solve the problem of dynamic access control. If our approach is correct then we would like to know whether we need to override any other methods or beans.

Outcomes