Skip to content

Commit 8accabb

Browse files
committed
Begin making 3.0 adjustments
Update some tests Implement allowlisting for methods and classes Extract separate MethodValidator Add result validating Use string-based config. Make the allowlists easier to work with Wrap classes before validating result Split MethodValidator from ReturnTypeValidator Don't create new JinjavaBeanELResolver instances per Jinjava or JinjavaConfig for bean cache performance Validate ReturnTypes at the top-level so that accessing values of arrays, lists, maps have their return values validated Wrap at a higher level and don't resolve `____int3rpr3t3r____` Use BeanMethods and cache allowed methods and return types Don't expect ____int3rpr3t3r____ and don't use arrays in ReverseFilter and add method and return type validator to test classes Helper for constructing JinjavaConfig in tests Extract test objects to separate classes. Allow arrays. Add AnnotationIntrospector Don't need annotation introspector All tests passing Fix build Describe a couple more changes Don't allow jinjava constructs outside of the AllowlistGroup classes from being allowlisted Add tests that certain classes and packages CANNOT be allowlisted Allow BigInteger Add annotation to MethodValidator Test that certain constructs are fully banned Remove unused method from ReturnTypeValidator Use Map and Set instead of ImmutableMap and ImmutableSet for less churn Apply spotless formatting Fix test after merge conflicts
1 parent 22808dc commit 8accabb

123 files changed

Lines changed: 2003 additions & 860 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

3.0-changes.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
- Migrated JinjavaConfig to immutable
2+
- Removed whitespaceRequiredWithinTokens LegacyOverride and converted to BuiltinFeatures
3+
- Nested interpretation disabled by default
4+
- Removed restricted methods and properties from JinjavaConfig
5+
- Turn on all current LegacyOverrides by default
6+
- Use MethodValidator and ReturnTypeValidator to enforce method invocations and objects returned by ELResolver

src/main/java/com/hubspot/jinjava/JinjavaConfig.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import com.hubspot.jinjava.el.JinjavaObjectUnwrapper;
2525
import com.hubspot.jinjava.el.JinjavaProcessors;
2626
import com.hubspot.jinjava.el.ObjectUnwrapper;
27+
import com.hubspot.jinjava.el.ext.AllowlistMethodValidator;
28+
import com.hubspot.jinjava.el.ext.AllowlistReturnTypeValidator;
2729
import com.hubspot.jinjava.features.FeatureConfig;
2830
import com.hubspot.jinjava.features.Features;
2931
import com.hubspot.jinjava.interpret.Context.Library;
@@ -98,8 +100,6 @@ default int getMaxMacroRecursionDepth() {
98100
}
99101

100102
Map<Library, Set<String>> getDisabled();
101-
Set<String> getRestrictedMethods();
102-
Set<String> getRestrictedProperties();
103103

104104
@Value.Default
105105
default boolean isFailOnUnknownTokens() {
@@ -161,6 +161,16 @@ default TokenScannerSymbols getTokenScannerSymbols() {
161161
return new DefaultTokenScannerSymbols();
162162
}
163163

164+
@Value.Default
165+
default AllowlistMethodValidator getMethodValidator() {
166+
return AllowlistMethodValidator.DEFAULT;
167+
}
168+
169+
@Value.Default
170+
default AllowlistReturnTypeValidator getReturnTypeValidator() {
171+
return AllowlistReturnTypeValidator.DEFAULT;
172+
}
173+
164174
@Value.Default
165175
default ELResolver getElResolver() {
166176
return isDefaultReadOnlyResolver()

src/main/java/com/hubspot/jinjava/el/ExpressionResolver.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@
2222
import com.hubspot.jinjava.interpret.UnknownTokenException;
2323
import com.hubspot.jinjava.interpret.errorcategory.BasicTemplateErrorCategory;
2424
import com.hubspot.jinjava.lib.fn.ELFunctionDefinition;
25+
import com.hubspot.jinjava.objects.serialization.PyishObjectMapper;
2526
import com.hubspot.jinjava.util.WhitespaceUtils;
2627
import de.odysseus.el.tree.TreeBuilderException;
2728
import java.util.Arrays;
2829
import java.util.List;
30+
import java.util.Objects;
2931
import javax.el.ELException;
3032
import javax.el.ExpressionFactory;
3133
import javax.el.PropertyNotFoundException;
@@ -39,7 +41,7 @@ public class ExpressionResolver {
3941

4042
private final JinjavaInterpreter interpreter;
4143
private final ExpressionFactory expressionFactory;
42-
private final JinjavaInterpreterResolver resolver;
44+
private final ReturnTypeValidatingJinjavaInterpreterResolver resolver;
4345
private final JinjavaELContext elContext;
4446
private final ObjectUnwrapper objectUnwrapper;
4547

@@ -53,7 +55,11 @@ public ExpressionResolver(JinjavaInterpreter interpreter, Jinjava jinjava) {
5355
? jinjava.getEagerExpressionFactory()
5456
: jinjava.getExpressionFactory();
5557

56-
this.resolver = new JinjavaInterpreterResolver(interpreter);
58+
this.resolver =
59+
new ReturnTypeValidatingJinjavaInterpreterResolver(
60+
interpreter.getConfig().getReturnTypeValidator(),
61+
new JinjavaInterpreterResolver(interpreter)
62+
);
5763
this.elContext = new JinjavaELContext(interpreter, resolver);
5864
for (ELFunctionDefinition fn : jinjava.getGlobalContext().getAllFunctions()) {
5965
this.elContext.setFunction(fn.getNamespace(), fn.getLocalName(), fn.getMethod());
@@ -343,4 +349,12 @@ public Object resolveProperty(Object object, List<String> propertyNames) {
343349
public Object wrap(Object object) {
344350
return resolver.wrap(object);
345351
}
352+
353+
public String getAsString(Object object) {
354+
if (interpreter.getConfig().getLegacyOverrides().isUsePyishObjectMapper()) {
355+
// resolver.
356+
return PyishObjectMapper.getAsUnquotedPyishString(object);
357+
}
358+
return Objects.toString(object, "");
359+
}
346360
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.hubspot.jinjava.el;
2+
3+
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
4+
5+
public interface HasInterpreter {
6+
JinjavaInterpreter interpreter();
7+
}

src/main/java/com/hubspot/jinjava/el/JinjavaELContext.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
import java.lang.reflect.Method;
66
import javax.el.ELResolver;
77

8-
public class JinjavaELContext extends SimpleContext {
8+
public class JinjavaELContext extends SimpleContext implements HasInterpreter {
99

1010
private JinjavaInterpreter interpreter;
1111
private MacroFunctionMapper functionMapper;
1212

13+
@Deprecated
1314
public JinjavaELContext() {
1415
super();
1516
}
@@ -19,6 +20,11 @@ public JinjavaELContext(JinjavaInterpreter interpreter, ELResolver resolver) {
1920
this.interpreter = interpreter;
2021
}
2122

23+
@Override
24+
public JinjavaInterpreter interpreter() {
25+
return interpreter;
26+
}
27+
2228
@Override
2329
public MacroFunctionMapper getFunctionMapper() {
2430
if (functionMapper == null) {

src/main/java/com/hubspot/jinjava/el/JinjavaInterpreterResolver.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.hubspot.jinjava.objects.PyWrapper;
2222
import com.hubspot.jinjava.objects.collections.SizeLimitingPyList;
2323
import com.hubspot.jinjava.objects.collections.SizeLimitingPyMap;
24+
import com.hubspot.jinjava.objects.collections.SizeLimitingPySet;
2425
import com.hubspot.jinjava.objects.date.FormattedDate;
2526
import com.hubspot.jinjava.objects.date.InvalidDateFormatException;
2627
import com.hubspot.jinjava.objects.date.PyishDate;
@@ -39,6 +40,7 @@
3940
import java.util.Locale;
4041
import java.util.Map;
4142
import java.util.Objects;
43+
import java.util.Set;
4244
import javax.el.ArrayELResolver;
4345
import javax.el.CompositeELResolver;
4446
import javax.el.ELContext;
@@ -274,7 +276,7 @@ private Object getValue(
274276
}
275277

276278
context.setPropertyResolved(true);
277-
return wrap(value);
279+
return value;
278280
}
279281

280282
@SuppressWarnings("unchecked")
@@ -308,6 +310,12 @@ Object wrap(Object value) {
308310
interpreter.getConfig().getMaxListSize()
309311
);
310312
}
313+
if (Set.class.isAssignableFrom(value.getClass())) {
314+
return new SizeLimitingPySet(
315+
(Set<Object>) value,
316+
interpreter.getConfig().getMaxListSize()
317+
);
318+
}
311319
if (Map.class.isAssignableFrom(value.getClass())) {
312320
// FIXME: ensure keys are actually strings, if not, convert them
313321
return new SizeLimitingPyMap(

src/main/java/com/hubspot/jinjava/el/NoInvokeELContext.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package com.hubspot.jinjava.el;
22

3+
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
34
import javax.el.ELContext;
45
import javax.el.ELResolver;
56
import javax.el.FunctionMapper;
67
import javax.el.VariableMapper;
78

8-
public class NoInvokeELContext extends ELContext {
9+
public class NoInvokeELContext extends ELContext implements HasInterpreter {
910

10-
private ELContext delegate;
11+
private final ELContext delegate;
1112
private NoInvokeELResolver elResolver;
1213

1314
public NoInvokeELContext(ELContext delegate) {
@@ -31,4 +32,9 @@ public FunctionMapper getFunctionMapper() {
3132
public VariableMapper getVariableMapper() {
3233
return delegate.getVariableMapper();
3334
}
35+
36+
@Override
37+
public JinjavaInterpreter interpreter() {
38+
return ((HasInterpreter) delegate).interpreter();
39+
}
3440
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package com.hubspot.jinjava.el;
2+
3+
import com.hubspot.jinjava.el.ext.AllowlistReturnTypeValidator;
4+
import java.beans.FeatureDescriptor;
5+
import java.util.Iterator;
6+
import javax.el.ELContext;
7+
import javax.el.ELResolver;
8+
9+
class ReturnTypeValidatingJinjavaInterpreterResolver extends ELResolver {
10+
11+
private final AllowlistReturnTypeValidator returnTypeValidator;
12+
private final JinjavaInterpreterResolver delegate;
13+
14+
ReturnTypeValidatingJinjavaInterpreterResolver(
15+
AllowlistReturnTypeValidator returnTypeValidator,
16+
JinjavaInterpreterResolver delegate
17+
) {
18+
this.returnTypeValidator = returnTypeValidator;
19+
this.delegate = delegate;
20+
}
21+
22+
@Override
23+
public Class<?> getCommonPropertyType(ELContext context, Object base) {
24+
return delegate.getCommonPropertyType(context, base);
25+
}
26+
27+
@Override
28+
public Iterator<FeatureDescriptor> getFeatureDescriptors(
29+
ELContext context,
30+
Object base
31+
) {
32+
return delegate.getFeatureDescriptors(context, base);
33+
}
34+
35+
@Override
36+
public Class<?> getType(ELContext context, Object base, Object property) {
37+
return delegate.getType(context, base, property);
38+
}
39+
40+
@Override
41+
public Object getValue(ELContext context, Object base, Object property) {
42+
return returnTypeValidator.validateReturnType(
43+
wrap(delegate.getValue(context, base, property))
44+
);
45+
}
46+
47+
@Override
48+
public boolean isReadOnly(ELContext context, Object base, Object property) {
49+
return delegate.isReadOnly(context, base, property);
50+
}
51+
52+
@Override
53+
public void setValue(ELContext context, Object base, Object property, Object value) {
54+
delegate.setValue(context, base, property, value);
55+
}
56+
57+
@Override
58+
public Object invoke(
59+
ELContext context,
60+
Object base,
61+
Object method,
62+
Class<?>[] paramTypes,
63+
Object[] params
64+
) {
65+
return returnTypeValidator.validateReturnType(
66+
wrap(delegate.invoke(context, base, method, paramTypes, params))
67+
);
68+
}
69+
70+
Object wrap(Object object) {
71+
return delegate.wrap(object);
72+
}
73+
}

0 commit comments

Comments
 (0)