/* * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH * under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright * ownership. Camunda licenses this file to you under the Apache License, * Version 2.0; you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.camunda.bpm.engine.impl.cfg.auth; import static org.camunda.bpm.engine.ProcessEngineConfiguration.HISTORY_REMOVAL_TIME_STRATEGY_START; import static org.camunda.bpm.engine.authorization.Authorization.AUTH_TYPE_GRANT; import static org.camunda.bpm.engine.authorization.Permissions.ALL; import static org.camunda.bpm.engine.authorization.Permissions.DELETE; import static org.camunda.bpm.engine.authorization.Permissions.READ; import static org.camunda.bpm.engine.authorization.Resources.DEPLOYMENT; import static org.camunda.bpm.engine.authorization.Resources.FILTER; import static org.camunda.bpm.engine.authorization.Resources.GROUP; import static org.camunda.bpm.engine.authorization.Resources.HISTORIC_TASK; import static org.camunda.bpm.engine.authorization.Resources.TASK; import static org.camunda.bpm.engine.authorization.Resources.TENANT; import static org.camunda.bpm.engine.authorization.Resources.USER; import static org.camunda.bpm.engine.impl.util.EnsureUtil.ensureValidIndividualResourceId; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.camunda.bpm.engine.IdentityService; import org.camunda.bpm.engine.authorization.HistoricTaskPermissions; import org.camunda.bpm.engine.authorization.Permission; import org.camunda.bpm.engine.authorization.Resource; import org.camunda.bpm.engine.authorization.TaskPermissions; import org.camunda.bpm.engine.delegate.DelegateTask; import org.camunda.bpm.engine.filter.Filter; import org.camunda.bpm.engine.identity.Group; import org.camunda.bpm.engine.identity.Tenant; import org.camunda.bpm.engine.identity.User; import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.camunda.bpm.engine.impl.context.Context; import org.camunda.bpm.engine.impl.db.entitymanager.DbEntityManager; import org.camunda.bpm.engine.impl.history.event.HistoricProcessInstanceEventEntity; import org.camunda.bpm.engine.impl.history.event.HistoryEvent; import org.camunda.bpm.engine.impl.identity.Authentication; import org.camunda.bpm.engine.impl.interceptor.CommandContext; import org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity; import org.camunda.bpm.engine.impl.persistence.entity.AuthorizationManager; import org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity; import org.camunda.bpm.engine.repository.DecisionDefinition; import org.camunda.bpm.engine.repository.DecisionRequirementsDefinition; import org.camunda.bpm.engine.repository.Deployment; import org.camunda.bpm.engine.repository.ProcessDefinition; import org.camunda.bpm.engine.runtime.ProcessInstance; import org.camunda.bpm.engine.task.Task; /** * <p>Provides the default authorizations for camunda BPM.</p> * * @author Daniel Meyer * */ public class DefaultAuthorizationProvider implements ResourceAuthorizationProvider { public AuthorizationEntity[] newUser(User user) { // create an authorization which gives the user all permissions on himself: String userId = user.getId(); ensureValidIndividualResourceId("Cannot create default authorization for user " + userId, userId); AuthorizationEntity resourceOwnerAuthorization = createGrantAuthorization(userId, null, USER, userId, ALL); return new AuthorizationEntity[]{ resourceOwnerAuthorization }; } public AuthorizationEntity[] newGroup(Group group) { List<AuthorizationEntity> authorizations = new ArrayList<AuthorizationEntity>(); // whenever a new group is created, all users part of the // group are granted READ permissions on the group String groupId = group.getId(); ensureValidIndividualResourceId("Cannot create default authorization for group " + groupId, groupId); AuthorizationEntity groupMemberAuthorization = createGrantAuthorization(null, groupId, GROUP, groupId, READ); authorizations.add(groupMemberAuthorization); return authorizations.toArray(new AuthorizationEntity[0]); } public AuthorizationEntity[] newTenant(Tenant tenant) { // no default authorizations on tenants. return null; } public AuthorizationEntity[] groupMembershipCreated(String groupId, String userId) { // no default authorizations on memberships. return null; } public AuthorizationEntity[] tenantMembershipCreated(Tenant tenant, User user) { AuthorizationEntity userAuthorization = createGrantAuthorization(user.getId(), null, TENANT, tenant.getId(), READ); return new AuthorizationEntity[]{ userAuthorization }; } public AuthorizationEntity[] tenantMembershipCreated(Tenant tenant, Group group) { AuthorizationEntity userAuthorization = createGrantAuthorization(null, group.getId(), TENANT, tenant.getId(), READ); return new AuthorizationEntity[]{ userAuthorization }; } public AuthorizationEntity[] newFilter(Filter filter) { String owner = filter.getOwner(); if(owner != null) { // create an authorization which gives the owner of the filter all permissions on the filter String filterId = filter.getId(); ensureValidIndividualResourceId("Cannot create default authorization for filter owner " + owner, owner); AuthorizationEntity filterOwnerAuthorization = createGrantAuthorization(owner, null, FILTER, filterId, ALL); return new AuthorizationEntity[]{ filterOwnerAuthorization }; } else { return null; } } // Deployment /////////////////////////////////////////////// public AuthorizationEntity[] newDeployment(Deployment deployment) { ProcessEngineConfigurationImpl processEngineConfiguration = Context.getProcessEngineConfiguration(); IdentityService identityService = processEngineConfiguration.getIdentityService(); Authentication currentAuthentication = identityService.getCurrentAuthentication(); if (currentAuthentication != null && currentAuthentication.getUserId() != null) { String userId = currentAuthentication.getUserId(); String deploymentId = deployment.getId(); AuthorizationEntity authorization = createGrantAuthorization(userId, null, DEPLOYMENT, deploymentId, READ, DELETE); return new AuthorizationEntity[]{ authorization }; } return null; } // Process Definition ////////////////////////////////////// public AuthorizationEntity[] newProcessDefinition(ProcessDefinition processDefinition) { // no default authorizations on process definitions. return null; } // Process Instance /////////////////////////////////////// public AuthorizationEntity[] newProcessInstance(ProcessInstance processInstance) { // no default authorizations on process instances. return null; } // Task ///////////////////////////////////////////////// public AuthorizationEntity[] newTask(Task task) { // no default authorizations on tasks. return null; } public AuthorizationEntity[] newTaskAssignee(Task task, String oldAssignee, String newAssignee) { if (newAssignee != null) { ensureValidIndividualResourceId("Cannot create default authorization for assignee " + newAssignee, newAssignee); // create (or update) an authorization for the new assignee. return createOrUpdateAuthorizationsByUserId(task, newAssignee); } return null; } public AuthorizationEntity[] newTaskOwner(Task task, String oldOwner, String newOwner) { if (newOwner != null) { ensureValidIndividualResourceId("Cannot create default authorization for owner " + newOwner, newOwner); // create (or update) an authorization for the new owner. return createOrUpdateAuthorizationsByUserId(task, newOwner); } return null; } public AuthorizationEntity[] newTaskUserIdentityLink(Task task, String userId, String type) { // create (or update) an authorization for the given user // whenever a new user identity link will be added ensureValidIndividualResourceId("Cannot grant default authorization for identity link to user " + userId, userId); return createOrUpdateAuthorizationsByUserId(task, userId); } public AuthorizationEntity[] newTaskGroupIdentityLink(Task task, String groupId, String type) { ensureValidIndividualResourceId("Cannot grant default authorization for identity link to group " + groupId, groupId); // create (or update) an authorization for the given group // whenever a new user identity link will be added return createOrUpdateAuthorizationsByGroupId(task, groupId); } public AuthorizationEntity[] deleteTaskUserIdentityLink(Task task, String userId, String type) { // an existing authorization will not be deleted in such a case return null; } public AuthorizationEntity[] deleteTaskGroupIdentityLink(Task task, String groupId, String type) { // an existing authorization will not be deleted in such a case return null; } public AuthorizationEntity[] newDecisionDefinition(DecisionDefinition decisionDefinition) { // no default authorizations on decision definitions. return null; } public AuthorizationEntity[] newDecisionRequirementsDefinition(DecisionRequirementsDefinition decisionRequirementsDefinition) { // no default authorizations on decision requirements definitions. return null; } // helper ////////////////////////////////////////////////////////////// protected AuthorizationEntity[] createOrUpdateAuthorizationsByGroupId(Task task, String groupId) { return createOrUpdateAuthorizations(task, groupId, null); } protected AuthorizationEntity[] createOrUpdateAuthorizationsByUserId(Task task, String userId) { return createOrUpdateAuthorizations(task, null, userId); } /** * (1) Fetch existing runtime & history authorizations * (2) Update authorizations: * (2a) fetched authorization == null * -> create a new runtime authorization (with READ, (UPDATE/TASK_WORK) permission, * and READ_VARIABLE if enabled) * -> create a new history authorization (with READ on HISTORIC_TASK) * (2b) fetched authorization != null * -> Add READ, (UPDATE/TASK_WORK) permission, and READ_VARIABLE if enabled * UPDATE or TASK_WORK permission is configurable in camunda.cfg.xml and by default, * UPDATE permission is provided * -> Add READ on HISTORIC_TASK */ protected AuthorizationEntity[] createOrUpdateAuthorizations(Task task, String groupId, String userId) { boolean enforceSpecificVariablePermission = isEnforceSpecificVariablePermission(); Permission[] runtimeTaskPermissions = getRuntimePermissions(enforceSpecificVariablePermission); AuthorizationEntity runtimeAuthorization = createOrUpdateAuthorization(task, userId, groupId, TASK, false, runtimeTaskPermissions); if (!isHistoricInstancePermissionsEnabled()) { return new AuthorizationEntity[]{ runtimeAuthorization }; } else { Permission[] historicTaskPermissions = getHistoricPermissions(enforceSpecificVariablePermission); AuthorizationEntity historyAuthorization = createOrUpdateAuthorization(task, userId, groupId, HISTORIC_TASK, true, historicTaskPermissions); return new AuthorizationEntity[]{ runtimeAuthorization, historyAuthorization }; } } protected AuthorizationEntity createOrUpdateAuthorization(Task task, String userId, String groupId, Resource resource, boolean isHistoric, Permission... permissions) { String taskId = task.getId(); AuthorizationEntity authorization = getGrantAuthorization(taskId, userId, groupId, resource); if (authorization == null) { authorization = createAuthorization(userId, groupId, resource, taskId, permissions); if (isHistoric) { provideRemovalTime(authorization, task); } } else { addPermissions(authorization, permissions); } return authorization; } protected void provideRemovalTime(AuthorizationEntity authorization, Task task) { String rootProcessInstanceId = getRootProcessInstanceId(task); if (rootProcessInstanceId != null) { authorization.setRootProcessInstanceId(rootProcessInstanceId); if (isHistoryRemovalTimeStrategyStart()) { HistoryEvent rootProcessInstance = findHistoricProcessInstance(rootProcessInstanceId); Date removalTime = null; if (rootProcessInstance != null) { removalTime = rootProcessInstance.getRemovalTime(); } authorization.setRemovalTime(removalTime); } } } protected String getRootProcessInstanceId(Task task) { ExecutionEntity execution = (ExecutionEntity) ((DelegateTask) task).getExecution(); if (execution != null) { return execution.getRootProcessInstanceId(); } else { return null; } } protected boolean isHistoryRemovalTimeStrategyStart() { return HISTORY_REMOVAL_TIME_STRATEGY_START.equals(getHistoryRemovalTimeStrategy()); } protected String getHistoryRemovalTimeStrategy() { return Context.getProcessEngineConfiguration() .getHistoryRemovalTimeStrategy(); } protected HistoryEvent findHistoricProcessInstance(String rootProcessInstanceId) { return Context.getCommandContext() .getDbEntityManager() .selectById(HistoricProcessInstanceEventEntity.class, rootProcessInstanceId); } protected Permission[] getHistoricPermissions(boolean enforceSpecificVariablePermission) { List<Permission> historicPermissions = new ArrayList<>(); historicPermissions.add(HistoricTaskPermissions.READ); if (enforceSpecificVariablePermission) { historicPermissions.add(HistoricTaskPermissions.READ_VARIABLE); } return historicPermissions.toArray(new Permission[0]); } protected Permission[] getRuntimePermissions(boolean enforceSpecificVariablePermission) { List<Permission> runtimePermissions = new ArrayList<>(); runtimePermissions.add(READ); Permission defaultUserPermissionForTask = getDefaultUserPermissionForTask(); runtimePermissions.add(defaultUserPermissionForTask); if (enforceSpecificVariablePermission) { runtimePermissions.add(TaskPermissions.READ_VARIABLE); } return runtimePermissions.toArray(new Permission[0]); } protected boolean isHistoricInstancePermissionsEnabled() { return Context.getProcessEngineConfiguration().isEnableHistoricInstancePermissions(); } protected AuthorizationManager getAuthorizationManager() { CommandContext commandContext = Context.getCommandContext(); return commandContext.getAuthorizationManager(); } protected AuthorizationEntity getGrantAuthorization(String taskId, String userId, String groupId, Resource resource) { if (groupId != null) { return getGrantAuthorizationByGroupId(groupId, resource, taskId); } else { return getGrantAuthorizationByUserId(userId, resource, taskId); } } protected AuthorizationEntity getGrantAuthorizationByUserId(String userId, Resource resource, String resourceId) { AuthorizationManager authorizationManager = getAuthorizationManager(); return authorizationManager.findAuthorizationByUserIdAndResourceId(AUTH_TYPE_GRANT, userId, resource, resourceId); } protected AuthorizationEntity getGrantAuthorizationByGroupId(String groupId, Resource resource, String resourceId) { AuthorizationManager authorizationManager = getAuthorizationManager(); return authorizationManager.findAuthorizationByGroupIdAndResourceId(AUTH_TYPE_GRANT, groupId, resource, resourceId); } protected AuthorizationEntity createAuthorization(String userId, String groupId, Resource resource, String resourceId, Permission... permissions) { AuthorizationEntity authorization = createGrantAuthorization(userId, groupId, resource, resourceId, permissions); updateAuthorizationBasedOnCacheEntries(authorization, userId, groupId, resource, resourceId); return authorization; } protected void addPermissions(AuthorizationEntity authorization, Permission... permissions) { if (permissions != null) { for (Permission permission : permissions) { if (permission != null) { authorization.addPermission(permission); } } } } protected AuthorizationEntity createGrantAuthorization(String userId, String groupId, Resource resource, String resourceId, Permission... permissions) { // assuming that there are no default authorizations for * if (userId != null) { ensureValidIndividualResourceId("Cannot create authorization for user " + userId, userId); } if (groupId != null) { ensureValidIndividualResourceId("Cannot create authorization for group " + groupId, groupId); } AuthorizationEntity authorization = new AuthorizationEntity(AUTH_TYPE_GRANT); authorization.setUserId(userId); authorization.setGroupId(groupId); authorization.setResource(resource); authorization.setResourceId(resourceId); addPermissions(authorization, permissions); return authorization; } protected Permission getDefaultUserPermissionForTask() { return Context .getProcessEngineConfiguration() .getDefaultUserPermissionForTask(); } protected boolean isEnforceSpecificVariablePermission() { return Context.getProcessEngineConfiguration() .isEnforceSpecificVariablePermission(); } /** * Searches through the cache, if there is already an authorization with same rights. If that's the case * update the given authorization with the permissions and remove the old one from the cache. */ protected void updateAuthorizationBasedOnCacheEntries(AuthorizationEntity authorization, String userId, String groupId, Resource resource, String resourceId) { DbEntityManager dbManager = Context.getCommandContext().getDbEntityManager(); List<AuthorizationEntity> list = dbManager.getCachedEntitiesByType(AuthorizationEntity.class); for (AuthorizationEntity authEntity : list) { boolean hasSameAuthRights = hasEntitySameAuthorizationRights(authEntity, userId, groupId, resource, resourceId); if (hasSameAuthRights) { int previousPermissions = authEntity.getPermissions(); authorization.setPermissions(previousPermissions); dbManager.getDbEntityCache().remove(authEntity); return; } } } protected boolean hasEntitySameAuthorizationRights(AuthorizationEntity authEntity, String userId, String groupId, Resource resource, String resourceId) { boolean sameUserId = areIdsEqual(authEntity.getUserId(), userId); boolean sameGroupId = areIdsEqual(authEntity.getGroupId(), groupId); boolean sameResourceId = areIdsEqual(authEntity.getResourceId(), (resourceId)); boolean sameResourceType = authEntity.getResourceType() == resource.resourceType(); boolean sameAuthorizationType = authEntity.getAuthorizationType() == AUTH_TYPE_GRANT; return sameUserId && sameGroupId && sameResourceType && sameResourceId && sameAuthorizationType; } protected boolean areIdsEqual(String firstId, String secondId) { if (firstId == null || secondId == null) { return firstId == secondId; }else { return firstId.equals(secondId); } } }