diff --git a/apps/showcase/src/main/java/org/apache/struts2/showcase/fileupload/MultipleFileUploadUsingArrayAction.java b/apps/showcase/src/main/java/org/apache/struts2/showcase/fileupload/MultipleFileUploadUsingArrayAction.java
index b1a598543..dcf671e5e 100644
--- a/apps/showcase/src/main/java/org/apache/struts2/showcase/fileupload/MultipleFileUploadUsingArrayAction.java
+++ b/apps/showcase/src/main/java/org/apache/struts2/showcase/fileupload/MultipleFileUploadUsingArrayAction.java
@@ -32,9 +32,9 @@ import java.io.File;
*/
public class MultipleFileUploadUsingArrayAction extends ActionSupport {
- private File[] uploads;
- private String[] uploadFileNames;
- private String[] uploadContentTypes;
+ private File[] uploads = new File[0];
+ private String[] uploadFileNames = new String[0];
+ private String[] uploadContentTypes = new String[0];
public String upload() throws Exception {
diff --git a/apps/showcase/src/main/resources/struts-fileupload.xml b/apps/showcase/src/main/resources/struts-fileupload.xml
index a13739aa5..33be370ba 100644
--- a/apps/showcase/src/main/resources/struts-fileupload.xml
+++ b/apps/showcase/src/main/resources/struts-fileupload.xml
@@ -40,6 +40,7 @@
+ /WEB-INF/fileupload/multipleUploadUsingList.jsp
/WEB-INF/fileupload/multiple-success.jsp
@@ -49,6 +50,7 @@
+ /WEB-INF/fileupload/multipleUploadUsingArray.jsp
/WEB-INF/fileupload/multiple-success.jsp
diff --git a/apps/showcase/src/main/webapp/WEB-INF/tags/non-ui/ifTag/testIf.jsp b/apps/showcase/src/main/webapp/WEB-INF/tags/non-ui/ifTag/testIf.jsp
index f9fe49997..a0d52a677 100644
--- a/apps/showcase/src/main/webapp/WEB-INF/tags/non-ui/ifTag/testIf.jsp
+++ b/apps/showcase/src/main/webapp/WEB-INF/tags/non-ui/ifTag/testIf.jsp
@@ -18,6 +18,7 @@
* under the License.
*/
-->
+<%@page import="org.apache.struts2.showcase.hangman.HangmanConstants" %>
<%@taglib prefix="s" uri="/struts-tags" %>
@@ -635,5 +636,18 @@
+
+
+
+ A secondary test for this JSP visually verifies expression access to a public constant.
+ A direct access to the same public constant via scriptlet provides secondary verification.
+
+
+
+ Test public static (constant) access (expression). Value:
+
+
+ Test public static (constant) access (scriptlet). Value: <%=org.apache.struts2.showcase.hangman.HangmanConstants.HANGMAN_SESSION_KEY%>
+
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 371d3f498..d92ce008a 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
@@ -91,6 +91,7 @@ public class ConstantConfig {
private BeanConfig localeProvider;
private BeanConfig localeProviderFactory;
private String mapperIdParameterName;
+ private Boolean ognlAllowStaticFieldAccess;
private Boolean ognlAllowStaticMethodAccess;
private BeanConfig actionValidatorManager;
private BeanConfig valueStackFactory;
@@ -219,6 +220,7 @@ public class ConstantConfig {
map.put(StrutsConstants.STRUTS_LOCALE_PROVIDER, beanConfToString(localeProvider));
map.put(StrutsConstants.STRUTS_LOCALE_PROVIDER_FACTORY, beanConfToString(localeProviderFactory));
map.put(StrutsConstants.STRUTS_ID_PARAMETER_NAME, mapperIdParameterName);
+ map.put(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, Objects.toString(ognlAllowStaticFieldAccess, null));
map.put(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, Objects.toString(ognlAllowStaticMethodAccess, null));
map.put(StrutsConstants.STRUTS_ACTIONVALIDATORMANAGER, beanConfToString(actionValidatorManager));
map.put(StrutsConstants.STRUTS_VALUESTACKFACTORY, beanConfToString(valueStackFactory));
@@ -824,6 +826,14 @@ public class ConstantConfig {
this.mapperIdParameterName = mapperIdParameterName;
}
+ public Boolean getOgnlAllowStaticFieldAccess() {
+ return ognlAllowStaticFieldAccess;
+ }
+
+ public void setOgnlAllowStaticFieldAccess(Boolean ognlAllowStaticFieldAccess) {
+ this.ognlAllowStaticFieldAccess = ognlAllowStaticFieldAccess;
+ }
+
public Boolean getOgnlAllowStaticMethodAccess() {
return ognlAllowStaticMethodAccess;
}
diff --git a/core/src/main/resources/org/apache/struts2/default.properties b/core/src/main/resources/org/apache/struts2/default.properties
index a465567df..a441e77ba 100644
--- a/core/src/main/resources/org/apache/struts2/default.properties
+++ b/core/src/main/resources/org/apache/struts2/default.properties
@@ -203,6 +203,9 @@ struts.xslt.nocache=false
### Whether to always select the namespace to be everything before the last slash or not
struts.mapper.alwaysSelectFullNamespace=false
+### Whether to allow static field access in OGNL expressions or not
+struts.ognl.allowStaticFieldAccess=true
+
### Whether to allow static method access in OGNL expressions or not
struts.ognl.allowStaticMethodAccess=false
diff --git a/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlValueStackTest.java b/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlValueStackTest.java
index 9209e73bf..b10cba7c6 100644
--- a/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlValueStackTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlValueStackTest.java
@@ -19,15 +19,15 @@
package com.opensymphony.xwork2.ognl;
import com.opensymphony.xwork2.*;
-import com.opensymphony.xwork2.config.ConfigurationManager;
-import com.opensymphony.xwork2.config.ConfigurationProvider;
-import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
+import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
-import com.opensymphony.xwork2.inject.Container;
+import com.opensymphony.xwork2.inject.ContainerBuilder;
import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
+import com.opensymphony.xwork2.test.StubConfigurationProvider;
import com.opensymphony.xwork2.test.TestBean2;
import com.opensymphony.xwork2.util.*;
import com.opensymphony.xwork2.util.Foo;
+import com.opensymphony.xwork2.util.location.LocatableProperties;
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
import ognl.PropertyAccessor;
@@ -36,6 +36,7 @@ import java.math.BigDecimal;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
+import org.apache.struts2.StrutsConstants;
/**
@@ -43,10 +44,25 @@ import java.util.Map;
*/
public class OgnlValueStackTest extends XWorkTestCase {
+ // Fields for static field access test
+ public static final String STATIC_FINAL_PUBLIC_ATTRIBUTE = "Static_Final_Public_Attribute";
+ static final String STATIC_FINAL_PACKAGE_ATTRIBUTE = "Static_Final_Package_Attribute";
+ protected static final String STATIC_FINAL_PROTECTED_ATTRIBUTE = "Static_Final_Protected_Attribute";
+ private static final String STATIC_FINAL_PRIVATE_ATTRIBUTE = "Static_Final_Private_Attribute";
+ public static String STATIC_PUBLIC_ATTRIBUTE = "Static_Public_Attribute";
+ static String STATIC_PACKAGE_ATTRIBUTE = "Static_Package_Attribute";
+ protected static String STATIC_PROTECTED_ATTRIBUTE = "Static_Protected_Attribute";
+ private static String STATIC_PRIVATE_ATTRIBUTE = "Static_Private_Attribute";
+
+
public static Integer staticNullMethod() {
return null;
}
+ public static Integer staticInteger100Method() {
+ return 100;
+ }
+
private OgnlUtil ognlUtil;
@Override
@@ -66,9 +82,38 @@ public class OgnlValueStackTest extends XWorkTestCase {
container.getInstance(TextProvider.class, "system"), allowStaticMethodAccess, allowStaticFieldAccess);
container.inject(stack);
ognlUtil.setAllowStaticMethodAccess(Boolean.toString(allowStaticMethodAccess));
+ ognlUtil.setAllowStaticFieldAccess(Boolean.toString(allowStaticFieldAccess));
return stack;
}
+ /**
+ * @return current OgnlValueStackFactory instance from current container
+ */
+ private OgnlValueStackFactory getValueStackFactory() {
+ return (OgnlValueStackFactory) container.getInstance(ValueStackFactory.class);
+ }
+
+ /**
+ * Reloads container and gets a new OgnlValueStackFactory with specified new configuration.
+ * Intended for testing OgnlValueStack instance(s) that are minimally configured.
+ * This should help ensure no underlying configuration/injection side-effects are responsible
+ * for the behaviour of fundamental access control flags).
+ *
+ * @param allowStaticMethod new allowStaticMethod configuration
+ * @param allowStaticField new allowStaticField configuration
+ * @return a new OgnlValueStackFactory with specified new configuration
+ */
+ private OgnlValueStackFactory reloadValueStackFactory(Boolean allowStaticMethod, Boolean allowStaticField) {
+ try {
+ reloadTestContainerConfiguration(allowStaticMethod, allowStaticField);
+ }
+ catch (Exception ex) {
+ fail("Unable to reload container configuration and configure ognlValueStackFactory - exception: " + ex);
+ }
+
+ return getValueStackFactory();
+ }
+
public void testExpOverridesCanStackExpUp() throws Exception {
Map expr1 = new LinkedHashMap();
expr1.put("expr1", "'expr1value'");
@@ -580,7 +625,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
OgnlValueStack stack = createValueStack();
stack.push(dog);
assertNull(stack.findValue("nullMethod()"));
- assertNull(stack.findValue("@com.opensymphony.xwork2.util.OgnlValueStackTest@staticNullMethod()"));
+ assertNull(stack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticNullMethod()"));
}
public void testPetSoarBug() {
@@ -980,6 +1025,245 @@ public class OgnlValueStackTest extends XWorkTestCase {
assertEquals(null, stack.findValue("address.country.name", String.class));
}
+ /**
+ * Test a default OgnlValueStackFactory and OgnlValueStack generated by it
+ * when a default configuration is used.
+ */
+ public void testOgnlValueStackFromOgnlValueStackFactoryDefaultConfig() {
+ OgnlValueStackFactory ognlValueStackFactory = getValueStackFactory();
+ OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
+ Object accessedValue;
+
+ // An OgnlValueStackFactory using a container config with default (from XWorkConfigurationProvider)
+ // static access flag values present should prevent staticMethodAccess but allow staticFieldAccess.
+ assertFalse("OgnlValueStackFactory staticMethodAccess (default flags) not false?", ognlValueStackFactory.containerAllowsStaticMethodAccess());
+ assertTrue("OgnlValueStackFactory staticFieldAccess (default flags) not true?", ognlValueStackFactory.containerAllowsStaticFieldAccess());
+ // An OgnlValueStack created from the above OgnlValueStackFactory should allow public field access,
+ // but prevent non-public field access. It should also deny static method access.
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
+ assertNull("able to access static method (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
+ assertEquals("accessed static final public field value not equal to actual?", accessedValue, STATIC_FINAL_PUBLIC_ATTRIBUTE);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
+ assertEquals("accessed static public field value not equal to actual?", accessedValue, STATIC_PUBLIC_ATTRIBUTE);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
+ assertNull("accessed final package field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
+ assertNull("accessed package field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
+ assertNull("accessed final protected field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
+ assertNull("accessed protected field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
+ assertNull("accessed final private field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
+ assertNull("accessed private field (result not null) ?", accessedValue);
+ }
+
+ /**
+ * Test a raw OgnlValueStackFactory and OgnlValueStack generated by it
+ * when no static access flags are set (not present in configuration).
+ */
+ public void testOgnlValueStackFromOgnlValueStackFactoryNoFlagsSet() {
+ OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(null, null);
+ OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
+ Object accessedValue;
+
+ // An OgnlValueStackFactory using a container config with no static access flag values present
+ // (such as from a DefaultConfiguration vs. XWorkConfigurationProvider) should
+ // prevent staticMethodAccess AND prevent staticFieldAccess.
+ // Note: Under normal circumstances, explicit static access configuration flags should be present,
+ // but this specific check verifies what happens if those configuration flags are not present.
+ assertFalse("OgnlValueStackFactory staticMethodAccess (no flag present) not false?", ognlValueStackFactory.containerAllowsStaticMethodAccess());
+ assertFalse("OgnlValueStackFactory staticFieldAccess (no flag present) not false?", ognlValueStackFactory.containerAllowsStaticFieldAccess());
+ // An OgnlValueStack created from the above OgnlValueStackFactory should prevent public field access,
+ // and prevent non-public field access. It should also deny static method access.
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
+ assertNull("able to access static method (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
+ assertNull("able to access static final public field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
+ assertNull("able to access static public field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
+ assertNull("accessed final package field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
+ assertNull("accessed package field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
+ assertNull("accessed final protected field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
+ assertNull("accessed protected field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
+ assertNull("accessed final private field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
+ assertNull("accessed private field (result not null) ?", accessedValue);
+ }
+
+ /**
+ * Test a raw OgnlValueStackFactory and OgnlValueStack generated by it
+ * when both static access flags are set to false.
+ */
+ public void testOgnlValueStackFromOgnlValueStackFactoryNoStaticAccess() {
+ OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(false, false);
+ OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
+ Object accessedValue;
+
+ // An OgnlValueStackFactory using a container config with both static access flags set false should
+ // prevent staticMethodAccess AND prevent staticFieldAccess.
+ assertFalse("OgnlValueStackFactory staticMethodAccess (set false) not false?", ognlValueStackFactory.containerAllowsStaticMethodAccess());
+ assertFalse("OgnlValueStackFactory staticFieldAccess (set false) not false?", ognlValueStackFactory.containerAllowsStaticFieldAccess());
+ // An OgnlValueStack created from the above OgnlValueStackFactory should prevent public field access,
+ // and prevent non-public field access. It should also deny static method access.
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
+ assertNull("able to access static method (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
+ assertNull("able to access static final public field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
+ assertNull("able to access static public field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
+ assertNull("accessed final package field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
+ assertNull("accessed package field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
+ assertNull("accessed final protected field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
+ assertNull("accessed protected field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
+ assertNull("accessed final private field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
+ assertNull("accessed private field (result not null) ?", accessedValue);
+ }
+
+ /**
+ * Test a raw OgnlValueStackFactory and OgnlValueStack generated by it
+ * when both static access flags are set to true.
+ */
+ public void testOgnlValueStackFromOgnlValueStackFactoryAllStaticAccess() {
+ OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(true, true);
+ OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
+ Object accessedValue;
+
+ // An OgnlValueStackFactory using a container config with both static access flags set true should
+ // allow both staticMethodAccess AND staticFieldAccess.
+ assertTrue("OgnlValueStackFactory staticMethodAccess (set true) not true?", ognlValueStackFactory.containerAllowsStaticMethodAccess());
+ assertTrue("OgnlValueStackFactory staticFieldAccess (set true) not true?", ognlValueStackFactory.containerAllowsStaticFieldAccess());
+ // An OgnlValueStack created from the above OgnlValueStackFactory should allow public field access,
+ // but prevent non-public field access. It should also allow static method access.
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
+ assertNotNull("unable to access static method (result null) ?", accessedValue);
+ assertEquals("accessed static method result not equal to expected?", accessedValue, staticInteger100Method());
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
+ assertEquals("accessed static final public field value not equal to actual?", accessedValue, STATIC_FINAL_PUBLIC_ATTRIBUTE);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
+ assertEquals("accessed static public field value not equal to actual?", accessedValue, STATIC_PUBLIC_ATTRIBUTE);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
+ assertNull("accessed final package field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
+ assertNull("accessed package field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
+ assertNull("accessed final protected field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
+ assertNull("accessed protected field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
+ assertNull("accessed final private field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
+ assertNull("accessed private field (result not null) ?", accessedValue);
+ }
+
+ /**
+ * Test a raw OgnlValueStackFactory and OgnlValueStack generated by it
+ * when static method access flag is true, static field access flag is false.
+ */
+ public void testOgnlValueStackFromOgnlValueStackFactoryOnlyStaticMethodAccess() {
+ OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(true, false);
+ OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
+ Object accessedValue;
+
+ // An OgnlValueStackFactory using a container config with static method access flag true, static field access false should
+ // allow staticMethodAccess but deny staticFieldAccess.
+ assertTrue("OgnlValueStackFactory staticMethodAccess (set true) not true?", ognlValueStackFactory.containerAllowsStaticMethodAccess());
+ assertFalse("OgnlValueStackFactory staticFieldAccess (set false) not false?", ognlValueStackFactory.containerAllowsStaticFieldAccess());
+ // An OgnlValueStack created from the above OgnlValueStackFactory should deny public field access,
+ // and also prevent non-public field access. It should also allow static method access.
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
+ assertNotNull("unable to access static method (result null) ?", accessedValue);
+ assertEquals("accessed static method result not equal to expected?", accessedValue, staticInteger100Method());
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
+ assertNull("able to access static final public field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
+ assertNull("able to access static public field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
+ assertNull("accessed final package field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
+ assertNull("accessed package field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
+ assertNull("accessed final protected field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
+ assertNull("accessed protected field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
+ assertNull("accessed final private field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
+ assertNull("accessed private field (result not null) ?", accessedValue);
+ }
+
+ /**
+ * Test a raw OgnlValueStackFactory and OgnlValueStack generated by it
+ * when static method access flag is false, static field access flag is true.
+ */
+ public void testOgnlValueStackFromOgnlValueStackFactoryOnlyStaticFieldAccess() {
+ OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(false, true);
+ OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
+ Object accessedValue;
+
+ // An OgnlValueStackFactory using a container config with static method access flag false, static field access true should
+ // deny staticMethodAccess but allow staticFieldAccess.
+ assertFalse("OgnlValueStackFactory staticMethodAccess (set false) not false?", ognlValueStackFactory.containerAllowsStaticMethodAccess());
+ assertTrue("OgnlValueStackFactory staticFieldAccess (set true) not true?", ognlValueStackFactory.containerAllowsStaticFieldAccess());
+ // An OgnlValueStack created from the above OgnlValueStackFactory should allow public field access,
+ // but prevent non-public field access. It should also deny static method access.
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
+ assertNull("able to access static method (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
+ assertEquals("accessed static final public field value not equal to actual?", accessedValue, STATIC_FINAL_PUBLIC_ATTRIBUTE);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
+ assertEquals("accessed static public field value not equal to actual?", accessedValue, STATIC_PUBLIC_ATTRIBUTE);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
+ assertNull("accessed final package field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
+ assertNull("accessed package field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
+ assertNull("accessed final protected field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
+ assertNull("accessed protected field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
+ assertNull("accessed final private field (result not null) ?", accessedValue);
+ accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
+ assertNull("accessed private field (result not null) ?", accessedValue);
+ }
+
+ private void reloadTestContainerConfiguration(Boolean allowStaticMethod, Boolean allowStaticField) throws Exception {
+ loadConfigurationProviders(new StubConfigurationProvider() {
+ @Override
+ public void register(ContainerBuilder builder,
+ LocatableProperties props) throws ConfigurationException {
+ // null values simulate undefined (by removing).
+ // undefined values then should be evaluated to false
+ if (props.containsKey(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS)) {
+ props.remove(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS);
+ }
+ if (props.containsKey(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS)) {
+ props.remove(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS);
+ }
+ if (allowStaticMethod != null) {
+ props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, "" + allowStaticMethod);
+ }
+ if (allowStaticField != null) {
+ props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, "" + allowStaticField);
+ }
+ }
+ });
+ ognlUtil = container.getInstance(OgnlUtil.class);
+ }
+
class BadJavaBean {
private int count;
private int count2;