View | Details | Raw Unified | Return to bug 65151
Collapse All | Expand All

(-)a/bin/jmeter.properties (+20 lines)
Lines 1354-1356 jmeter.reportgenerator.apdex_tolerated_threshold=1500 Link Here
1354
# Path to XSL file used to generate Schematic View of Test Plan
1354
# Path to XSL file used to generate Schematic View of Test Plan
1355
# When empty, JMeter will use the embedded one in src/core/org/apache/jmeter/gui/action/schematic.xsl
1355
# When empty, JMeter will use the embedded one in src/core/org/apache/jmeter/gui/action/schematic.xsl
1356
#docgeneration.schematic_xsl=
1356
#docgeneration.schematic_xsl=
1357
1358
#---------------------------------------------------------------------------
1359
# JEXL configuration
1360
#---------------------------------------------------------------------------
1361
1362
# If set to true, then JEXL functions are allowed to access any class by default
1363
jexl.allow.by.default=false
1364
1365
# A list of comma-separated patterns that tells which methods JEXL functions are allowed to call
1366
#   Examples:
1367
#     "org.apache.jmeter." allows access to all classes in the org.apache.jmeter package
1368
#     "java.lang.String" allows access to all methods in the String class
1369
#     "foo.bar.MyClass.doSomething" allows access to the doSomething() method in the foo.bar.MyClass class
1370
jexl.allowed.classes=org.apache.jmeter.,\
1371
  java.lang.String,java.lang.Boolean,java.lang.Math,\
1372
  java.lang.Integer,java.lang.Double,java.lang.Byte,java.lang.Float,java.lang.Number,java.lang.Long,java.lang.Short
1373
1374
# A list of comma-separated patterns that tells which methods JEXL functions are not allowed to call
1375
# The syntax is the same as for the "jexl.allowed.classes" property
1376
jexl.disallowed.classes=
(-)a/src/functions/src/main/java/org/apache/jmeter/functions/Jexl2Function.java (-1 / +63 lines)
Lines 17-30 Link Here
17
package org.apache.jmeter.functions;
17
package org.apache.jmeter.functions;
18
import java.lang.reflect.Constructor;
19
import java.security.AccessControlException;
18
import java.util.ArrayList;
20
import java.util.ArrayList;
19
import java.util.Collection;
21
import java.util.Collection;
22
import java.util.Iterator;
20
import java.util.List;
23
import java.util.List;
21
import org.apache.commons.jexl2.JexlContext;
24
import org.apache.commons.jexl2.JexlContext;
22
import org.apache.commons.jexl2.JexlEngine;
25
import org.apache.commons.jexl2.JexlEngine;
26
import org.apache.commons.jexl2.JexlInfo;
23
import org.apache.commons.jexl2.MapContext;
27
import org.apache.commons.jexl2.MapContext;
24
import org.apache.commons.jexl2.Script;
28
import org.apache.commons.jexl2.Script;
29
import org.apache.commons.jexl2.introspection.JexlMethod;
30
import org.apache.commons.jexl2.introspection.JexlPropertyGet;
31
import org.apache.commons.jexl2.introspection.JexlPropertySet;
32
import org.apache.commons.jexl2.introspection.Uberspect;
33
import org.apache.commons.jexl2.introspection.UberspectImpl;
25
import org.apache.jmeter.engine.util.CompoundVariable;
34
import org.apache.jmeter.engine.util.CompoundVariable;
26
import org.apache.jmeter.samplers.SampleResult;
35
import org.apache.jmeter.samplers.SampleResult;
27
import org.apache.jmeter.samplers.Sampler;
36
import org.apache.jmeter.samplers.Sampler;
Lines 115-121 public class Jexl2Function extends AbstractFunction implements ThreadListener { Link Here
115
    private static JexlEngine getJexlEngine() {
124
    private static JexlEngine getJexlEngine() {
116
        JexlEngine engine = threadLocalJexl.get();
125
        JexlEngine engine = threadLocalJexl.get();
117
        if(engine == null) {
126
        if(engine == null) {
118
            engine = new JexlEngine();
127
            engine = new JexlEngine(Sandbox.INSTANCE, null, null, null);
119
            engine.setCache(512);
128
            engine.setCache(512);
120
            engine.setLenient(false);
129
            engine.setLenient(false);
121
            engine.setSilent(false);
130
            engine.setSilent(false);
Lines 160-163 public class Jexl2Function extends AbstractFunction implements ThreadListener { Link Here
160
        }
169
        }
161
    }
170
    }
171
    /**
172
     * The class implements a sandbox for JEXL functions.
173
     * The sandbox defines which methods are allowed to call.
174
     */
175
    private static class Sandbox implements Uberspect {
176
177
        static final Sandbox INSTANCE = new Sandbox();
178
179
        private final Uberspect uberspect = new UberspectImpl(null);
180
181
        private Sandbox() {}
182
183
        @Override
184
        public void setClassLoader(ClassLoader loader) {
185
            uberspect.setClassLoader(loader);
186
        }
187
188
        @Override
189
        @SuppressWarnings("deprecation")
190
        public Constructor<?> getConstructor(Object ctorHandle, Object[] args, JexlInfo info) {
191
            return uberspect.getConstructor(ctorHandle, args, info);
192
        }
193
194
        @Override
195
        public JexlMethod getConstructorMethod(Object ctorHandle, Object[] args, JexlInfo info) {
196
            return uberspect.getConstructorMethod(ctorHandle, args, info);
197
        }
198
199
        @Override
200
        public JexlMethod getMethod(Object obj, String method, Object[] args, JexlInfo info) {
201
            String call = String.format("%s.%s", obj.getClass().getCanonicalName(), method);
202
            if (!JexlFunctionAccessController.INSTANCE.isAllowed(call)) {
203
                throw new AccessControlException("Not allowed");
204
            }
205
            return uberspect.getMethod(obj, method, args, info);
206
        }
207
208
        @Override
209
        public JexlPropertyGet getPropertyGet(Object obj, Object identifier, JexlInfo info) {
210
            return uberspect.getPropertyGet(obj, identifier, info);
211
        }
212
213
        @Override
214
        public JexlPropertySet getPropertySet(Object obj, Object identifier, Object arg, JexlInfo info) {
215
            return uberspect.getPropertySet(obj, identifier, arg, info);
216
        }
217
218
        @Override
219
        public Iterator<?> getIterator(Object obj, JexlInfo info) {
220
            return uberspect.getIterator(obj, info);
221
        }
222
    }
223
162
}
224
}
(-)a/src/functions/src/main/java/org/apache/jmeter/functions/Jexl3Function.java (+81 lines)
Lines 17-31 Link Here
17
package org.apache.jmeter.functions;
17
package org.apache.jmeter.functions;
18
import java.security.AccessControlException;
18
import java.util.ArrayList;
19
import java.util.ArrayList;
19
import java.util.Collection;
20
import java.util.Collection;
21
import java.util.Iterator;
20
import java.util.List;
22
import java.util.List;
23
import org.apache.commons.jexl3.JexlArithmetic;
21
import org.apache.commons.jexl3.JexlBuilder;
24
import org.apache.commons.jexl3.JexlBuilder;
22
import org.apache.commons.jexl3.JexlContext;
25
import org.apache.commons.jexl3.JexlContext;
23
import org.apache.commons.jexl3.JexlEngine;
26
import org.apache.commons.jexl3.JexlEngine;
27
import org.apache.commons.jexl3.JexlOperator;
24
import org.apache.commons.jexl3.JexlScript;
28
import org.apache.commons.jexl3.JexlScript;
25
import org.apache.commons.jexl3.MapContext;
29
import org.apache.commons.jexl3.MapContext;
30
import org.apache.commons.jexl3.introspection.JexlMethod;
31
import org.apache.commons.jexl3.introspection.JexlPropertyGet;
32
import org.apache.commons.jexl3.introspection.JexlPropertySet;
33
import org.apache.commons.jexl3.introspection.JexlUberspect;
26
import org.apache.jmeter.engine.util.CompoundVariable;
34
import org.apache.jmeter.engine.util.CompoundVariable;
27
import org.apache.jmeter.samplers.SampleResult;
35
import org.apache.jmeter.samplers.SampleResult;
28
import org.apache.jmeter.samplers.Sampler;
36
import org.apache.jmeter.samplers.Sampler;
Lines 110-115 public class Jexl3Function extends AbstractFunction implements ThreadListener { Link Here
110
    private static JexlEngine createJexlEngine() {
118
    private static JexlEngine createJexlEngine() {
111
        return new JexlBuilder()
119
        return new JexlBuilder()
120
                .uberspect(Sandbox.INSTANCE)
112
                .cache(512)
121
                .cache(512)
113
                .silent(true)
122
                .silent(true)
114
                .strict(true)
123
                .strict(true)
Lines 157-160 public class Jexl3Function extends AbstractFunction implements ThreadListener { Link Here
157
        }
166
        }
158
    }
167
    }
168
    /**
169
     * The class implements a sandbox for JEXL functions.
170
     * The sandbox defines which methods are allowed to call.
171
     */
172
    private static class Sandbox implements JexlUberspect {
173
174
        static final Sandbox INSTANCE = new Sandbox();
175
176
        private final JexlUberspect uberspect = new JexlBuilder().create().getUberspect();
177
178
        private Sandbox() {}
179
180
        @Override
181
        public List<PropertyResolver> getResolvers(JexlOperator op, Object obj) {
182
            return uberspect.getResolvers(op, obj);
183
        }
184
185
        @Override
186
        public void setClassLoader(ClassLoader loader) {
187
            uberspect.setClassLoader(loader);
188
        }
189
190
        @Override
191
        public int getVersion() {
192
            return uberspect.getVersion();
193
        }
194
195
        @Override
196
        public JexlMethod getConstructor(Object ctorHandle, Object... args) {
197
            return null;
198
        }
199
200
        @Override
201
        public JexlMethod getMethod(Object obj, String method, Object... args) {
202
            String call = String.format("%s.%s", obj.getClass().getCanonicalName(), method);
203
            if (!JexlFunctionAccessController.INSTANCE.isAllowed(call)) {
204
                throw new AccessControlException("Not allowed");
205
            }
206
            return uberspect.getMethod(obj, method, args);
207
        }
208
209
        @Override
210
        public JexlPropertyGet getPropertyGet(Object obj, Object identifier) {
211
            return uberspect.getPropertyGet(obj, identifier);
212
        }
213
214
        @Override
215
        public JexlPropertyGet getPropertyGet(List<PropertyResolver> resolvers, Object obj, Object identifier) {
216
            return uberspect.getPropertyGet(resolvers, obj, identifier);
217
        }
218
219
        @Override
220
        public JexlPropertySet getPropertySet(Object obj, Object identifier, Object arg) {
221
            return uberspect.getPropertySet(obj, identifier, arg);
222
        }
223
224
        @Override
225
        public JexlPropertySet getPropertySet(List<PropertyResolver> resolvers, Object obj, Object identifier, Object arg) {
226
            return uberspect.getPropertySet(resolvers, obj, identifier, arg);
227
        }
228
229
        @Override
230
        public Iterator<?> getIterator(Object obj) {
231
            return uberspect.getIterator(obj);
232
        }
233
234
        @Override
235
        public JexlArithmetic.Uberspect getArithmetic(JexlArithmetic arithmetic) {
236
            return uberspect.getArithmetic(arithmetic);
237
        }
238
    }
239
159
}
240
}
(-)a/src/functions/src/main/java/org/apache/jmeter/functions/JexlFunctionAccessController.java (+81 lines)
Lines 17-21 Link Here
17
package org.apache.jmeter.functions;
17
package org.apache.jmeter.functions;
18
import java.util.ArrayList;
19
import java.util.List;
20
import java.util.Properties;
21
22
import org.apache.jmeter.util.JMeterUtils;
23
18
public class JexlFunctionAccessController {
24
public class JexlFunctionAccessController {
25
26
    static final JexlFunctionAccessController INSTANCE;
27
28
    static {
29
        Properties properties = JMeterUtils.getJMeterProperties();
30
31
        boolean allowedByDefault = Boolean.parseBoolean(properties.getProperty(
32
                "jexl.allow.by.default", "false"));
33
        List<String> allowedList = new ArrayList<>();
34
        List<String> disallowedList = new ArrayList<>();
35
36
        String[] tokens = properties.getProperty(
37
                "jexl.allowed.classes", "").split(",");
38
39
        for (String token : tokens) {
40
            String pattern = token.trim();
41
            if (!token.isEmpty()) {
42
                allowedList.add(pattern);
43
            }
44
        }
45
46
        tokens = properties.getProperty(
47
                "jexl.disallowed.classes", "").split(",");
48
        for (String token : tokens) {
49
            String pattern = token.trim();
50
            if (!pattern.isEmpty()) {
51
                disallowedList.add(pattern);
52
            }
53
        }
54
55
        INSTANCE = new JexlFunctionAccessController(allowedByDefault, allowedList, disallowedList);
56
    }
57
58
    private final boolean allowedByDefault;
59
    private final List<String> allowedList;
60
    private final List<String> disallowedList;
61
62
    private JexlFunctionAccessController(
63
            boolean allowedByDefault, List<String> allowedList, List<String> disallowedList) {
64
65
        this.allowedByDefault = allowedByDefault;
66
        this.allowedList = allowedList;
67
        this.disallowedList = disallowedList;
68
    }
69
70
    public boolean isAllowed(String name) {
71
        if (inDisallowedList(name)) {
72
            return false;
73
        }
74
75
        if (inAllowedList(name)) {
76
            return true;
77
        }
78
79
        return allowedByDefault;
80
    }
81
82
    private boolean inAllowedList(String name) {
83
        return inList(name, allowedList);
84
    }
85
86
    private boolean inDisallowedList(String name) {
87
        return inList(name, disallowedList);
88
    }
89
90
    private static boolean inList(String name, List<String> patterns) {
91
        for (String pattern : patterns) {
92
            if (name.startsWith(pattern)) {
93
                return true;
94
            }
95
        }
96
97
        return false;
98
    }
99
19
}
100
}
(-)a/src/functions/src/test/java/org/apache/jmeter/functions/TestJexl2Function.java (+9 lines)
Lines 18-23 Link Here
18
package org.apache.jmeter.functions;
18
package org.apache.jmeter.functions;
19
import static org.junit.Assert.assertEquals;
19
import static org.junit.Assert.assertEquals;
20
import static org.junit.Assert.assertNotEquals;
20
import java.util.Collection;
21
import java.util.Collection;
21
import java.util.LinkedList;
22
import java.util.LinkedList;
Lines 102-105 public class TestJexl2Function extends JMeterTestCase { Link Here
102
        String ret = function.execute(result, null);
103
        String ret = function.execute(result, null);
103
        assertEquals("6", ret);
104
        assertEquals("6", ret);
104
    }
105
    }
106
107
    @Test
108
    public void testNoAccessToRuntime() throws Exception {
109
        params.add(new CompoundVariable(
110
                "sampleResult.getClass().forName('java.lang.Runtime').getCanonicalName()"));
111
        function.setParameters(params);
112
        assertNotEquals("java.lang.Runtime", function.execute(result, null));
113
    }
105
}
114
}

Return to bug 65151