You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2020/02/02 08:08:03 UTC
[struts] 01/01: WW-5054 Uses a dedicated set of excluded classes &
packages to be used in devMode
This is an automated email from the ASF dual-hosted git repository.
lukaszlenart pushed a commit to branch WW-5054-debug-browser
in repository https://gitbox.apache.org/repos/asf/struts.git
commit a844265a9050b12c1e7a9415fc768d8e9491220a
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sun Feb 2 08:53:32 2020 +0100
WW-5054 Uses a dedicated set of excluded classes & packages to be used in devMode
---
.../com/opensymphony/xwork2/ognl/OgnlUtil.java | 125 +++++++++++----------
.../java/org/apache/struts2/StrutsConstants.java | 5 +
.../struts2/config/entities/ConstantConfig.java | 30 +++++
core/src/main/resources/struts-default.xml | 34 ++++++
4 files changed, 136 insertions(+), 58 deletions(-)
diff --git a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java
index 88b54cc..21bc0fc 100644
--- a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java
+++ b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java
@@ -65,18 +65,23 @@ public class OgnlUtil {
private Set<Pattern> excludedPackageNamePatterns;
private Set<String> excludedPackageNames;
+ private Set<Class<?>> devModeExcludedClasses;
+ private Set<Pattern> devModeExcludedPackageNamePatterns;
+ private Set<String> devModeExcludedPackageNames;
+
private Container container;
private boolean allowStaticFieldAccess = true;
private boolean allowStaticMethodAccess;
private boolean disallowProxyMemberAccess;
public OgnlUtil() {
- excludedClasses = new HashSet<>();
- excludedPackageNamePatterns = new HashSet<>();
- excludedPackageNames = new HashSet<>();
- excludedClasses = Collections.unmodifiableSet(excludedClasses);
- excludedPackageNamePatterns = Collections.unmodifiableSet(excludedPackageNamePatterns);
- excludedPackageNames = Collections.unmodifiableSet(excludedPackageNames);
+ excludedClasses = Collections.unmodifiableSet(new HashSet<>());
+ excludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>());
+ excludedPackageNames = Collections.unmodifiableSet(new HashSet<>());
+
+ devModeExcludedClasses = Collections.unmodifiableSet(new HashSet<>());
+ devModeExcludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>());
+ devModeExcludedPackageNames = Collections.unmodifiableSet(new HashSet<>());
}
@Inject
@@ -111,6 +116,14 @@ public class OgnlUtil {
this.excludedClasses = Collections.unmodifiableSet(excludedClasses);
}
+ @Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_CLASSES, required = false)
+ protected void setDevModeExcludedClasses(String commaDelimitedClasses) {
+ Set<Class<?>> excludedClasses = new HashSet<>();
+ excludedClasses.addAll(this.devModeExcludedClasses);
+ excludedClasses.addAll(parseExcludedClasses(commaDelimitedClasses));
+ this.devModeExcludedClasses = Collections.unmodifiableSet(excludedClasses);
+ }
+
private Set<Class<?>> parseExcludedClasses(String commaDelimitedClasses) {
Set<String> classNames = TextParseUtil.commaDelimitedStringToSet(commaDelimitedClasses);
Set<Class<?>> classes = new HashSet<>();
@@ -134,6 +147,14 @@ public class OgnlUtil {
this.excludedPackageNamePatterns = Collections.unmodifiableSet(excludedPackageNamePatterns);
}
+ @Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAME_PATTERNS, required = false)
+ protected void setDevModeExcludedPackageNamePatterns(String commaDelimitedPackagePatterns) {
+ Set<Pattern> excludedPackageNamePatterns = new HashSet<>();
+ excludedPackageNamePatterns.addAll(this.devModeExcludedPackageNamePatterns);
+ excludedPackageNamePatterns.addAll(parseExcludedPackageNamePatterns(commaDelimitedPackagePatterns));
+ this.devModeExcludedPackageNamePatterns = Collections.unmodifiableSet(excludedPackageNamePatterns);
+ }
+
private Set<Pattern> parseExcludedPackageNamePatterns(String commaDelimitedPackagePatterns) {
Set<String> packagePatterns = TextParseUtil.commaDelimitedStringToSet(commaDelimitedPackagePatterns);
Set<Pattern> packageNamePatterns = new HashSet<>();
@@ -153,6 +174,14 @@ public class OgnlUtil {
this.excludedPackageNames = Collections.unmodifiableSet(excludedPackageNames);
}
+ @Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAMES, required = false)
+ protected void setDevModeExcludedPackageNames(String commaDelimitedPackageNames) {
+ Set<String> excludedPackageNames = new HashSet<>();
+ excludedPackageNames.addAll(this.devModeExcludedPackageNames);
+ excludedPackageNames.addAll(parseExcludedPackageNames(commaDelimitedPackageNames));
+ this.devModeExcludedPackageNames = Collections.unmodifiableSet(excludedPackageNames);
+ }
+
private Set<String> parseExcludedPackageNames(String commaDelimitedPackageNames) {
return TextParseUtil.commaDelimitedStringToSet(commaDelimitedPackageNames);
}
@@ -428,17 +457,15 @@ public class OgnlUtil {
* @throws OgnlException in case of ognl errors
*/
public void setValue(final String name, final Map<String, Object> context, final Object root, final Object value) throws OgnlException {
- compileAndExecute(name, context, new OgnlTask<Void>() {
- public Void execute(Object tree) throws OgnlException {
- if (isEvalExpression(tree, context)) {
- throw new OgnlException("Eval expression/chained expressions cannot be used as parameter name");
- }
- if (isArithmeticExpression(tree, context)) {
- throw new OgnlException("Arithmetic expressions cannot be used as parameter name");
- }
- Ognl.setValue(tree, context, root, value);
- return null;
+ compileAndExecute(name, context, (OgnlTask<Void>) tree -> {
+ if (isEvalExpression(tree, context)) {
+ throw new OgnlException("Eval expression/chained expressions cannot be used as parameter name");
}
+ if (isArithmeticExpression(tree, context)) {
+ throw new OgnlException("Arithmetic expressions cannot be used as parameter name");
+ }
+ Ognl.setValue(tree, context, root, value);
+ return null;
});
}
@@ -447,7 +474,7 @@ public class OgnlUtil {
SimpleNode node = (SimpleNode) tree;
OgnlContext ognlContext = null;
- if (context!=null && context instanceof OgnlContext) {
+ if (context instanceof OgnlContext) {
ognlContext = (OgnlContext) context;
}
return node.isEvalChain(ognlContext) || node.isSequence(ognlContext);
@@ -460,7 +487,7 @@ public class OgnlUtil {
SimpleNode node = (SimpleNode) tree;
OgnlContext ognlContext = null;
- if (context!=null && context instanceof OgnlContext) {
+ if (context instanceof OgnlContext) {
ognlContext = (OgnlContext) context;
}
return node.isOperation(ognlContext);
@@ -473,7 +500,7 @@ public class OgnlUtil {
SimpleNode node = (SimpleNode) tree;
OgnlContext ognlContext = null;
- if (context!=null && context instanceof OgnlContext) {
+ if (context instanceof OgnlContext) {
ognlContext = (OgnlContext) context;
}
return node.isSimpleMethod(ognlContext) && !node.isChain(ognlContext);
@@ -482,27 +509,15 @@ public class OgnlUtil {
}
public Object getValue(final String name, final Map<String, Object> context, final Object root) throws OgnlException {
- return compileAndExecute(name, context, new OgnlTask<Object>() {
- public Object execute(Object tree) throws OgnlException {
- return Ognl.getValue(tree, context, root);
- }
- });
+ return compileAndExecute(name, context, tree -> Ognl.getValue(tree, context, root));
}
public Object callMethod(final String name, final Map<String, Object> context, final Object root) throws OgnlException {
- return compileAndExecuteMethod(name, context, new OgnlTask<Object>() {
- public Object execute(Object tree) throws OgnlException {
- return Ognl.getValue(tree, context, root);
- }
- });
+ return compileAndExecuteMethod(name, context, tree -> Ognl.getValue(tree, context, root));
}
- public Object getValue(final String name, final Map<String, Object> context, final Object root, final Class resultType) throws OgnlException {
- return compileAndExecute(name, context, new OgnlTask<Object>() {
- public Object execute(Object tree) throws OgnlException {
- return Ognl.getValue(tree, context, root, resultType);
- }
- });
+ public Object getValue(final String name, final Map<String, Object> context, final Object root, final Class<?> resultType) throws OgnlException {
+ return compileAndExecute(name, context, tree -> Ognl.getValue(tree, context, root, resultType));
}
@@ -553,11 +568,7 @@ public class OgnlUtil {
}
public Object compile(String expression, Map<String, Object> context) throws OgnlException {
- return compileAndExecute(expression,context,new OgnlTask<Object>() {
- public Object execute(Object tree) throws OgnlException {
- return tree;
- }
- });
+ return compileAndExecute(expression, context, tree -> tree);
}
private void checkEnableEvalExpression(Object tree, Map<String, Object> context) throws OgnlException {
@@ -608,8 +619,8 @@ public class OgnlUtil {
return;
}
- final Map contextFrom = createDefaultContext(from);
- final Map contextTo = createDefaultContext(to);
+ final Map<String, Object> contextFrom = createDefaultContext(from);
+ final Map<String, Object> contextTo = createDefaultContext(to);
PropertyDescriptor[] fromPds;
PropertyDescriptor[] toPds;
@@ -646,12 +657,10 @@ public class OgnlUtil {
PropertyDescriptor toPd = toPdHash.get(fromPd.getName());
if ((toPd != null) && (toPd.getWriteMethod() != null)) {
try {
- compileAndExecute(fromPd.getName(), context, new OgnlTask<Object>() {
- public Void execute(Object expr) throws OgnlException {
- Object value = Ognl.getValue(expr, contextFrom, from);
- Ognl.setValue(expr, contextTo, to, value);
- return null;
- }
+ compileAndExecute(fromPd.getName(), context, expr -> {
+ Object value = Ognl.getValue(expr, contextFrom, from);
+ Ognl.setValue(expr, contextTo, to, value);
+ return null;
});
} catch (OgnlException e) {
@@ -700,7 +709,7 @@ public class OgnlUtil {
* @return property descriptors.
* @throws IntrospectionException is thrown if an exception occurs during introspection.
*/
- public PropertyDescriptor[] getPropertyDescriptors(Class clazz) throws IntrospectionException {
+ public PropertyDescriptor[] getPropertyDescriptors(Class<?> clazz) throws IntrospectionException {
BeanInfo beanInfo = getBeanInfo(clazz);
return beanInfo.getPropertyDescriptors();
}
@@ -719,17 +728,13 @@ public class OgnlUtil {
*/
public Map<String, Object> getBeanMap(final Object source) throws IntrospectionException, OgnlException {
Map<String, Object> beanMap = new HashMap<>();
- final Map sourceMap = createDefaultContext(source);
+ final Map<String, Object> sourceMap = createDefaultContext(source);
PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(source);
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
final String propertyName = propertyDescriptor.getDisplayName();
Method readMethod = propertyDescriptor.getReadMethod();
if (readMethod != null) {
- final Object value = compileAndExecute(propertyName, null, new OgnlTask<Object>() {
- public Object execute(Object expr) throws OgnlException {
- return Ognl.getValue(expr, sourceMap, source);
- }
- });
+ final Object value = compileAndExecute(propertyName, null, expr -> Ognl.getValue(expr, sourceMap, source));
beanMap.put(propertyName, value);
} else {
beanMap.put(propertyName, "There is no read method for " + propertyName);
@@ -757,7 +762,7 @@ public class OgnlUtil {
* @return java bean info.
* @throws IntrospectionException is thrown if an exception occurs during introspection.
*/
- public BeanInfo getBeanInfo(Class clazz) throws IntrospectionException {
+ public BeanInfo getBeanInfo(Class<?> clazz) throws IntrospectionException {
synchronized (beanInfoCache) {
BeanInfo beanInfo = beanInfoCache.get(clazz);
if (beanInfo == null) {
@@ -798,13 +803,17 @@ public class OgnlUtil {
}
SecurityMemberAccess memberAccess = new SecurityMemberAccess(allowStaticMethodAccess, allowStaticFieldAccess);
+ memberAccess.setDisallowProxyMemberAccess(disallowProxyMemberAccess);
+
if (devMode) {
- LOG.warn("Working in devMode, ignoring internal security");
+ LOG.warn("Working in devMode, using devMode excluded classes and packages!");
+ memberAccess.setExcludedClasses(devModeExcludedClasses);
+ memberAccess.setExcludedPackageNamePatterns(devModeExcludedPackageNamePatterns);
+ memberAccess.setExcludedPackageNames(devModeExcludedPackageNames);
} else {
memberAccess.setExcludedClasses(excludedClasses);
memberAccess.setExcludedPackageNamePatterns(excludedPackageNamePatterns);
memberAccess.setExcludedPackageNames(excludedPackageNames);
- memberAccess.setDisallowProxyMemberAccess(disallowProxyMemberAccess);
}
return Ognl.createDefaultContext(root, memberAccess, resolver, defaultConverter);
diff --git a/core/src/main/java/org/apache/struts2/StrutsConstants.java b/core/src/main/java/org/apache/struts2/StrutsConstants.java
index 2d12095..a55ed62 100644
--- a/core/src/main/java/org/apache/struts2/StrutsConstants.java
+++ b/core/src/main/java/org/apache/struts2/StrutsConstants.java
@@ -319,6 +319,11 @@ public final class StrutsConstants {
public static final String STRUTS_EXCLUDED_PACKAGE_NAME_PATTERNS = "struts.excludedPackageNamePatterns";
public static final String STRUTS_EXCLUDED_PACKAGE_NAMES = "struts.excludedPackageNames";
+ /** Comma delimited set of excluded classes and package names which cannot be accessed via expressions in devMode */
+ public static final String STRUTS_DEV_MODE_EXCLUDED_CLASSES = "struts.devMode.excludedClasses";
+ public static final String STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAME_PATTERNS = "struts.devMode.excludedPackageNamePatterns";
+ public static final String STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAMES = "struts.devMode.excludedPackageNames";
+
/** Dedicated services to check if passed string is excluded/accepted */
public static final String STRUTS_EXCLUDED_PATTERNS_CHECKER = "struts.excludedPatterns.checker";
public static final String STRUTS_ACCEPTED_PATTERNS_CHECKER = "struts.acceptedPatterns.checker";
diff --git a/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java b/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java
index 904296f..5ef6c4d 100644
--- a/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java
+++ b/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java
@@ -129,6 +129,9 @@ public class ConstantConfig {
private Set<Class<?>> excludedClasses;
private List<Pattern> excludedPackageNamePatterns;
private Set<String> excludedPackageNames;
+ private Set<Class<?>> devModeExcludedClasses;
+ private List<Pattern> devModeExcludedPackageNamePatterns;
+ private Set<String> devModeExcludedPackageNames;
private BeanConfig excludedPatternsChecker;
private BeanConfig acceptedPatternsChecker;
private Set<Pattern> overrideExcludedPatterns;
@@ -257,6 +260,9 @@ public class ConstantConfig {
map.put(StrutsConstants.STRUTS_EXCLUDED_CLASSES, classesToString(excludedClasses));
map.put(StrutsConstants.STRUTS_EXCLUDED_PACKAGE_NAME_PATTERNS, StringUtils.join(excludedPackageNamePatterns, ','));
map.put(StrutsConstants.STRUTS_EXCLUDED_PACKAGE_NAMES, StringUtils.join(excludedPackageNames, ','));
+ map.put(StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_CLASSES, classesToString(devModeExcludedClasses));
+ map.put(StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAME_PATTERNS, StringUtils.join(devModeExcludedPackageNamePatterns, ','));
+ map.put(StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAMES, StringUtils.join(devModeExcludedPackageNames, ','));
map.put(StrutsConstants.STRUTS_EXCLUDED_PATTERNS_CHECKER, beanConfToString(excludedPatternsChecker));
map.put(StrutsConstants.STRUTS_ACCEPTED_PATTERNS_CHECKER, beanConfToString(acceptedPatternsChecker));
map.put(StrutsConstants.STRUTS_OVERRIDE_EXCLUDED_PATTERNS, StringUtils.join(overrideExcludedPatterns, ','));
@@ -1209,6 +1215,30 @@ public class ConstantConfig {
this.excludedPackageNames = excludedPackageNames;
}
+ public Set<Class<?>> getDevModeExcludedClasses() {
+ return devModeExcludedClasses;
+ }
+
+ public void setDevModeExcludedClasses(Set<Class<?>> devModeExcludedClasses) {
+ this.devModeExcludedClasses = devModeExcludedClasses;
+ }
+
+ public List<Pattern> getDevModeExcludedPackageNamePatterns() {
+ return devModeExcludedPackageNamePatterns;
+ }
+
+ public void setDevModeExcludedPackageNamePatterns(List<Pattern> devModeExcludedPackageNamePatterns) {
+ this.devModeExcludedPackageNamePatterns = devModeExcludedPackageNamePatterns;
+ }
+
+ public Set<String> getDevModeExcludedPackageNames() {
+ return devModeExcludedPackageNames;
+ }
+
+ public void setDevModeExcludedPackageNames(Set<String> devModeExcludedPackageNames) {
+ this.devModeExcludedPackageNames = devModeExcludedPackageNames;
+ }
+
public BeanConfig getExcludedPatternsChecker() {
return excludedPatternsChecker;
}
diff --git a/core/src/main/resources/struts-default.xml b/core/src/main/resources/struts-default.xml
index 9da9daf..0988d87 100644
--- a/core/src/main/resources/struts-default.xml
+++ b/core/src/main/resources/struts-default.xml
@@ -48,9 +48,21 @@
sun.misc.Unsafe,
com.opensymphony.xwork2.ActionContext" />
+ <constant name="struts.devMode.excludedClasses"
+ value="
+ java.lang.Object,
+ java.lang.Runtime,
+ java.lang.System,
+ java.lang.Class,
+ java.lang.ClassLoader,
+ java.lang.Shutdown,
+ java.lang.ProcessBuilder,
+ sun.misc.Unsafe" />
+
<!-- this must be valid regex, each '.' in package name must be escaped! -->
<!-- it's more flexible but slower than simple string comparison -->
<!-- constant name="struts.excludedPackageNamePatterns" value="^java\.lang\..*,^ognl.*,^(?!javax\.servlet\..+)(javax\..+)" / -->
+ <!-- constant name="struts.devMode.excludedPackageNamePatterns" value="^java\.lang\..*,^ognl.*,^(?!javax\.servlet\..+)(javax\..+)" / -->
<!-- this is simpler version of the above used with string comparison -->
<constant name="struts.excludedPackageNames"
@@ -75,6 +87,28 @@
com.opensymphony.xwork2.security.,
com.opensymphony.xwork2.util." />
+ <constant name="struts.devMode.excludedPackageNames"
+ value="
+ ognl.,
+ java.io.,
+ java.net.,
+ java.nio.,
+ javax.,
+ freemarker.core.,
+ freemarker.template.,
+ freemarker.ext.jsp.,
+ freemarker.ext.rhino.,
+ sun.misc.,
+ sun.reflect.,
+ javassist.,
+ org.apache.velocity.,
+ org.objectweb.asm.,
+ org.springframework.context.,
+ com.opensymphony.xwork2.inject.,
+ com.opensymphony.xwork2.ognl.,
+ com.opensymphony.xwork2.security.,
+ com.opensymphony.xwork2.util." />
+
<bean class="com.opensymphony.xwork2.ObjectFactory" name="struts"/>
<bean type="com.opensymphony.xwork2.factory.ResultFactory" name="struts" class="org.apache.struts2.factory.StrutsResultFactory" />
<bean type="com.opensymphony.xwork2.factory.ActionFactory" name="struts" class="com.opensymphony.xwork2.factory.DefaultActionFactory" />