Skip to content

Commit eda46f6

Browse files
committed
Add option to disable access to services in scripts
1 parent 3f43fa4 commit eda46f6

6 files changed

Lines changed: 101 additions & 72 deletions

File tree

modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/CmmnEngineConfiguration.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,11 @@ public class CmmnEngineConfiguration extends AbstractBuildableEngineConfiguratio
440440
protected List<ResolverFactory> resolverFactories;
441441
protected Collection<ResolverFactory> preDefaultResolverFactories;
442442
protected Collection<ResolverFactory> postDefaultResolverFactories;
443+
/**
444+
* Flag to indicate whether the services should be enabled in the scripting engine. This is set to true by default.
445+
* If set to false, then services like cmmnTaskService, cmmnRuntimeService, etc. will not be available in the scripting engine.
446+
*/
447+
protected boolean servicesEnabledInScripting = true;
443448

444449
/**
445450
* Using field injection together with a delegate expression for a service task / execution listener / task listener is not thread-sade , see user guide section 'Field Injection' for more
@@ -4296,6 +4301,15 @@ public CmmnEngineConfiguration addPostDefaultResolverFactory(ResolverFactory res
42964301
return this;
42974302
}
42984303

4304+
public boolean isServicesEnabledInScripting() {
4305+
return servicesEnabledInScripting;
4306+
}
4307+
4308+
public CmmnEngineConfiguration setServicesEnabledInScripting(boolean servicesEnabledInScripting) {
4309+
this.servicesEnabledInScripting = servicesEnabledInScripting;
4310+
return this;
4311+
}
4312+
42994313
public void resetClock() {
43004314
if (this.clock != null) {
43014315
clock.reset();

modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/scripting/CmmnVariableScopeResolver.java

Lines changed: 25 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
*/
1313
package org.flowable.cmmn.engine.impl.scripting;
1414

15-
import java.util.Arrays;
16-
import java.util.HashSet;
15+
import java.util.Map;
1716
import java.util.Set;
17+
import java.util.function.Function;
1818

1919
import org.apache.commons.lang3.StringUtils;
2020
import org.flowable.cmmn.api.runtime.CaseInstance;
@@ -35,35 +35,28 @@
3535
*/
3636
public class CmmnVariableScopeResolver implements Resolver {
3737

38-
protected static final String ENGINE_CONFIG_KEY = "engineConfiguration";
39-
protected static final String CMMN_ENGINE_CONFIG_KEY = "cmmnEngineConfiguration";
40-
41-
protected static final String RUNTIME__SERVICE_KEY = "runtimeService";
42-
protected static final String CMMN_RUNTIME__SERVICE_KEY = "cmmnRuntimeService";
43-
44-
protected static final String HISTORY_SERVICE_KEY = "historyService";
45-
protected static final String CMMN_HISTORY_SERVICE_KEY = "cmmnHistoryService";
46-
47-
protected static final String MANAGEMENT_SERVICE_KEY = "managementService";
48-
protected static final String CMMN_MANAGEMENT_SERVICE_KEY = "cmmnManagementService";
49-
50-
protected static final String TASK_SERVICE_KEY = "taskService";
51-
protected static final String CMMN_TASK_SERVICE_KEY = "cmmnTaskService";
52-
5338
protected static final String CASE_INSTANCE_KEY = "caseInstance";
5439
protected static final String PLAN_ITEM_INSTANCE_KEY = "planItemInstance";
5540
protected static final String TASK_KEY = "task";
5641

57-
protected static final Set<String> KEYS = new HashSet<>(Arrays.asList(
58-
ENGINE_CONFIG_KEY, CMMN_ENGINE_CONFIG_KEY,
59-
RUNTIME__SERVICE_KEY, CMMN_RUNTIME__SERVICE_KEY,
60-
HISTORY_SERVICE_KEY, CMMN_HISTORY_SERVICE_KEY,
61-
MANAGEMENT_SERVICE_KEY, CMMN_MANAGEMENT_SERVICE_KEY,
62-
TASK_SERVICE_KEY, CMMN_TASK_SERVICE_KEY,
42+
protected static final Map<String, Function<CmmnEngineConfiguration, ?>> SERVICE_RESOLVERS = Map.of(
43+
"engineConfiguration", Function.identity(),
44+
"cmmnEngineConfiguration", Function.identity(),
45+
"runtimeService", CmmnEngineConfiguration::getCmmnRuntimeService,
46+
"cmmnRuntimeService", CmmnEngineConfiguration::getCmmnRuntimeService,
47+
"historyService", CmmnEngineConfiguration::getCmmnHistoryService,
48+
"cmmnHistoryService", CmmnEngineConfiguration::getCmmnHistoryService,
49+
"managementService", CmmnEngineConfiguration::getCmmnManagementService,
50+
"cmmnManagementService", CmmnEngineConfiguration::getCmmnManagementService,
51+
"taskService", CmmnEngineConfiguration::getCmmnTaskService,
52+
"cmmnTaskService", CmmnEngineConfiguration::getCmmnTaskService
53+
);
54+
55+
protected static final Set<String> KEYS = Set.of(
6356
CASE_INSTANCE_KEY,
6457
PLAN_ITEM_INSTANCE_KEY,
6558
TASK_KEY
66-
));
59+
);
6760

6861
protected CmmnEngineConfiguration engineConfiguration;
6962
protected VariableContainer scopeContainer;
@@ -81,26 +74,18 @@ public CmmnVariableScopeResolver(CmmnEngineConfiguration engineConfiguration, Va
8174

8275
@Override
8376
public boolean containsKey(Object key) {
84-
return inputVariableContainer.hasVariable((String) key) || KEYS.contains(key);
77+
return inputVariableContainer.hasVariable((String) key) || KEYS.contains(key)
78+
|| SERVICE_RESOLVERS.containsKey(key) && engineConfiguration.isServicesEnabledInScripting();
8579
}
8680

8781
@Override
8882
public Object get(Object key) {
89-
if (ENGINE_CONFIG_KEY.equals(key) || CMMN_ENGINE_CONFIG_KEY.equals(key)) {
90-
return engineConfiguration;
91-
92-
} else if (RUNTIME__SERVICE_KEY.equals(key) || CMMN_RUNTIME__SERVICE_KEY.equals(key)) {
93-
return engineConfiguration.getCmmnRuntimeService();
94-
95-
} else if (HISTORY_SERVICE_KEY.equals(key) || CMMN_HISTORY_SERVICE_KEY.equals(key)) {
96-
return engineConfiguration.getCmmnHistoryService();
97-
98-
} else if (MANAGEMENT_SERVICE_KEY.equals(key) || CMMN_MANAGEMENT_SERVICE_KEY.equals(key)) {
99-
return engineConfiguration.getCmmnManagementService();
100-
101-
} else if (TASK_SERVICE_KEY.equals(key) || CMMN_TASK_SERVICE_KEY.equals(key)) {
102-
return engineConfiguration.getCmmnTaskService();
103-
83+
if (SERVICE_RESOLVERS.containsKey((String) key)) {
84+
if (engineConfiguration.isServicesEnabledInScripting()) {
85+
return SERVICE_RESOLVERS.get(key).apply(engineConfiguration);
86+
} else {
87+
throw new FlowableException("The service '" + key + "' is not available in the current context. Please enable services in scripting.");
88+
}
10489
} else if (CASE_INSTANCE_KEY.equals(key)) {
10590
if (scopeContainer instanceof CaseInstance) {
10691
return scopeContainer;

modules/flowable-engine/src/main/java/org/flowable/engine/impl/cfg/ProcessEngineConfigurationImpl.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,11 @@ public abstract class ProcessEngineConfigurationImpl extends ProcessEngineConfig
740740
protected List<ResolverFactory> resolverFactories;
741741
protected Collection<ResolverFactory> preDefaultResolverFactories;
742742
protected Collection<ResolverFactory> postDefaultResolverFactories;
743+
/**
744+
* Flag to indicate whether the services should be enabled in the scripting engine. This is set to true by default.
745+
* If set to false, then services like cmmnTaskService, cmmnRuntimeService, etc. will not be available in the scripting engine.
746+
*/
747+
protected boolean servicesEnabledInScripting = true;
743748
// END SCRIPTING
744749
protected boolean isExpressionCacheEnabled = true;
745750
protected int expressionCacheSize = 4096;
@@ -3688,6 +3693,15 @@ public ProcessEngineConfigurationImpl addPostDefaultResolverFactory(ResolverFact
36883693
return this;
36893694
}
36903695

3696+
public boolean isServicesEnabledInScripting() {
3697+
return servicesEnabledInScripting;
3698+
}
3699+
3700+
public ProcessEngineConfigurationImpl setServicesEnabledInScripting(boolean servicesEnabledInScripting) {
3701+
this.servicesEnabledInScripting = servicesEnabledInScripting;
3702+
return this;
3703+
}
3704+
36913705
public DeploymentManager getDeploymentManager() {
36923706
return deploymentManager;
36933707
}

modules/flowable-engine/src/main/java/org/flowable/engine/impl/scripting/VariableScopeResolver.java

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@
1212
*/
1313
package org.flowable.engine.impl.scripting;
1414

15-
import java.util.Arrays;
16-
import java.util.HashSet;
17-
import java.util.Set;
15+
import java.util.Map;
16+
import java.util.function.Function;
1817

1918
import org.flowable.common.engine.api.FlowableException;
2019
import org.flowable.common.engine.api.FlowableIllegalArgumentException;
2120
import org.flowable.common.engine.api.variable.VariableContainer;
2221
import org.flowable.common.engine.impl.scripting.Resolver;
22+
import org.flowable.engine.ProcessEngineConfiguration;
2323
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
2424
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
2525
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
@@ -36,18 +36,16 @@ public class VariableScopeResolver implements Resolver {
3636

3737
protected String variableScopeKey = "execution";
3838

39-
protected static final String processEngineConfigurationKey = "processEngineConfiguration";
40-
protected static final String runtimeServiceKey = "runtimeService";
41-
protected static final String taskServiceKey = "taskService";
42-
protected static final String repositoryServiceKey = "repositoryService";
43-
protected static final String managementServiceKey = "managementService";
44-
protected static final String historyServiceKey = "historyService";
45-
protected static final String formServiceKey = "formService";
46-
protected static final String identityServiceKey = "identityServiceKey";
47-
48-
protected static final Set<String> KEYS = new HashSet<>(Arrays.asList(
49-
processEngineConfigurationKey, runtimeServiceKey, taskServiceKey,
50-
repositoryServiceKey, managementServiceKey, historyServiceKey, formServiceKey, identityServiceKey));
39+
protected static final Map<String, Function<ProcessEngineConfiguration, ?>> SERVICE_RESOLVERS = Map.of(
40+
"processEngineConfiguration", Function.identity(),
41+
"runtimeService", ProcessEngineConfiguration::getRuntimeService,
42+
"taskService", ProcessEngineConfiguration::getTaskService,
43+
"repositoryService", ProcessEngineConfiguration::getRepositoryService,
44+
"managementService", ProcessEngineConfiguration::getManagementService,
45+
"historyService", ProcessEngineConfiguration::getHistoryService,
46+
"formService", ProcessEngineConfiguration::getFormService,
47+
"identityServiceKey", ProcessEngineConfiguration::getIdentityService
48+
);
5149

5250
public VariableScopeResolver(ProcessEngineConfigurationImpl processEngineConfiguration, VariableContainer scopeContainer,
5351
VariableContainer inputVariableContainer) {
@@ -70,29 +68,20 @@ public VariableScopeResolver(ProcessEngineConfigurationImpl processEngineConfigu
7068

7169
@Override
7270
public boolean containsKey(Object key) {
73-
return variableScopeKey.equals(key) || KEYS.contains(key) || inputVariableContainer.hasVariable((String) key);
71+
return variableScopeKey.equals(key) || inputVariableContainer.hasVariable((String) key)
72+
|| SERVICE_RESOLVERS.containsKey(key) && processEngineConfiguration.isServicesEnabledInScripting();
7473
}
7574

7675
@Override
7776
public Object get(Object key) {
7877
if (variableScopeKey.equals(key)) {
7978
return scopeContainer;
80-
} else if (processEngineConfigurationKey.equals(key)) {
81-
return processEngineConfiguration;
82-
} else if (runtimeServiceKey.equals(key)) {
83-
return processEngineConfiguration.getRuntimeService();
84-
} else if (taskServiceKey.equals(key)) {
85-
return processEngineConfiguration.getTaskService();
86-
} else if (repositoryServiceKey.equals(key)) {
87-
return processEngineConfiguration.getRepositoryService();
88-
} else if (managementServiceKey.equals(key)) {
89-
return processEngineConfiguration.getManagementService();
90-
} else if (formServiceKey.equals(key)) {
91-
return processEngineConfiguration.getFormService();
92-
} else if (identityServiceKey.equals(key)) {
93-
return processEngineConfiguration.getIdentityService();
94-
} else if (historyServiceKey.equals(key)) {
95-
return processEngineConfiguration.getHistoryService();
79+
} else if (SERVICE_RESOLVERS.containsKey((String) key)) {
80+
if (processEngineConfiguration.isServicesEnabledInScripting()) {
81+
return SERVICE_RESOLVERS.get(key).apply(processEngineConfiguration);
82+
} else {
83+
throw new FlowableException("The service '" + key + "' is not available in the current context. Please enable services in scripting.");
84+
}
9685
}
9786

9887
return inputVariableContainer.getVariable((String) key);

modules/flowable-engine/src/test/java/org/flowable/examples/bpmn/tasklistener/ScriptTaskListenerTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.flowable.common.engine.api.FlowableException;
1919
import org.flowable.common.engine.api.FlowableIllegalArgumentException;
2020
import org.flowable.common.engine.impl.history.HistoryLevel;
21+
import org.flowable.common.engine.impl.scripting.FlowableScriptEvaluationException;
2122
import org.flowable.engine.impl.test.HistoryTestHelper;
2223
import org.flowable.engine.impl.test.PluggableFlowableTestCase;
2324
import org.flowable.engine.repository.ProcessDefinition;
@@ -56,6 +57,19 @@ public void testScriptTaskListener() {
5657
assertThat(foo).as("Could not find the 'foo' variable in variable scope").isEqualTo("FOO");
5758
}
5859

60+
@Test
61+
@Deployment(resources = { "org/flowable/examples/bpmn/tasklistener/ScriptTaskListenerTest.bpmn20.xml" })
62+
public void testScriptTaskListenerWithDisabledServicesInScript() {
63+
try {
64+
processEngineConfiguration.setServicesEnabledInScripting(false);
65+
assertThatThrownBy(() -> runtimeService.startProcessInstanceByKey("scriptTaskListenerProcess"))
66+
.isInstanceOf(FlowableScriptEvaluationException.class)
67+
.hasMessageContaining("No such property: taskService");
68+
} finally {
69+
processEngineConfiguration.setServicesEnabledInScripting(true);
70+
}
71+
}
72+
5973
@Test
6074
@Deployment
6175
public void testThrowFlowableIllegalArgumentException() {

modules/flowable-engine/src/test/java/org/flowable/examples/bpmn/tasklistener/TaskListenerTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,19 @@ public void testTaskListenerTypeScript() {
369369
assertThat(task2ScriptListenerResult).as("Expected 'task2ScriptListenerResult' variable in variable scope").isEqualTo("usertask2ReturnVal");
370370
}
371371

372+
@Test
373+
@Deployment(resources = { "org/flowable/examples/bpmn/tasklistener/TaskListenerTypeScript.bpmn20.xml" })
374+
public void testTaskListenerTypeScriptWithDisabledServicesInScript() {
375+
try {
376+
processEngineConfiguration.setServicesEnabledInScripting(false);
377+
assertThatThrownBy(() -> runtimeService.startProcessInstanceByKey("taskListenerTypeScriptProcess"))
378+
.isInstanceOf(FlowableScriptEvaluationException.class)
379+
.hasMessageContaining("No such property: taskService");
380+
} finally {
381+
processEngineConfiguration.setServicesEnabledInScripting(true);
382+
}
383+
}
384+
372385
@Test
373386
@Deployment(resources = { "org/flowable/examples/bpmn/tasklistener/TaskListenerTest.throwBpmnErrorCatchEventSubProcess.bpmn20.xml" })
374387
public void testTaskListenerThrowBpmnErrorCreate() {

0 commit comments

Comments
 (0)