[MNT-21638] Script task execution (#1210)

* [MNT-21638] Script task execution based on workflow deloyment category. Javadoc. Unit tests.
This commit is contained in:
tiagosalvado10
2022-09-23 13:24:49 +01:00
committed by GitHub
parent a77584a398
commit 125b35e11c
17 changed files with 542 additions and 139 deletions

View File

@@ -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();
}
}

View File

@@ -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());

View File

@@ -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);
}
}
/**

View File

@@ -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)
{

View File

@@ -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
*

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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.
*/

View File

@@ -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
*

View File

@@ -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

View File

@@ -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\")";

View File

@@ -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();

View File

@@ -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)

View File

@@ -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>

View File

@@ -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>