diff --git a/repository/src/main/java/org/alfresco/repo/workflow/activiti/script/ActivitiScriptBase.java b/repository/src/main/java/org/alfresco/repo/workflow/activiti/script/ActivitiScriptBase.java index 1dfee2d75f..1123ca1542 100644 --- a/repository/src/main/java/org/alfresco/repo/workflow/activiti/script/ActivitiScriptBase.java +++ b/repository/src/main/java/org/alfresco/repo/workflow/activiti/script/ActivitiScriptBase.java @@ -28,11 +28,17 @@ package org.alfresco.repo.workflow.activiti.script; import java.util.Map; +import org.activiti.engine.RepositoryService; import org.activiti.engine.delegate.VariableScope; import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.activiti.engine.impl.context.Context; import org.activiti.engine.impl.el.Expression; import org.activiti.engine.impl.persistence.entity.DeploymentEntity; +import org.activiti.engine.impl.persistence.entity.ExecutionEntity; +import org.activiti.engine.repository.ProcessDefinition; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.workflow.WorkflowDeployer; @@ -45,13 +51,12 @@ import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.workflow.WorkflowException; /** - * Base class for execution scripts, using {@link ScriptService} as part of - * activiti workflow. + * Base class for execution scripts, using {@link ScriptService} as part of activiti workflow. * * @author Frederik Heremans * @since 3.4.e */ -public class ActivitiScriptBase +public class ActivitiScriptBase { protected static final String PERSON_BINDING_NAME = "person"; protected static final String USERHOME_BINDING_NAME = "userhome"; @@ -61,17 +66,19 @@ public class ActivitiScriptBase protected Expression runAs; protected Expression scriptProcessor; + private static final Logger LOGGER = LoggerFactory.getLogger(ActivitiScriptBase.class); + protected Object executeScript(String theScript, Map model, String scriptProcessorName, String runAsUser) { String user = AuthenticationUtil.getFullyAuthenticatedUser(); - + Object scriptResult = null; if (runAsUser == null && user != null) { // Just execute the script using the current user scriptResult = executeScript(theScript, model, scriptProcessorName); } - else + else { if (runAsUser != null) { @@ -87,26 +94,25 @@ public class ActivitiScriptBase } return scriptResult; } - + protected Object executeScriptAsUser(final String theScript, final Map model, final String scriptProcessorName, final String runAsUser) { // execute as specified runAsUser - return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() - { + return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<>() { public Object doWork() throws Exception { return executeScript(theScript, model, scriptProcessorName); } }, runAsUser); } - + protected Object executeScript(String theScript, Map model, String scriptProcessorName) { // Execute the script using the appropriate processor Object scriptResult = null; // Checks if current workflow is secure - boolean secure = isSecure(); + boolean secure = isSecure(model); if (scriptProcessorName != null) { @@ -117,11 +123,11 @@ public class ActivitiScriptBase // Use default script-processor scriptResult = getServiceRegistry().getScriptService().executeScriptString(theScript, model, secure); } - + return scriptResult; } - - protected String getStringValue(Expression expression, VariableScope scope) + + protected String getStringValue(Expression expression, VariableScope scope) { if (expression != null) { @@ -133,15 +139,15 @@ public class ActivitiScriptBase protected ServiceRegistry getServiceRegistry() { ProcessEngineConfigurationImpl config = Context.getProcessEngineConfiguration(); - if (config != null) + if (config != null) { // Fetch the registry that is injected in the activiti spring-configuration ServiceRegistry registry = (ServiceRegistry) config.getBeans().get(ActivitiConstants.SERVICE_REGISTRY_BEAN_KEY); if (registry == null) { throw new RuntimeException( - "Service-registry not present in ProcessEngineConfiguration beans, expected ServiceRegistry with key" + - ActivitiConstants.SERVICE_REGISTRY_BEAN_KEY); + "Service-registry not present in ProcessEngineConfiguration beans, expected ServiceRegistry with key" + + ActivitiConstants.SERVICE_REGISTRY_BEAN_KEY); } return registry; } @@ -149,42 +155,136 @@ public class ActivitiScriptBase } /** - * Checks whether the workflow must be considered secure or not - based on {@link DeploymentEntity} category. - * If it is not considered secure, the workflow will be executed in sandbox context with more restrictions + * Checks whether the workflow must be considered secure or not - based on {@link DeploymentEntity} category. If it is not considered secure, the workflow will be executed in sandbox context with more restrictions * * @return true if workflow is considered secure, false otherwise */ - private boolean isSecure() + private boolean isSecure(Map model) + { + String category = getDeploymentCategory(model); + + // iF The deployment category matches the condition (either internal or full access) the workflow is considered secure + return category != null && (WorkflowDeployer.CATEGORY_ALFRESCO_INTERNAL.equals(category) || WorkflowDeployer.CATEGORY_FULL_ACCESS.equals(category)); + } + + /** + * Gets the deployment category from the execution context. If no execution context is available, a query to obtain the deployment is performed so the category can be returned. + * + * @param model + * a map with workflow model + * @return the deployment category + */ + private String getDeploymentCategory(Map model) + { + String category = getDeploymentCategoryFromContext(); + + if (category == null) + { + String deploymentId = null; + String processDefinitionId = null; + + if (model != null && model.containsKey(EXECUTION_BINDING_NAME) && model.get(EXECUTION_BINDING_NAME) instanceof ExecutionEntity) + { + ExecutionEntity executionEntity = (ExecutionEntity) model.get(EXECUTION_BINDING_NAME); + deploymentId = executionEntity.getDeploymentId(); + processDefinitionId = executionEntity.getProcessDefinitionId(); + } + + category = getDeploymentCategoryFromQuery(deploymentId, processDefinitionId); + } + + return category; + } + + /** + * Obtains the deployment category from current execution context + * + * @return the category for current execution deployment, otherwise null + */ + private String getDeploymentCategoryFromContext() { String category = null; - try { if (Context.isExecutionContextActive()) { category = Context.getExecutionContext().getDeployment().getCategory(); } + else + { + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug("No execution context available"); + } + } } catch (Exception e) { - // No action required + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug("Could not obtain deployment category from execution context: {}", e.getMessage()); + } } - // If the workflow is considered secure, the deployment entity category matches the condition (either internal or full access) - return category != null && (WorkflowDeployer.CATEGORY_ALFRESCO_INTERNAL.equals(category) || WorkflowDeployer.CATEGORY_FULL_ACCESS.equals(category)); + return category; } /** - * Checks that the specified 'runAs' field - * specifies a valid username. + * Obtains the deployment category through a query + * + * @param deploymentId + * the deployment id to obtain the category from + * @param processDefinitionId + * if no deployment id is provided, the process definition id can be used to obtain the deployment + * @return the category for the obtained deployment, otherwise null */ - private void validateRunAsUser(final String runAsUser) + private String getDeploymentCategoryFromQuery(String deploymentId, String processDefinitionId) { - Boolean runAsExists = AuthenticationUtil.runAs(new RunAsWork() + String category = null; + + try { + RepositoryService repositoryService = Context.getProcessEngineConfiguration().getRepositoryService(); + + if (deploymentId == null && processDefinitionId != null) + { + ProcessDefinition processDefnition = repositoryService.getProcessDefinition(processDefinitionId); + if (processDefnition != null) + { + deploymentId = processDefnition.getDeploymentId(); + } + } + + if (deploymentId != null) + { + DeploymentEntity deployment = (DeploymentEntity) repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult(); + if (deployment != null) + { + category = deployment.getCategory(); + } + } + } + catch (Exception e) + { + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug("Could not obtain deployment category through a query: {}", e.getMessage()); + } + } + + return category; + } + + /** + * Checks that the specified 'runAs' field specifies a valid username. + */ + private void validateRunAsUser(final String runAsUser) + { + Boolean runAsExists = AuthenticationUtil.runAs(new RunAsWork<>() { // Validate using System user to ensure sufficient permissions available to access person node. - public Boolean doWork() throws Exception + @Override + public Boolean doWork() throws Exception { return getServiceRegistry().getPersonService().personExists(runAsUser); } @@ -195,21 +295,21 @@ public class ActivitiScriptBase throw new WorkflowException("runas user '" + runAsUser + "' does not exist."); } } - + protected ActivitiScriptNode getPersonNode(String runAsUser) { String userName = null; - if (runAsUser != null) + if (runAsUser != null) { userName = runAsUser; } - else + else { userName = AuthenticationUtil.getFullyAuthenticatedUser(); } - + // The "System" user is a special case, which has no person object associated with it. - if(userName != null && !AuthenticationUtil.SYSTEM_USER_NAME.equals(userName)) + if (userName != null && !AuthenticationUtil.SYSTEM_USER_NAME.equals(userName)) { ServiceRegistry services = getServiceRegistry(); PersonService personService = services.getPersonService(); @@ -221,18 +321,18 @@ public class ActivitiScriptBase } return null; } - - public void setScript(Expression script) + + public void setScript(Expression script) { this.script = script; } - public void setRunAs(Expression runAs) + public void setRunAs(Expression runAs) { this.runAs = runAs; } - public void setScriptProcessor(Expression scriptProcessor) + public void setScriptProcessor(Expression scriptProcessor) { this.scriptProcessor = scriptProcessor; }