/** * Copyright (C) 2010 eXo Platform SAS. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xcmis.spi; import org.xcmis.spi.model.AccessControlEntry; import org.xcmis.spi.model.AllowableActions; import org.xcmis.spi.model.BaseType; import org.xcmis.spi.model.CapabilityACL; import org.xcmis.spi.model.PermissionMapping; import org.xcmis.spi.model.RepositoryCapabilities; import org.xcmis.spi.model.RepositoryInfo; import org.xcmis.spi.model.TypeDefinition; import org.xcmis.spi.model.Permission.BasicPermissions; import org.xcmis.spi.utils.CmisUtils; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; /** * Common service for resolve CMIS object permissions. * * @author <a href="mailto:andrew00x@gmail.com">Andrey Parfonov</a> * @version $Id$ */ public class PermissionService { /** * Calculate allowable actions for specified object. * * @param object object * @param userIdentity user's identity * @param repositoryInfo RepositoryInfo * @return allowable actions for object * @see Identity */ public AllowableActions calculateAllowableActions(ObjectData object, String userId, RepositoryInfo repositoryInfo) { if (repositoryInfo.getCapabilities().getCapabilityACL().equals(CapabilityACL.NONE)) { return AllowableActions.ALL(); } if (userId == null) { userId = repositoryInfo.getPrincipalAnonymous(); } PermissionMapping permissionMapping = repositoryInfo.getAclCapability().getMapping(); AllowableActions actions = new AllowableActions(); TypeDefinition type = object.getTypeDefinition(); RepositoryCapabilities capabilities = repositoryInfo.getCapabilities(); for (String action : AllowableActions.DEFAULT) { if (AllowableActions.CAN_GET_DESCENDENTS.equals(action)) { if (capabilities.isCapabilityGetDescendants() && BaseType.FOLDER == type.getBaseId() && hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_GET_DESCENDENTS_FOLDER), userId, repositoryInfo)) { actions.setCanGetDescendants(true); } } else if (AllowableActions.CAN_GET_FOLDER_TREE.equals(action)) { if (capabilities.isCapabilityGetFolderTree() && BaseType.FOLDER == type.getBaseId() && hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_GET_FOLDER_TREE_FOLDER), userId, repositoryInfo)) { actions.setCanGetFolderTree(true); } } else if (AllowableActions.CAN_GET_CHILDREN.equals(action)) { if (BaseType.FOLDER == type.getBaseId() && hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_GET_CHILDREN_FOLDER), userId, repositoryInfo)) { actions.setCanGetChildren(true); } } else if (AllowableActions.CAN_GET_OBJECT_PARENTS.equals(action)) { if (type.isFileable() && hasPermission(object, permissionMapping .getPermissions(PermissionMapping.CAN_GET_OBJECT_PARENTS_OBJECT), userId, repositoryInfo)) { actions.setCanGetObjectParents(true); } } else if (AllowableActions.CAN_GET_FOLDER_PARENT.equals(action)) { if (BaseType.FOLDER == type.getBaseId() && hasPermission(object, permissionMapping .getPermissions(PermissionMapping.CAN_GET_FOLDER_PARENT_FOLDER), userId, repositoryInfo)) { actions.setCanGetFolderParent(true); } } else if (AllowableActions.CAN_CREATE_DOCUMENT.equals(action)) { if (BaseType.FOLDER == type.getBaseId() && hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_CREATE_DOCUMENT_FOLDER), userId, repositoryInfo)) { actions.setCanCreateDocument(true); } } else if (AllowableActions.CAN_CREATE_FOLDER.equals(action)) { if (BaseType.FOLDER == type.getBaseId() && hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_CREATE_FOLDER_FOLDER), userId, repositoryInfo)) { actions.setCanCreateFolder(true); } } else if (AllowableActions.CAN_CREATE_RELATIONSHIP.equals(action)) { if (BaseType.RELATIONSHIP != type.getBaseId() && hasPermission(object, permissionMapping .getPermissions(PermissionMapping.CAN_CREATE_RELATIONSHIP_SOURCE), userId, repositoryInfo) && hasPermission(object, permissionMapping .getPermissions(PermissionMapping.CAN_CREATE_RELATIONSHIP_TARGET), userId, repositoryInfo)) { actions.setCanCreateRelationship(true); } } else if (AllowableActions.CAN_GET_PROPERTIES.equals(action)) { if (hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_GET_PROPERTIES_OBJECT), userId, repositoryInfo)) { actions.setCanGetProperties(true); } } else if (AllowableActions.CAN_GET_CONTENT_STREAM.equals(action)) { if (BaseType.DOCUMENT == type.getBaseId() && hasPermission(object, permissionMapping .getPermissions(PermissionMapping.CAN_GET_CONTENT_STREAM_OBJECT), userId, repositoryInfo)) { actions.setCanGetContentStream(true); } } else if (AllowableActions.CAN_UPDATE_PROPERTIES.equals(action)) { if (hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_UPDATE_PROPERTIES_OBJECT), userId, repositoryInfo)) { actions.setCanUpdateProperties(true); } } else if (AllowableActions.CAN_MOVE_OBJECT.equals(action)) { if (type.isFileable() && hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_MOVE_OBJECT_OBJECT), userId, repositoryInfo)) { actions.setCanMoveObject(true); } } else if (AllowableActions.CAN_DELETE.equals(action)) { if (BaseType.FOLDER == type.getBaseId()) { if (!((FolderData)object).hasChildren() && hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_DELETE_OBJECT), userId, repositoryInfo)) { actions.setCanDeleteObject(true); } } else if (hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_DELETE_OBJECT), userId, repositoryInfo)) { actions.setCanDeleteObject(true); } } else if (AllowableActions.CAN_DELETE_TREE.equals(action)) { if (BaseType.FOLDER == type.getBaseId() && hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_DELETE_TREE_FOLDER), userId, repositoryInfo)) { actions.setCanDeleteTree(true); } } else if (AllowableActions.CAN_SET_CONTENT_STREAM.equals(action)) { if (BaseType.DOCUMENT == type.getBaseId() && hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_SET_CONTENT_DOCUMENT), userId, repositoryInfo)) { actions.setCanSetContentStream(true); } } else if (AllowableActions.CAN_DELETE_CONTENT_STREAM.equals(action)) { if (BaseType.DOCUMENT == type.getBaseId() && hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_DELETE_CONTENT_DOCUMENT), userId, repositoryInfo)) { actions.setCanDeleteContentStream(true); } } else if (AllowableActions.CAN_GET_RENDITIONS.equals(action)) { if (BaseType.DOCUMENT == type.getBaseId() && hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_GET_RENDITIONS_OBJECT), userId, repositoryInfo)) { actions.setCanGetRenditions(true); } } else if (AllowableActions.CAN_ADD_TO_FOLDER.equals(action)) { if (type.isFileable() && hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_ADD_TO_FOLDER_OBJECT), userId, repositoryInfo)) { actions.setCanAddObjectToFolder(true); } } else if (AllowableActions.CAN_REMOVE_OBJECT_FROM_FOLDER.equals(action)) { if (type.isFileable() // && type.getBaseId() != BaseType.FOLDER // && hasPermission(object, permissionMapping .getPermissions(PermissionMapping.CAN_REMOVE_OBJECT_FROM_FOLDER_OBJECT), userId, repositoryInfo) // && (repositoryInfo.getCapabilities().isCapabilityUnfiling() || object.getParents().size() > 1)) { actions.setCanRemoveObjectFromFolder(true); } } else if (AllowableActions.CAN_CHECKOUT.equals(action)) { if (type.isVersionable() && hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_CHECKOUT_DOCUMENT), userId, repositoryInfo)) { actions.setCanCheckOut(true); } } else if (AllowableActions.CAN_CANCEL_CHECKOUT.equals(action)) { if (type.isVersionable() && ((DocumentData)object).isVersionSeriesCheckedOut() && hasPermission(object, permissionMapping .getPermissions(PermissionMapping.CAN_CANCEL_CHECKOUT_DOCUMENT), userId, repositoryInfo)) { actions.setCanCancelCheckOut(true); } } else if (AllowableActions.CAN_CHECKIN.equals(action)) { if (type.isVersionable() && ((DocumentData)object).isPWC() && hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_CHECKIN_DOCUMENT), userId, repositoryInfo)) { actions.setCanCancelCheckOut(true); } } else if (AllowableActions.CAN_GET_ALL_VERSIONS.equals(action)) { if (BaseType.DOCUMENT == type.getBaseId() && hasPermission(object, permissionMapping .getPermissions(PermissionMapping.CAN_GET_ALL_VERSIONS_DOCUMENT), userId, repositoryInfo)) { actions.setCanGetAllVersions(true); } } else if (AllowableActions.CAN_GET_OBJECT_RELATIONSHIPS.equals(action)) { if (BaseType.RELATIONSHIP != type.getBaseId() && hasPermission(object, permissionMapping .getPermissions(PermissionMapping.CAN_GET_OBJECT_RELATIONSHIPS_OBJECT), userId, repositoryInfo)) { actions.setCanGetObjectRelationships(true); } } else if (AllowableActions.CAN_ADD_POLICY.equals(action)) { if (type.isControllablePolicy() && hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_ADD_POLICY_OBJECT), userId, repositoryInfo)) { actions.setCanApplyPolicy(true); } } else if (AllowableActions.CAN_REMOVE_POLICY.equals(action)) { if (type.isControllablePolicy() && hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_REMOVE_POLICY_OBJECT), userId, repositoryInfo)) { actions.setCanRemovePolicy(true); } } else if (AllowableActions.CAN_GET_APPLIED_POLICIES.equals(action)) { if (type.isControllablePolicy() && hasPermission(object, permissionMapping .getPermissions(PermissionMapping.CAN_GET_APPLIED_POLICIES_OBJECT), userId, repositoryInfo)) { actions.setCanGetAppliedPolicies(true); } } else if (AllowableActions.CAN_GET_ACL.equals(action)) { if (type.isControllableACL() && hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_GET_ACL_OBJECT), userId, repositoryInfo)) { actions.setCanGetACL(true); } } else if (AllowableActions.CAN_APPLY_ACL.equals(action)) { if (type.isControllableACL() && hasPermission(object, permissionMapping.getPermissions(PermissionMapping.CAN_APPLY_ACL_OBJECT), userId, repositoryInfo)) { actions.setCanApplyACL(true); } } } return actions; } /** * @param object object * @param permissions set of actions to be checked * @param userId user's id * @param repositoryInfo * @return <code>true</code> if user has all <code>permissions</code> and * <code>false</code> otherwise */ public boolean hasPermission(ObjectData object, Collection<String> permissions, String userId, RepositoryInfo repositoryInfo) { if (permissions == null || permissions.size() == 0) { throw new CmisRuntimeException("Permissions set may not be null or empty."); } if (userId == null) { userId = repositoryInfo.getPrincipalAnonymous(); } List<AccessControlEntry> acl = object.getACL(false); if (acl.size() == 0) { return true; } Map<String, Set<String>> map = new HashMap<String, Set<String>>(); CmisUtils.addAclToPermissionMap(map, acl); // Check for 'any principal' first the for current principal. for (String principal : new String[]{repositoryInfo.getPrincipalAnyone(), userId}) { Set<String> p = map.get(principal); if (p != null) { if (p.contains(BasicPermissions.CMIS_ALL.value())) { // All operations allowed. return true; } return p.containsAll(permissions); } } return false; } }