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/01/12 11:09:19 UTC

[struts] 01/03: WW-5054 Allows omit class/packages restrictions 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 8326535c3e2637352f8d4b7801059fbf34ee4e46
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sun Jan 12 12:07:56 2020 +0100

    WW-5054 Allows omit class/packages restrictions in devMode
---
 .../com/opensymphony/xwork2/ognl/OgnlUtil.java     |  39 ++++++-
 .../debugging/DebuggingInterceptor.java            | 128 +++++++++++----------
 .../interceptor/debugging/ObjectToHTMLWriter.java  |  36 ++++--
 3 files changed, 126 insertions(+), 77 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 01d5374..9798974 100644
--- a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java
+++ b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java
@@ -65,6 +65,10 @@ public class OgnlUtil {
     private Set<Pattern> excludedPackageNamePatterns;
     private Set<String> excludedPackageNames;
 
+    private Set<Class<?>> excludedClassesCopy;
+    private Set<Pattern> excludedPackageNamePatternsCopy;
+    private Set<String> excludedPackageNamesCopy;
+
     private Container container;
     private boolean allowStaticFieldAccess = true;
     private boolean allowStaticMethodAccess;
@@ -111,6 +115,33 @@ public class OgnlUtil {
         this.excludedClasses = Collections.unmodifiableSet(excludedClasses);
     }
 
+    public void avoidAccessControl() {
+        if (devMode) {
+            LOG.warn("Cleans up excluded classes and packages in devMode");
+            excludedClassesCopy = new HashSet<>(excludedClasses);
+            excludedClasses = Collections.unmodifiableSet(new HashSet<>());
+
+            excludedPackageNamePatternsCopy = new HashSet<>(excludedPackageNamePatterns);
+            excludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>());
+
+            excludedPackageNamesCopy = new HashSet<>(excludedPackageNames);
+            excludedPackageNames = Collections.unmodifiableSet(new HashSet<>());
+        }
+    }
+    public void restoreAccessControl() {
+        if (devMode) {
+            LOG.warn("Restores excluded classes and packages in devMode");
+            excludedClasses = Collections.unmodifiableSet(excludedClassesCopy);
+            excludedClassesCopy = null;
+
+            excludedPackageNamePatterns = Collections.unmodifiableSet(excludedPackageNamePatternsCopy);
+            excludedPackageNamePatternsCopy = null;
+
+            excludedPackageNames = Collections.unmodifiableSet(excludedPackageNamesCopy);
+            excludedPackageNamesCopy = null;
+        }
+    }
+
     private Set<Class<?>> parseExcludedClasses(String commaDelimitedClasses) {
         Set<String> classNames = TextParseUtil.commaDelimitedStringToSet(commaDelimitedClasses);
         Set<Class<?>> classes = new HashSet<>();
@@ -339,7 +370,7 @@ public class OgnlUtil {
      *                                problems setting the properties
      */
     public void setProperties(Map<String, ?> properties, Object o, boolean throwPropertyExceptions) {
-        Map context = createDefaultContext(o, null);
+        Map context = createDefaultContext(o);
         setProperties(properties, o, context, throwPropertyExceptions);
     }
 
@@ -608,8 +639,8 @@ public class OgnlUtil {
             return;
         }
 
-        final Map contextFrom = createDefaultContext(from, null);
-        final Map contextTo = createDefaultContext(to, null);
+        final Map contextFrom = createDefaultContext(from);
+        final Map contextTo = createDefaultContext(to);
 
         PropertyDescriptor[] fromPds;
         PropertyDescriptor[] toPds;
@@ -719,7 +750,7 @@ 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, null);
+        final Map sourceMap = createDefaultContext(source);
         PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(source);
         for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
             final String propertyName = propertyDescriptor.getDisplayName();
diff --git a/core/src/main/java/org/apache/struts2/interceptor/debugging/DebuggingInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/debugging/DebuggingInterceptor.java
index 7e995f8..ff7e2d3 100644
--- a/core/src/main/java/org/apache/struts2/interceptor/debugging/DebuggingInterceptor.java
+++ b/core/src/main/java/org/apache/struts2/interceptor/debugging/DebuggingInterceptor.java
@@ -23,6 +23,7 @@ import com.opensymphony.xwork2.ActionInvocation;
 import com.opensymphony.xwork2.inject.Inject;
 import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
 import com.opensymphony.xwork2.interceptor.PreResultListener;
+import com.opensymphony.xwork2.ognl.OgnlUtil;
 import com.opensymphony.xwork2.util.ValueStack;
 import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
 import org.apache.logging.log4j.LogManager;
@@ -145,18 +146,20 @@ public class DebuggingInterceptor extends AbstractInterceptor {
         boolean devMode = devModeOverride != null ? devModeOverride : this.devMode;
         if (devMode) {
             final ActionContext ctx = ActionContext.getContext();
-            String type = getParameter(DEBUG_PARAM);
-            ctx.getParameters().remove(DEBUG_PARAM);
-            if (XML_MODE.equals(type)) {
-                inv.addPreResultListener(
+            ctx.getInstance(OgnlUtil.class).avoidAccessControl();;
+            try {
+                String type = getParameter(DEBUG_PARAM);
+                ctx.getParameters().remove(DEBUG_PARAM);
+                if (XML_MODE.equals(type)) {
+                    inv.addPreResultListener(
                         new PreResultListener() {
                             public void beforeResult(ActionInvocation inv, String result) {
                                 printContext();
                             }
                         });
-            } else if (CONSOLE_MODE.equals(type)) {
-                consoleEnabled = true;
-                inv.addPreResultListener(
+                } else if (CONSOLE_MODE.equals(type)) {
+                    consoleEnabled = true;
+                    inv.addPreResultListener(
                         new PreResultListener() {
                             public void beforeResult(ActionInvocation inv, String actionResult) {
                                 String xml = "";
@@ -183,64 +186,67 @@ public class DebuggingInterceptor extends AbstractInterceptor {
 
                             }
                         });
-            } else if (COMMAND_MODE.equals(type)) {
-                ValueStack stack = (ValueStack) ctx.getSession().get(SESSION_KEY);
-                if (stack == null) {
-                    //allows it to be embedded on another page
-                    stack = (ValueStack) ctx.get(ActionContext.VALUE_STACK);
-                    ctx.getSession().put(SESSION_KEY, stack);
-                }
-                String cmd = getParameter(EXPRESSION_PARAM);
+                } else if (COMMAND_MODE.equals(type)) {
+                    ValueStack stack = (ValueStack) ctx.getSession().get(SESSION_KEY);
+                    if (stack == null) {
+                        //allows it to be embedded on another page
+                        stack = (ValueStack) ctx.get(ActionContext.VALUE_STACK);
+                        ctx.getSession().put(SESSION_KEY, stack);
+                    }
+                    String cmd = getParameter(EXPRESSION_PARAM);
 
-                ServletActionContext.getRequest().setAttribute("decorator", "none");
-                HttpServletResponse res = ServletActionContext.getResponse();
-                res.setContentType("text/plain");
+                    ServletActionContext.getRequest().setAttribute("decorator", "none");
+                    HttpServletResponse res = ServletActionContext.getResponse();
+                    res.setContentType("text/plain");
 
-                try (PrintWriter writer =
-                            ServletActionContext.getResponse().getWriter()) {
-                    writer.print(stack.findValue(cmd));
-                } catch (IOException ex) {
-                    ex.printStackTrace();
-                }
-                cont = false;
-            } else if (BROWSER_MODE.equals(type)) {
-                actionOnly = true;
-                inv.addPreResultListener(
-                    new PreResultListener() {
-                        public void beforeResult(ActionInvocation inv, String actionResult) {
-                            String rootObjectExpression = getParameter(OBJECT_PARAM);
-                            if (rootObjectExpression == null)
-                                rootObjectExpression = "#context";
-                            String decorate = getParameter(DECORATE_PARAM);
-                            ValueStack stack = (ValueStack) ctx.get(ActionContext.VALUE_STACK);
-                            Object rootObject = stack.findValue(rootObjectExpression);
-                            
-                            try (StringWriter writer = new StringWriter()) {
-                                ObjectToHTMLWriter htmlWriter = new ObjectToHTMLWriter(writer);
-                                htmlWriter.write(reflectionProvider, rootObject, rootObjectExpression);
-                                String html = writer.toString();
-                                writer.close();
-                                
-                                stack.set("debugHtml", html);
-                                
-                                //on the first request, response can be decorated
-                                //but we need plain text on the other ones
-                                if ("false".equals(decorate))
-                                    ServletActionContext.getRequest().setAttribute("decorator", "none");
-                                
-                                FreemarkerResult result = new FreemarkerResult();
-                                result.setFreemarkerManager(freemarkerManager);
-                                result.setContentType("text/html");
-                                result.setLocation("/org/apache/struts2/interceptor/debugging/browser.ftl");
-                                result.execute(inv);
-                            } catch (Exception ex) {
-                                LOG.error("Unable to create debugging console", ex);
-                            }
+                    try (PrintWriter writer =
+                             ServletActionContext.getResponse().getWriter()) {
+                        writer.print(stack.findValue(cmd));
+                    } catch (IOException ex) {
+                        ex.printStackTrace();
+                    }
+                    cont = false;
+                } else if (BROWSER_MODE.equals(type)) {
+                    actionOnly = true;
+                    inv.addPreResultListener(
+                        new PreResultListener() {
+                            public void beforeResult(ActionInvocation inv, String actionResult) {
+                                String rootObjectExpression = getParameter(OBJECT_PARAM);
+                                if (rootObjectExpression == null)
+                                    rootObjectExpression = "top";
+                                String decorate = getParameter(DECORATE_PARAM);
+                                ValueStack stack = (ValueStack) ctx.get(ActionContext.VALUE_STACK);
+                                Object rootObject = stack.findValue(rootObjectExpression);
+
+                                try (StringWriter writer = new StringWriter()) {
+                                    ObjectToHTMLWriter htmlWriter = new ObjectToHTMLWriter(writer);
+                                    htmlWriter.write(reflectionProvider, rootObject, rootObjectExpression);
+                                    String html = writer.toString();
+                                    writer.close();
+
+                                    stack.set("debugHtml", html);
+
+                                    //on the first request, response can be decorated
+                                    //but we need plain text on the other ones
+                                    if ("false".equals(decorate))
+                                        ServletActionContext.getRequest().setAttribute("decorator", "none");
+
+                                    FreemarkerResult result = new FreemarkerResult();
+                                    result.setFreemarkerManager(freemarkerManager);
+                                    result.setContentType("text/html");
+                                    result.setLocation("/org/apache/struts2/interceptor/debugging/browser.ftl");
+                                    result.execute(inv);
+                                } catch (Exception ex) {
+                                    LOG.error("Unable to create debugging console", ex);
+                                }
 
-                        }
-                    });
+                            }
+                        });
+                }
+            } finally {
+                ctx.getInstance(OgnlUtil.class).restoreAccessControl();
             }
-        } 
+        }
         if (cont) {
             try {
                 if (actionOnly) {
diff --git a/core/src/main/java/org/apache/struts2/interceptor/debugging/ObjectToHTMLWriter.java b/core/src/main/java/org/apache/struts2/interceptor/debugging/ObjectToHTMLWriter.java
index bad10b1..3374f73 100644
--- a/core/src/main/java/org/apache/struts2/interceptor/debugging/ObjectToHTMLWriter.java
+++ b/core/src/main/java/org/apache/struts2/interceptor/debugging/ObjectToHTMLWriter.java
@@ -20,6 +20,8 @@ package org.apache.struts2.interceptor.debugging;
 
 import com.opensymphony.xwork2.util.reflection.ReflectionException;
 import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 import java.beans.IntrospectionException;
 import java.io.Writer;
@@ -33,6 +35,9 @@ import java.util.Set;
  *
  */
 class ObjectToHTMLWriter {
+
+    private static final Logger LOG = LogManager.getLogger(ObjectToHTMLWriter.class);
+
     private PrettyPrintWriter prettyWriter;
 
     ObjectToHTMLWriter(Writer writer) {
@@ -40,36 +45,43 @@ class ObjectToHTMLWriter {
         this.prettyWriter.setEscape(false);
     }
 
-    @SuppressWarnings("unchecked")
     public void write(ReflectionProvider reflectionProvider, Object root, String expr) throws IntrospectionException,
         ReflectionException {
         prettyWriter.startNode("table");
         prettyWriter.addAttribute("class", "debugTable");
 
-        if (root instanceof Map) {
-            for (Object next : ((Map) root).entrySet()) {
-                Map.Entry property = (Map.Entry) next;
+        if (root == null) {
+            LOG.info("Root is null");
+            writeProperty("root", null, expr);
+        } else if (root instanceof Map) {
+            LOG.info("Root is a Map");
+            for (Object next : ((Map<?, ?>) root).entrySet()) {
+                Map.Entry<?, ?> property = (Map.Entry<?, ?>) next;
                 String key = property.getKey().toString();
                 Object value = property.getValue();
                 writeProperty(key, value, expr);
             }
         } else if (root instanceof List) {
-            List list = (List) root;
+            LOG.info("Root is a List");
+            List<?> list = (List<?>) root;
             for (int i = 0; i < list.size(); i++) {
                 Object element = list.get(i);
                 writeProperty(String.valueOf(i), element, expr);
             }
         } else if (root instanceof Set) {
-            Set set = (Set) root;
+            LOG.info("Root is a Set");
+            Set<?> set = (Set<?>) root;
             for (Object next : set) {
                 writeProperty("", next, expr);
             }
         } else if (root.getClass().isArray()) {
+            LOG.info("Root is an Array");
             Object[] objects = (Object[]) root;
             for (int i = 0; i < objects.length; i++) {
                 writeProperty(String.valueOf(i), objects[i], expr);
             }
         } else {
+            LOG.info("Root is {}", root.getClass());
             //print properties
             Map<String, Object> properties = reflectionProvider.getBeanMap(root);
             for (Map.Entry<String, Object> property : properties.entrySet()) {
@@ -99,9 +111,9 @@ class ObjectToHTMLWriter {
         //value cell
         prettyWriter.startNode("td");
         if (value != null) {
+            LOG.info("Writing property [{}] as [{}]", name, value);
             //if is is an empty collection or array, don't write a link
-            if (isEmptyCollection(value) || isEmptyMap(value) || (value.getClass()
-                    .isArray() && ((Object[]) value).length == 0)) {
+            if (isEmptyCollection(value) || isEmptyMap(value) || (value.getClass().isArray() && ((Object[]) value).length == 0)) {
                 prettyWriter.addAttribute("class", "emptyCollection");
                 prettyWriter.setValue("empty");
             } else {
@@ -118,7 +130,7 @@ class ObjectToHTMLWriter {
         prettyWriter.startNode("td");
         if (value != null) {
             prettyWriter.addAttribute("class", "typeColumn");
-            Class clazz = value.getClass();
+            Class<?> clazz = value.getClass();
             prettyWriter.setValue(clazz.getName());
         } else {
             prettyWriter.addAttribute("class", "nullValue");
@@ -135,7 +147,7 @@ class ObjectToHTMLWriter {
      */
     private boolean isEmptyMap(Object value) {
         try {
-            return value instanceof Map && ((Map) value).isEmpty();
+            return value instanceof Map && ((Map<?, ?>) value).isEmpty();
         } catch (Exception e) {
             return true;
         }
@@ -146,14 +158,14 @@ class ObjectToHTMLWriter {
      */
     private boolean isEmptyCollection(Object value) {
         try {
-            return value instanceof Collection && ((Collection) value).isEmpty();
+            return value instanceof Collection && ((Collection<?>) value).isEmpty();
         } catch (Exception e) {
             return true;
         }
     }
 
     private void writeValue(String name, Object value, String expr) {
-        Class clazz = value.getClass();
+        Class<?> clazz = value.getClass();
         if (clazz.isPrimitive() || Number.class.isAssignableFrom(clazz) ||
             clazz.equals(String.class) || Boolean.class.equals(clazz)) {
             prettyWriter.setValue(String.valueOf(value));