Skip to content

Commit f440e60

Browse files
committed
Wrapping Flowable's Groovy scriptTasks with security sandbox (#1418)
1 parent 72b7aab commit f440e60

3 files changed

Lines changed: 113 additions & 3 deletions

File tree

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.syncope.core.spring.implementation;
20+
21+
import groovy.grape.GrabAnnotationTransformation;
22+
import groovy.lang.GroovyClassLoader;
23+
import java.io.Reader;
24+
import java.util.Set;
25+
import javax.script.ScriptContext;
26+
import javax.script.ScriptException;
27+
import org.codehaus.groovy.control.CompilerConfiguration;
28+
import org.codehaus.groovy.jsr223.GroovyScriptEngineImpl;
29+
import org.jenkinsci.plugins.scriptsecurity.sandbox.blacklists.Blacklist;
30+
import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.RejectASTTransformsCustomizer;
31+
import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor;
32+
import org.kohsuke.groovy.sandbox.GroovyInterceptor;
33+
import org.kohsuke.groovy.sandbox.SandboxTransformer;
34+
import org.springframework.util.function.ThrowingSupplier;
35+
36+
public class GroovySandboxScriptEngineImpl extends GroovyScriptEngineImpl {
37+
38+
private static final GroovyClassLoader GROOVY_CLASSLOADER;
39+
40+
static {
41+
CompilerConfiguration cc = new CompilerConfiguration();
42+
cc.addCompilationCustomizers(new RejectASTTransformsCustomizer(), new SandboxTransformer());
43+
cc.setDisabledGlobalASTTransformations(Set.of(GrabAnnotationTransformation.class.getName()));
44+
45+
GROOVY_CLASSLOADER = new GroovyClassLoader(Thread.currentThread().getContextClassLoader(), cc);
46+
}
47+
48+
protected final Blacklist blackList;
49+
50+
public GroovySandboxScriptEngineImpl(final Blacklist blackList) {
51+
super(GROOVY_CLASSLOADER);
52+
this.blackList = blackList;
53+
}
54+
55+
protected Object sandboxEval(final ThrowingSupplier<Object> eval) {
56+
GroovyInterceptor interceptor = null;
57+
try {
58+
interceptor = new SandboxInterceptor(blackList);
59+
interceptor.register();
60+
} catch (NoClassDefFoundError noClassDefFound) {
61+
// ignore
62+
}
63+
64+
try {
65+
return eval.get();
66+
} finally {
67+
if (interceptor != null) {
68+
try {
69+
interceptor.unregister();
70+
} catch (NoClassDefFoundError noClassDefFound) {
71+
// ignore
72+
}
73+
}
74+
}
75+
}
76+
77+
@Override
78+
public Object eval(final Reader reader, final ScriptContext ctx) throws ScriptException {
79+
return sandboxEval(() -> super.eval(reader, ctx));
80+
}
81+
82+
@Override
83+
public Object eval(final String script, final ScriptContext ctx) throws ScriptException {
84+
return sandboxEval(() -> super.eval(script, ctx));
85+
}
86+
}

‎ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/FlowableWorkflowContext.java‎

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
package org.apache.syncope.core.flowable;
2020

2121
import java.util.List;
22+
import javax.script.ScriptContext;
23+
import javax.script.ScriptEngine;
2224
import org.apache.syncope.common.keymaster.client.api.ConfParamOps;
2325
import org.apache.syncope.core.flowable.api.UserRequestHandler;
2426
import org.apache.syncope.core.flowable.impl.FlowableBpmnProcessManager;
@@ -48,14 +50,19 @@
4850
import org.apache.syncope.core.provisioning.api.data.UserDataBinder;
4951
import org.apache.syncope.core.provisioning.api.notification.NotificationManager;
5052
import org.apache.syncope.core.provisioning.api.rules.RuleProvider;
53+
import org.apache.syncope.core.spring.implementation.GroovySandboxScriptEngineImpl;
5154
import org.apache.syncope.core.spring.security.SecurityProperties;
5255
import org.apache.syncope.core.workflow.api.UserWorkflowAdapter;
56+
import org.flowable.common.engine.api.FlowableException;
5357
import org.flowable.common.engine.impl.AbstractEngineConfiguration;
5458
import org.flowable.common.engine.impl.cfg.IdGenerator;
5559
import org.flowable.common.engine.impl.persistence.StrongUuidGenerator;
60+
import org.flowable.common.engine.impl.scripting.JSR223FlowableScriptEngine;
61+
import org.flowable.common.engine.impl.scripting.ScriptingEngines;
5662
import org.flowable.idm.spring.SpringIdmEngineConfiguration;
5763
import org.flowable.idm.spring.configurator.SpringIdmEngineConfigurator;
5864
import org.flowable.spring.SpringProcessEngineConfiguration;
65+
import org.jenkinsci.plugins.scriptsecurity.sandbox.blacklists.Blacklist;
5966
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
6067
import org.springframework.boot.context.properties.EnableConfigurationProperties;
6168
import org.springframework.context.ApplicationEventPublisher;
@@ -140,9 +147,10 @@ public IdGenerator idGenerator() {
140147
public SpringProcessEngineConfiguration processEngineConfiguration(
141148
final WorkflowFlowableProperties props,
142149
final SpringIdmEngineConfigurator syncopeIdmEngineConfigurator,
143-
final IdGenerator idGenerator,
144150
final SyncopeEntitiesVariableType syncopeEntitiesVariableType,
145-
final SyncopeFormHandlerHelper syncopeFormHandlerHelper) {
151+
final SyncopeFormHandlerHelper syncopeFormHandlerHelper,
152+
final IdGenerator idGenerator,
153+
final Blacklist groovyBlackList) {
146154

147155
SpringProcessEngineConfiguration conf = new SpringProcessEngineConfiguration();
148156
conf.setDatabaseSchemaUpdate(AbstractEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
@@ -154,6 +162,22 @@ public SpringProcessEngineConfiguration processEngineConfiguration(
154162
conf.setFormHandlerHelper(syncopeFormHandlerHelper);
155163
conf.setIdGenerator(idGenerator);
156164
conf.setPreBpmnParseHandlers(List.of(new ShellServiceTaskDisablingBpmnParseHandler()));
165+
166+
ScriptEngine groovyScriptEngine = new GroovySandboxScriptEngineImpl(groovyBlackList);
167+
groovyScriptEngine.getContext().
168+
setAttribute("#jsr223.groovy.engine.keep.globals", "weak", ScriptContext.ENGINE_SCOPE);
169+
conf.setScriptEngine(new JSR223FlowableScriptEngine() {
170+
171+
@Override
172+
protected ScriptEngine getEngineByName(final String language) {
173+
if (ScriptingEngines.GROOVY_SCRIPTING_LANGUAGE.equals(language)) {
174+
return groovyScriptEngine;
175+
}
176+
177+
throw new FlowableException("Can't find scripting engine for '" + language + "'");
178+
}
179+
});
180+
157181
return conf;
158182
}
159183

‎pom.xml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ under the License.
415415
<project.build.outputTimestamp>2026-05-22T09:50:39Z</project.build.outputTimestamp>
416416
<syncope.version>${project.version}</syncope.version>
417417

418-
<connid.version>1.6.1.0</connid.version>
418+
<connid.version>1.6.1.1-SNAPSHOT</connid.version>
419419
<connid.soap.version>1.5.0</connid.soap.version>
420420
<connid.rest.version>1.1.1</connid.rest.version>
421421
<connid.db.version>2.4.1</connid.db.version>

0 commit comments

Comments
 (0)