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" />