mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
[MNT-21638] Script task execution (#1210)
* [MNT-21638] Script task execution based on workflow deloyment category. Javadoc. Unit tests.
This commit is contained in:
@@ -35,10 +35,11 @@ public class GetDeploymentsSanityTests extends RestTest
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
deployments.assertThat().entriesListIsNotEmpty();
|
||||
deployments.getOneRandomEntry().onModel().assertThat()
|
||||
.fieldsCount().is(3).and()
|
||||
.fieldsCount().is(4).and()
|
||||
.field("id").isNotEmpty().and()
|
||||
.field("deployedAt").isNotEmpty().and()
|
||||
.field("name").isNotEmpty();
|
||||
.field("name").isNotEmpty().and()
|
||||
.field("category").isNotEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -38,6 +38,7 @@ import java.util.Map;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.tenant.TenantUtil;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.workflow.WorkflowDeployer;
|
||||
import org.alfresco.rest.api.tests.AbstractTestFixture;
|
||||
import org.alfresco.rest.api.tests.RepoService.TestNetwork;
|
||||
import org.alfresco.rest.api.tests.client.PublicApiClient.ListResponse;
|
||||
@@ -128,7 +129,7 @@ public class DeploymentWorkflowApiTest extends EnterpriseWorkflowTestApi
|
||||
Deployment adhocDeployment = deploymentMap.get("adhoc.bpmn20.xml");
|
||||
|
||||
assertEquals(activitiDeployment.getId(), adhocDeployment.getId());
|
||||
assertEquals(activitiDeployment.getCategory(), adhocDeployment.getCategory());
|
||||
assertEquals(activitiDeployment.getCategory(), WorkflowDeployer.CATEGORY_FULL_ACCESS);
|
||||
assertEquals(activitiDeployment.getName(), adhocDeployment.getName());
|
||||
assertEquals(activitiDeployment.getDeploymentTime(), adhocDeployment.getDeployedAt());
|
||||
|
||||
@@ -251,7 +252,7 @@ public class DeploymentWorkflowApiTest extends EnterpriseWorkflowTestApi
|
||||
assertNotNull(deployment);
|
||||
|
||||
assertEquals(activitiDeployment.getId(), deployment.getId());
|
||||
assertEquals(activitiDeployment.getCategory(), deployment.getCategory());
|
||||
assertEquals(activitiDeployment.getCategory(), WorkflowDeployer.CATEGORY_FULL_ACCESS);
|
||||
assertEquals(activitiDeployment.getName(), deployment.getName());
|
||||
assertEquals(activitiDeployment.getDeploymentTime(), deployment.getDeployedAt());
|
||||
|
||||
|
@@ -270,25 +270,33 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
|
||||
*/
|
||||
public Object executeString(String source, Map<String, Object> model)
|
||||
{
|
||||
try
|
||||
{
|
||||
// compile the script based on the node content
|
||||
Script script;
|
||||
Context cx = Context.enter();
|
||||
try
|
||||
{
|
||||
script = cx.compileString(resolveScriptImports(source), "AlfrescoJS", 1, null);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Context.exit();
|
||||
}
|
||||
return executeScriptImpl(script, model, true, "string script");
|
||||
}
|
||||
catch (Throwable err)
|
||||
{
|
||||
throw new ScriptException("Failed to execute supplied script: " + err.getMessage(), err);
|
||||
}
|
||||
return executeString(source, model, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.repository.ScriptProcessor#executeString(java.lang.String, java.util.Map, boolean)
|
||||
*/
|
||||
public Object executeString(String source, Map<String, Object> model, boolean secure)
|
||||
{
|
||||
try
|
||||
{
|
||||
// compile the script based on the node content
|
||||
Script script;
|
||||
Context cx = Context.enter();
|
||||
try
|
||||
{
|
||||
script = cx.compileString(resolveScriptImports(source), "AlfrescoJS", 1, null);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Context.exit();
|
||||
}
|
||||
return executeScriptImpl(script, model, secure, "string script");
|
||||
}
|
||||
catch (Throwable err)
|
||||
{
|
||||
throw new ScriptException("Failed to execute supplied script: " + err.getMessage(), err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -188,6 +188,15 @@ public class ScriptServiceImpl implements ScriptService
|
||||
throws ScriptException
|
||||
{
|
||||
return executeScriptString(this.defaultScriptProcessor, script, model);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.repository.ScriptService#executeScriptString(java.lang.String, java.util.Map, boolean)
|
||||
*/
|
||||
public Object executeScriptString(String script, Map<String, Object> model, boolean secure)
|
||||
throws ScriptException
|
||||
{
|
||||
return executeScriptString(this.defaultScriptProcessor, script, model, secure);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,12 +206,23 @@ public class ScriptServiceImpl implements ScriptService
|
||||
throws ScriptException
|
||||
{
|
||||
ScriptProcessor scriptProcessor = lookupScriptProcessor(engine);
|
||||
return executeString(scriptProcessor, script, model);
|
||||
}
|
||||
return executeString(scriptProcessor, script, model, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.repository.ScriptService#executeScriptString(java.lang.String, java.util.Map, boolean)
|
||||
*/
|
||||
public Object executeScriptString(String engine, String script, Map<String, Object> model, boolean secure)
|
||||
throws ScriptException
|
||||
{
|
||||
ScriptProcessor scriptProcessor = lookupScriptProcessor(engine);
|
||||
return executeString(scriptProcessor, script, model, secure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute script
|
||||
*
|
||||
*
|
||||
* @param processor the script processor that will be responsible for supplied script execution
|
||||
* @param location the location of the script
|
||||
* @param model context model
|
||||
* @return Object the result of the script
|
||||
@@ -227,6 +247,7 @@ public class ScriptServiceImpl implements ScriptService
|
||||
/**
|
||||
* Execute script
|
||||
*
|
||||
* @param processor the script processor that will be responsible for supplied script execution
|
||||
* @param scriptRef the script node reference
|
||||
* @param contentProp the content property of the script
|
||||
* @param model the context model
|
||||
@@ -251,7 +272,8 @@ public class ScriptServiceImpl implements ScriptService
|
||||
|
||||
/**
|
||||
* Execute script
|
||||
*
|
||||
*
|
||||
* @param processor the script processor that will be responsible for supplied script execution
|
||||
* @param location the classpath string locating the script
|
||||
* @param model the context model
|
||||
* @return Object the result of the script
|
||||
@@ -275,12 +297,15 @@ public class ScriptServiceImpl implements ScriptService
|
||||
|
||||
/**
|
||||
* Execute script string
|
||||
*
|
||||
*
|
||||
* @param processor the script processor that will be responsible for supplied script execution
|
||||
* @param script the script string
|
||||
* @param model the context model
|
||||
* @param model the context model
|
||||
* @param secure the flag indicating if string script is considered secure (e.g., if it comes from classpath)
|
||||
* if true it will have access to the full execution context, if false the script will be executed in a sandbox context
|
||||
* @return Object the result of the script
|
||||
*/
|
||||
protected Object executeString(ScriptProcessor processor, String script, Map<String, Object> model)
|
||||
protected Object executeString(ScriptProcessor processor, String script, Map<String, Object> model, boolean secure)
|
||||
{
|
||||
ParameterCheck.mandatoryString("script", script);
|
||||
|
||||
@@ -290,7 +315,7 @@ public class ScriptServiceImpl implements ScriptService
|
||||
}
|
||||
try
|
||||
{
|
||||
return processor.executeString(script, model);
|
||||
return processor.executeString(script, model, secure);
|
||||
}
|
||||
catch (Throwable err)
|
||||
{
|
||||
|
@@ -74,6 +74,18 @@ public interface WorkflowComponent
|
||||
* @since 4.0
|
||||
*/
|
||||
public WorkflowDeployment deployDefinition(InputStream workflowDefinition, String mimetype, String name);
|
||||
|
||||
/**
|
||||
* Deploy a Workflow Definition
|
||||
*
|
||||
* @param workflowDefinition the content object containing the definition
|
||||
* @param mimetype (optional) the mime type of the workflow definition
|
||||
* @param name (optional) a name to represent the deployment
|
||||
* @param fullAccess true if category should be defined in order to consider the deployment secure
|
||||
* @return workflow deployment descriptor
|
||||
* @since 4.0
|
||||
*/
|
||||
public WorkflowDeployment deployDefinition(InputStream workflowDefinition, String mimetype, String name, boolean fullAccess);
|
||||
|
||||
/**
|
||||
* Is the specified Workflow Definition already deployed?
|
||||
@@ -86,7 +98,14 @@ public interface WorkflowComponent
|
||||
* @return true => already deployed
|
||||
*/
|
||||
public boolean isDefinitionDeployed(InputStream workflowDefinition, String mimetype);
|
||||
|
||||
|
||||
/**
|
||||
* Sets the deployment category if applicable to allow the workflow to have full access
|
||||
*
|
||||
* @param workflowDefinition the definition to check
|
||||
*/
|
||||
public void checkDeploymentCategory(InputStream workflowDefinition);
|
||||
|
||||
/**
|
||||
* Undeploy an exisiting Workflow Definition
|
||||
*
|
||||
|
@@ -85,6 +85,7 @@ public class WorkflowDeployer extends AbstractLifecycleBean
|
||||
public static final String REDEPLOY = "redeploy";
|
||||
|
||||
public static final String CATEGORY_ALFRESCO_INTERNAL = "http://alfresco.org/workflows/internal";
|
||||
public static final String CATEGORY_FULL_ACCESS = "http://alfresco.org/workflows/fullAccess";
|
||||
|
||||
// Dependencies
|
||||
private TransactionService transactionService;
|
||||
@@ -306,12 +307,14 @@ public class WorkflowDeployer extends AbstractLifecycleBean
|
||||
if (!redeploy && workflowService.isDefinitionDeployed(engineId, workflowResource.getInputStream(), mimetype))
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Workflow deployer: Definition '" + location + "' already deployed");
|
||||
{
|
||||
logger.debug("Workflow deployer: Definition '" + location + "' already deployed. Checking deploymentcategory...");
|
||||
}
|
||||
workflowService.checkDeploymentCategory(engineId, workflowResource.getInputStream());
|
||||
}
|
||||
else
|
||||
{
|
||||
WorkflowDeployment deployment = workflowService.deployDefinition(engineId, workflowResource.getInputStream(),
|
||||
mimetype, workflowResource.getFilename());
|
||||
WorkflowDeployment deployment = workflowService.deployDefinition(engineId, workflowResource.getInputStream(), mimetype, workflowResource.getFilename(), true);
|
||||
logDeployment(location, deployment);
|
||||
}
|
||||
}
|
||||
|
@@ -232,9 +232,20 @@ public class WorkflowServiceImpl implements WorkflowService
|
||||
* .lang.String, java.io.InputStream, java.lang.String, java.lang.String)
|
||||
*/
|
||||
public WorkflowDeployment deployDefinition(String engineId, InputStream workflowDefinition, String mimetype, String name)
|
||||
{
|
||||
return deployDefinition(engineId, workflowDefinition, mimetype, name, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see
|
||||
* org.alfresco.service.cmr.workflow.WorkflowService#deployDefinition(java
|
||||
* .lang.String, java.io.InputStream, java.lang.String, java.lang.String, boolean)
|
||||
*/
|
||||
public WorkflowDeployment deployDefinition(String engineId, InputStream workflowDefinition, String mimetype, String name, boolean fullAccess)
|
||||
{
|
||||
WorkflowComponent component = getWorkflowComponent(engineId);
|
||||
WorkflowDeployment deployment = component.deployDefinition(workflowDefinition, mimetype, name);
|
||||
WorkflowDeployment deployment = component.deployDefinition(workflowDefinition, mimetype, name, fullAccess);
|
||||
|
||||
if (logger.isDebugEnabled() && deployment.getProblems().length > 0)
|
||||
{
|
||||
@@ -277,6 +288,18 @@ public class WorkflowServiceImpl implements WorkflowService
|
||||
return component.isDefinitionDeployed(workflowDefinition, mimetype);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see
|
||||
* org.alfresco.service.cmr.workflow.WorkflowService#checkDeploymentCategory
|
||||
* (java.lang.String, java.io.InputStream)
|
||||
*/
|
||||
public void checkDeploymentCategory(String engineId, InputStream workflowDefinition)
|
||||
{
|
||||
WorkflowComponent component = getWorkflowComponent(engineId);
|
||||
component.checkDeploymentCategory(workflowDefinition);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see
|
||||
|
@@ -1,28 +1,28 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
package org.alfresco.repo.workflow.activiti;
|
||||
|
||||
@@ -242,45 +242,45 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public WorkflowInstance cancelWorkflow(String workflowId)
|
||||
{
|
||||
String localId = createLocalId(workflowId);
|
||||
try
|
||||
{
|
||||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(localId).singleResult();
|
||||
if (processInstance == null)
|
||||
{
|
||||
throw new WorkflowException(messageService.getMessage(ERR_CANCEL_UNEXISTING_WORKFLOW));
|
||||
}
|
||||
|
||||
// TODO: Cancel VS delete?
|
||||
// Delete the process instance
|
||||
runtimeService.deleteProcessInstance(processInstance.getId(), WorkflowConstants.PROP_CANCELLED);
|
||||
|
||||
// Convert historic process instance
|
||||
HistoricProcessInstance deletedInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstance.getId())
|
||||
.singleResult();
|
||||
WorkflowInstance result = typeConverter.convert(deletedInstance);
|
||||
|
||||
// Delete the historic process instance
|
||||
// MNT-15498
|
||||
if (!activitiUtil.isRetentionHistoricProcessInstanceEnabled())
|
||||
{
|
||||
historyService.deleteHistoricProcessInstance(deletedInstance.getId());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (ActivitiException ae)
|
||||
{
|
||||
String msg = messageService.getMessage(ERR_CANCEL_WORKFLOW);
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(msg, ae);
|
||||
}
|
||||
throw new WorkflowException(msg, ae);
|
||||
}
|
||||
}
|
||||
public WorkflowInstance cancelWorkflow(String workflowId)
|
||||
{
|
||||
String localId = createLocalId(workflowId);
|
||||
try
|
||||
{
|
||||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(localId).singleResult();
|
||||
if (processInstance == null)
|
||||
{
|
||||
throw new WorkflowException(messageService.getMessage(ERR_CANCEL_UNEXISTING_WORKFLOW));
|
||||
}
|
||||
|
||||
// TODO: Cancel VS delete?
|
||||
// Delete the process instance
|
||||
runtimeService.deleteProcessInstance(processInstance.getId(), WorkflowConstants.PROP_CANCELLED);
|
||||
|
||||
// Convert historic process instance
|
||||
HistoricProcessInstance deletedInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstance.getId())
|
||||
.singleResult();
|
||||
WorkflowInstance result = typeConverter.convert(deletedInstance);
|
||||
|
||||
// Delete the historic process instance
|
||||
// MNT-15498
|
||||
if (!activitiUtil.isRetentionHistoricProcessInstanceEnabled())
|
||||
{
|
||||
historyService.deleteHistoricProcessInstance(deletedInstance.getId());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (ActivitiException ae)
|
||||
{
|
||||
String msg = messageService.getMessage(ERR_CANCEL_WORKFLOW);
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(msg, ae);
|
||||
}
|
||||
throw new WorkflowException(msg, ae);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
@@ -336,6 +336,14 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public WorkflowDeployment deployDefinition(InputStream workflowDefinition, String mimetype, String name)
|
||||
{
|
||||
return deployDefinition(workflowDefinition, mimetype, name, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public WorkflowDeployment deployDefinition(InputStream workflowDefinition, String mimetype, String name, boolean fullAccess)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -363,6 +371,10 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
|
||||
{
|
||||
repoService.setDeploymentCategory(deployment.getId(), WorkflowDeployer.CATEGORY_ALFRESCO_INTERNAL);
|
||||
}
|
||||
else if (fullAccess)
|
||||
{
|
||||
repoService.setDeploymentCategory(deployment.getId(), WorkflowDeployer.CATEGORY_FULL_ACCESS);
|
||||
}
|
||||
}
|
||||
|
||||
// No problems can be added to the WorkflowDeployment, warnings are
|
||||
@@ -1005,6 +1017,46 @@ public class ActivitiWorkflowEngine extends BPMEngine implements WorkflowEngine
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void checkDeploymentCategory(InputStream workflowDefinition)
|
||||
{
|
||||
try
|
||||
{
|
||||
String key = getProcessKey(workflowDefinition);
|
||||
ProcessDefinition pd = activitiUtil.getProcessDefinitionByKey(key);
|
||||
String deploymentId = pd.getDeploymentId();
|
||||
|
||||
List<ProcessDefinition> definitionList = repoService.createProcessDefinitionQuery().deploymentId(deploymentId).list();
|
||||
if (definitionList != null && definitionList.size() > 0)
|
||||
{
|
||||
boolean internalCategory = true;
|
||||
for (ProcessDefinition processDefinition : definitionList)
|
||||
{
|
||||
if (WorkflowDeployer.CATEGORY_ALFRESCO_INTERNAL.equals(processDefinition.getCategory()) == false)
|
||||
{
|
||||
internalCategory = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!internalCategory)
|
||||
{
|
||||
repoService.setDeploymentCategory(deploymentId, WorkflowDeployer.CATEGORY_FULL_ACCESS);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Category was not set: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getProcessKey(InputStream workflowDefinition) throws Exception
|
||||
{
|
||||
try
|
||||
|
@@ -32,8 +32,10 @@ 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.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.workflow.WorkflowDeployer;
|
||||
import org.alfresco.repo.workflow.activiti.ActivitiConstants;
|
||||
import org.alfresco.repo.workflow.activiti.ActivitiScriptNode;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
@@ -102,14 +104,18 @@ public class ActivitiScriptBase
|
||||
{
|
||||
// Execute the script using the appropriate processor
|
||||
Object scriptResult = null;
|
||||
|
||||
// Checks if current workflow is secure
|
||||
boolean secure = isSecure();
|
||||
|
||||
if (scriptProcessorName != null)
|
||||
{
|
||||
scriptResult = getServiceRegistry().getScriptService().executeScriptString(scriptProcessorName, theScript, model);
|
||||
scriptResult = getServiceRegistry().getScriptService().executeScriptString(scriptProcessorName, theScript, model, secure);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use default script-processor
|
||||
scriptResult = getServiceRegistry().getScriptService().executeScriptString(theScript, model);
|
||||
scriptResult = getServiceRegistry().getScriptService().executeScriptString(theScript, model, secure);
|
||||
}
|
||||
|
||||
return scriptResult;
|
||||
@@ -142,6 +148,32 @@ public class ActivitiScriptBase
|
||||
throw new IllegalStateException("No ProcessEngineCOnfiguration found in active context");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
String category = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (Context.isExecutionContextActive())
|
||||
{
|
||||
category = Context.getExecutionContext().getDeployment().getCategory();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// No action required
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the specified 'runAs' field
|
||||
* specifies a valid username.
|
||||
|
@@ -70,10 +70,21 @@ public interface ScriptProcessor extends Processor
|
||||
*
|
||||
* @param script the script string
|
||||
* @param model the context model
|
||||
* @return Obejct the result of the script
|
||||
* @return Object the result of the script
|
||||
*/
|
||||
public Object executeString(String script, Map<String, Object> model);
|
||||
|
||||
|
||||
/**
|
||||
* Execute script string
|
||||
*
|
||||
* @param script the script string
|
||||
* @param model the context model
|
||||
* @param secure the flag that indicates if string is considered secure to be executed, i.e., it will have
|
||||
* access to the full execution context instead of being executed in a sandbox context
|
||||
* @return Object the result of the script
|
||||
*/
|
||||
public Object executeString(String script, Map<String, Object> model, boolean secure);
|
||||
|
||||
/**
|
||||
* Reset the processor - such as clearing any internal caches etc.
|
||||
*/
|
||||
|
@@ -160,7 +160,22 @@ public interface ScriptService
|
||||
@Auditable(parameters = {"script", "model"})
|
||||
public Object executeScriptString(String script, Map<String, Object> model)
|
||||
throws ScriptException;
|
||||
|
||||
|
||||
/**
|
||||
* Process a script against the supplied data model. Uses the default script engine.
|
||||
*
|
||||
* @param script Script content as a String.
|
||||
* @param model Object model to process script against
|
||||
* @param secure A flag indicating if string script is considered secure (e.g., if it comes from the classpath)
|
||||
* If true it will have access to the full execution context, if false the script will be executed in a sandbox context (more restricted)
|
||||
* @return output of the script (may be null or any valid wrapped JavaScript object)
|
||||
*
|
||||
* @throws ScriptException
|
||||
*/
|
||||
@Auditable(parameters = {"script", "model", "secure"})
|
||||
public Object executeScriptString(String script, Map<String, Object> model, boolean secure)
|
||||
throws ScriptException;
|
||||
|
||||
/**
|
||||
* Process a script against the supplied data model.
|
||||
*
|
||||
@@ -175,7 +190,23 @@ public interface ScriptService
|
||||
@Auditable(parameters = {"engine", "script", "model"})
|
||||
public Object executeScriptString(String engine, String script, Map<String, Object> model)
|
||||
throws ScriptException;
|
||||
|
||||
|
||||
/**
|
||||
* Process a script against the supplied data model.
|
||||
*
|
||||
* @param engine the script engine to use
|
||||
* @param script Script content as a String.
|
||||
* @param model Object model to process script against
|
||||
* @param secure A flag indicating if string script is considered secure
|
||||
*
|
||||
* @return output of the script (may be null or any valid wrapped JavaScript object)
|
||||
*
|
||||
* @throws ScriptException
|
||||
*/
|
||||
@Auditable(parameters = {"engine", "script", "model", "secure"})
|
||||
public Object executeScriptString(String engine, String script, Map<String, Object> model, boolean secure)
|
||||
throws ScriptException;
|
||||
|
||||
/**
|
||||
* Registers a script processor with the script service
|
||||
*
|
||||
|
@@ -77,7 +77,24 @@ public interface WorkflowService
|
||||
parameters = {"engineId", "workflowDefinition", "mimetype", "name"},
|
||||
recordable = {true, false, true, true})
|
||||
public WorkflowDeployment deployDefinition(String engineId, InputStream workflowDefinition, String mimetype, String name);
|
||||
|
||||
|
||||
/**
|
||||
* Deploy a Workflow Definition to the Alfresco Repository
|
||||
*
|
||||
* @param engineId the bpm engine id
|
||||
* @param workflowDefinition the workflow definition
|
||||
* @param mimetype the mimetype of the workflow definition
|
||||
* @param name a name representing the deployment
|
||||
* @parm fullAccess true if workflow should be considered secure (e.g., if it is deployed in classpath) and should have full access to the execution context,
|
||||
* false if it should be executed in a sandbox context (more restricted)
|
||||
* @return workflow deployment descriptor
|
||||
* @since 4.0
|
||||
*/
|
||||
@Auditable(
|
||||
parameters = {"engineId", "workflowDefinition", "mimetype", "name", "fullAccess"},
|
||||
recordable = {true, false, true, true, true})
|
||||
public WorkflowDeployment deployDefinition(String engineId, InputStream workflowDefinition, String mimetype, String name, boolean fullAccess);
|
||||
|
||||
/**
|
||||
* Deploy a Workflow Definition to the Alfresco Repository
|
||||
*
|
||||
@@ -117,6 +134,17 @@ public interface WorkflowService
|
||||
parameters = {"engineId", "workflowDefinition", "mimetype"},
|
||||
recordable = {true, false, true})
|
||||
public boolean isDefinitionDeployed(String engineId, InputStream workflowDefinition, String mimetype);
|
||||
|
||||
/**
|
||||
* Checks if the deployment for supplied workflow definition has the proper category
|
||||
*
|
||||
* @param engineId the bpm engine id
|
||||
* @param workflowDefinition the definition to check
|
||||
*/
|
||||
@Auditable(
|
||||
parameters = {"engineId", "workflowDefinition"},
|
||||
recordable = {true, false})
|
||||
public void checkDeploymentCategory(String engineId, InputStream workflowDefinition);
|
||||
|
||||
/**
|
||||
* Undeploy an exisiting Workflow Definition
|
||||
|
@@ -25,42 +25,39 @@
|
||||
*/
|
||||
package org.alfresco.repo.jscript;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.dictionary.DictionaryComponent;
|
||||
import org.alfresco.repo.dictionary.DictionaryDAO;
|
||||
import org.alfresco.repo.dictionary.M2Model;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.dictionary.DictionaryComponent;
|
||||
import org.alfresco.repo.dictionary.DictionaryDAO;
|
||||
import org.alfresco.repo.dictionary.M2Model;
|
||||
import org.alfresco.repo.node.BaseNodeServiceTest;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.repo.security.permissions.AccessDeniedException;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.ScriptService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.ScriptProcessor;
|
||||
import org.alfresco.service.cmr.repository.ScriptService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.test_category.OwnJVMTestsCategory;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
import org.mozilla.javascript.ScriptableObject;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
import org.mozilla.javascript.ScriptableObject;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
|
||||
/**
|
||||
@@ -434,7 +431,51 @@ public class RhinoScriptTest extends TestCase
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
// MNT-21638
|
||||
public void testSecureScriptString()
|
||||
{
|
||||
boolean executed = executeSecureScriptString(TESTSCRIPT2, false);
|
||||
assertFalse("Script shouldn't have been executed (secure = false)", executed);
|
||||
|
||||
executed = executeSecureScriptString(TESTSCRIPT2, null);
|
||||
assertFalse("Script shouldn't have been executed (secure = null)", executed);
|
||||
|
||||
executed = executeSecureScriptString(TESTSCRIPT2, true);
|
||||
assertTrue("Script should have been executed (secure = true)", executed);
|
||||
}
|
||||
|
||||
private boolean executeSecureScriptString(String script, Boolean secure)
|
||||
{
|
||||
return transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Boolean>()
|
||||
{
|
||||
public Boolean execute() throws Exception
|
||||
{
|
||||
StoreRef store = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "rhino_" + System.currentTimeMillis());
|
||||
NodeRef root = nodeService.getRootNode(store);
|
||||
BaseNodeServiceTest.buildNodeGraph(nodeService, root);
|
||||
|
||||
try
|
||||
{
|
||||
Map<String, Object> model = new HashMap<String, Object>();
|
||||
model.put("out", System.out);
|
||||
|
||||
ScriptNode rootNode = new ScriptNode(root, serviceRegistry, null);
|
||||
model.put("root", rootNode);
|
||||
|
||||
// test executing a script directly as string
|
||||
scriptService.executeScriptString("javascript", script, model, secure);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static final String TESTSCRIPT_CLASSPATH1 = "org/alfresco/repo/jscript/test_script1.js";
|
||||
private static final String TESTSCRIPT_CLASSPATH2 = "org/alfresco/repo/jscript/test_script2.js";
|
||||
private static final String TESTSCRIPT_CLASSPATH3 = "org/alfresco/repo/jscript/test_script3.js";
|
||||
@@ -453,7 +494,12 @@ public class RhinoScriptTest extends TestCase
|
||||
"logger.log(\"child by name path: \" + childByNameNode.name);\r\n" +
|
||||
"var xpathResults = root.childrenByXPath(\"/*\");\r\n" +
|
||||
"logger.log(\"children of root from xpath: \" + xpathResults.length);\r\n";
|
||||
|
||||
|
||||
private static final String TESTSCRIPT2 = "var exec = new org.alfresco.util.exec.RuntimeExec();\r\n"
|
||||
+ "exec.setCommand([\"/bin/ls\"]);\r\n"
|
||||
+ "var res = exec.execute();\r\n"
|
||||
+ "java.lang.System.err.println(res.getStdOut());\r\n";
|
||||
|
||||
private static final String BASIC_JAVA =
|
||||
"var list = com.google.common.collect.Lists.newArrayList();\n" +
|
||||
"root.nodeRef.getClass().forName(\"java.lang.ProcessBuilder\")";
|
||||
|
@@ -1247,7 +1247,15 @@ public abstract class AbstractWorkflowServiceIntegrationTest extends BaseSpringT
|
||||
WorkflowDefinition definition = deployment.getDefinition();
|
||||
return definition;
|
||||
}
|
||||
|
||||
|
||||
protected WorkflowDefinition deployDefinition(String resource, String name, boolean fullAccess)
|
||||
{
|
||||
InputStream input = getInputStream(resource);
|
||||
WorkflowDeployment deployment = workflowService.deployDefinition(getEngine(), input, XML, name, fullAccess);
|
||||
WorkflowDefinition definition = deployment.getDefinition();
|
||||
return definition;
|
||||
}
|
||||
|
||||
protected abstract QName getAdhocProcessName();
|
||||
|
||||
|
||||
|
@@ -790,6 +790,45 @@ public class ActivitiWorkflowServiceIntegrationTest extends AbstractWorkflowServ
|
||||
assertNull("Workflow should not be deployed", workflowDef);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testMNT21638_1()
|
||||
{
|
||||
WorkflowDefinition definition = deployDefinition("activiti/test-MNT21638-1.bpmn20.xml");
|
||||
|
||||
personManager.setUser(USER1);
|
||||
|
||||
// Start the Workflow
|
||||
try
|
||||
{
|
||||
WorkflowPath path = workflowService.startWorkflow(definition.getId(), null);
|
||||
fail("Workflow should not have been executed");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testMNT21638_2()
|
||||
{
|
||||
WorkflowDefinition definition = deployDefinition("activiti/test-MNT21638-2.bpmn20.xml", "MNT21638", true);
|
||||
|
||||
personManager.setUser(USER1);
|
||||
|
||||
// Start the Workflow
|
||||
WorkflowPath path = workflowService.startWorkflow(definition.getId(), null);
|
||||
String instanceId = path.getInstance().getId();
|
||||
|
||||
assertNotNull(instanceId);
|
||||
}
|
||||
|
||||
private NodeRef findWorkflowParent()
|
||||
{
|
||||
RepositoryLocation workflowLocation = (RepositoryLocation)
|
||||
|
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<definitions
|
||||
xmlns:activiti="http://activiti.org/bpmn" xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
|
||||
typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath"
|
||||
targetNamespace="http://www.activiti.org/test">
|
||||
|
||||
<process id="test-mnt21638-1" name="test-mnt21638-1">
|
||||
|
||||
<startEvent id="start" activiti:formKey="wf:submitAdhocTask"/>
|
||||
<sequenceFlow id="flow1" sourceRef="start" targetRef="someTask2" />
|
||||
|
||||
<userTask id="someTask2" name="Activiti is awesome!" activiti:formKey="wf:adhocTask">
|
||||
<extensionElements>
|
||||
<activiti:taskListener event="create" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
|
||||
<activiti:field name="script">
|
||||
<activiti:string>
|
||||
var exec = new org.alfresco.util.exec.RuntimeExec();
|
||||
exec.setCommand(["/bin/ls"]);
|
||||
var res = exec.execute();
|
||||
java.lang.System.err.println(res.getStdOut());
|
||||
</activiti:string>
|
||||
</activiti:field>
|
||||
</activiti:taskListener>
|
||||
</extensionElements>
|
||||
<humanPerformer>
|
||||
<resourceAssignmentExpression>
|
||||
<formalExpression>admin</formalExpression>
|
||||
</resourceAssignmentExpression>
|
||||
</humanPerformer>
|
||||
</userTask>
|
||||
<sequenceFlow id="flow2" sourceRef="someTask2" targetRef="end" />
|
||||
|
||||
<endEvent id="end" />
|
||||
|
||||
</process>
|
||||
|
||||
</definitions>
|
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<definitions
|
||||
xmlns:activiti="http://activiti.org/bpmn" xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
|
||||
typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath"
|
||||
targetNamespace="http://www.activiti.org/test">
|
||||
|
||||
<process id="test-mnt21638-2" name="test-mnt21638-2">
|
||||
|
||||
<startEvent id="start" activiti:formKey="wf:submitAdhocTask"/>
|
||||
<sequenceFlow id="flow1" sourceRef="start" targetRef="someTask2" />
|
||||
|
||||
<userTask id="someTask2" name="Activiti is awesome!" activiti:formKey="wf:adhocTask">
|
||||
<extensionElements>
|
||||
<activiti:taskListener event="create" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
|
||||
<activiti:field name="script">
|
||||
<activiti:string>
|
||||
var exec = new org.alfresco.util.exec.RuntimeExec();
|
||||
exec.setCommand(["/bin/ls"]);
|
||||
var res = exec.execute();
|
||||
java.lang.System.err.println(res.getStdOut());
|
||||
</activiti:string>
|
||||
</activiti:field>
|
||||
</activiti:taskListener>
|
||||
</extensionElements>
|
||||
<humanPerformer>
|
||||
<resourceAssignmentExpression>
|
||||
<formalExpression>admin</formalExpression>
|
||||
</resourceAssignmentExpression>
|
||||
</humanPerformer>
|
||||
</userTask>
|
||||
<sequenceFlow id="flow2" sourceRef="someTask2" targetRef="end" />
|
||||
|
||||
<endEvent id="end" />
|
||||
|
||||
</process>
|
||||
|
||||
</definitions>
|
Reference in New Issue
Block a user