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 2015/09/28 20:43:24 UTC
[6/8] struts git commit: Merges security fixes from 2.3.24.1
Merges security fixes from 2.3.24.1
Conflicts:
apps/blank/pom.xml
apps/jboss-blank/pom.xml
apps/mailreader/pom.xml
apps/pom.xml
apps/portlet/pom.xml
apps/rest-showcase/pom.xml
apps/showcase/pom.xml
archetypes/pom.xml
archetypes/struts2-archetype-angularjs/pom.xml
archetypes/struts2-archetype-blank/pom.xml
archetypes/struts2-archetype-convention/pom.xml
archetypes/struts2-archetype-dbportlet/pom.xml
archetypes/struts2-archetype-plugin/pom.xml
archetypes/struts2-archetype-portlet/pom.xml
archetypes/struts2-archetype-starter/pom.xml
assembly/pom.xml
bom/pom.xml
bundles/admin/pom.xml
bundles/demo/pom.xml
bundles/pom.xml
core/pom.xml
plugins/bean-validation/pom.xml
plugins/cdi/pom.xml
plugins/codebehind/pom.xml
plugins/config-browser/pom.xml
plugins/convention/pom.xml
plugins/dojo/pom.xml
plugins/dwr/pom.xml
plugins/embeddedjsp/pom.xml
plugins/gxp/pom.xml
plugins/jasperreports/pom.xml
plugins/java8-support/pom.xml
plugins/javatemplates/pom.xml
plugins/jfreechart/pom.xml
plugins/json/pom.xml
plugins/junit/pom.xml
plugins/osgi/pom.xml
plugins/oval/pom.xml
plugins/pell-multipart/pom.xml
plugins/plexus/pom.xml
plugins/pom.xml
plugins/portlet-tiles/pom.xml
plugins/portlet/pom.xml
plugins/rest/pom.xml
plugins/sitegraph/pom.xml
plugins/sitemesh/pom.xml
plugins/spring/pom.xml
plugins/struts1/pom.xml
plugins/testng/pom.xml
plugins/tiles/pom.xml
plugins/tiles3/pom.xml
pom.xml
xwork-core/pom.xml
Project: http://git-wip-us.apache.org/repos/asf/struts/repo
Commit: http://git-wip-us.apache.org/repos/asf/struts/commit/dc270c2e
Tree: http://git-wip-us.apache.org/repos/asf/struts/tree/dc270c2e
Diff: http://git-wip-us.apache.org/repos/asf/struts/diff/dc270c2e
Branch: refs/heads/master
Commit: dc270c2e09f944c9ed8936cb0a74cd2dfadacf81
Parents: 0fac539 bfe51fc
Author: Lukasz Lenart <lu...@apache.org>
Authored: Wed Sep 23 08:42:01 2015 +0200
Committer: Lukasz Lenart <lu...@apache.org>
Committed: Wed Sep 23 08:42:01 2015 +0200
----------------------------------------------------------------------
.../DefaultExcludedPatternsChecker.java | 2 +-
.../interceptor/ParametersInterceptorTest.java | 6 ++--
.../DefaultExcludedPatternsCheckerTest.java | 35 ++++++++++++++++++++
3 files changed, 40 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/struts/blob/dc270c2e/core/src/main/java/com/opensymphony/xwork2/security/DefaultExcludedPatternsChecker.java
----------------------------------------------------------------------
diff --cc core/src/main/java/com/opensymphony/xwork2/security/DefaultExcludedPatternsChecker.java
index f6d48cd,0000000..13e091e
mode 100644,000000..100644
--- a/core/src/main/java/com/opensymphony/xwork2/security/DefaultExcludedPatternsChecker.java
+++ b/core/src/main/java/com/opensymphony/xwork2/security/DefaultExcludedPatternsChecker.java
@@@ -1,77 -1,0 +1,77 @@@
+package com.opensymphony.xwork2.security;
+
+import com.opensymphony.xwork2.XWorkConstants;
+import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.util.TextParseUtil;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+public class DefaultExcludedPatternsChecker implements ExcludedPatternsChecker {
+
+ private static final Logger LOG = LogManager.getLogger(DefaultExcludedPatternsChecker.class);
+
+ public static final String[] EXCLUDED_PATTERNS = {
- "(^|.*#)(dojo|struts|session|request|application|servlet(Request|Response)|parameters|context|_memberAccess)(\\.|\\[).*",
++ "(^|\\%\\{)((#?)(top(\\.|\\['|\\[\")|\\[\\d\\]\\.)?)(dojo|struts|session|request|response|application|servlet(Request|Response|Context)|parameters|context|_memberAccess)(\\.|\\[).*",
+ "^(action|method):.*"
+ };
+
+ private Set<Pattern> excludedPatterns;
+
+ public DefaultExcludedPatternsChecker() {
+ setExcludedPatterns(EXCLUDED_PATTERNS);
+ }
+
+ @Inject(value = XWorkConstants.OVERRIDE_EXCLUDED_PATTERNS, required = false)
+ public void setOverrideExcludePatterns(String excludePatterns) {
+ LOG.warn("Overriding excluded patterns [{}] with [{}], be aware that this affects all instances and safety of your application!",
+ XWorkConstants.OVERRIDE_EXCLUDED_PATTERNS, excludePatterns);
+ excludedPatterns = new HashSet<Pattern>();
+ for (String pattern : TextParseUtil.commaDelimitedStringToSet(excludePatterns)) {
+ excludedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
+ }
+ }
+
+ @Inject(value = XWorkConstants.ADDITIONAL_EXCLUDED_PATTERNS, required = false)
+ public void setAdditionalExcludePatterns(String excludePatterns) {
+ LOG.debug("Adding additional global patterns [{}] to excluded patterns!", excludePatterns);
+ for (String pattern : TextParseUtil.commaDelimitedStringToSet(excludePatterns)) {
+ excludedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
+ }
+ }
+
+ public void setExcludedPatterns(String commaDelimitedPatterns) {
+ setExcludedPatterns(TextParseUtil.commaDelimitedStringToSet(commaDelimitedPatterns));
+ }
+
+ public void setExcludedPatterns(String[] patterns) {
+ setExcludedPatterns(new HashSet<>(Arrays.asList(patterns)));
+ }
+
+ public void setExcludedPatterns(Set<String> patterns) {
+ LOG.trace("Sets excluded patterns [{}]", patterns);
+ excludedPatterns = new HashSet<>(patterns.size());
+ for (String pattern : patterns) {
+ excludedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
+ }
+ }
+
+ public IsExcluded isExcluded(String value) {
+ for (Pattern excludedPattern : excludedPatterns) {
+ if (excludedPattern.matcher(value).matches()) {
+ LOG.trace("[{}] matches excluded pattern [{}]", value, excludedPattern);
+ return IsExcluded.yes(excludedPattern);
+ }
+ }
+ return IsExcluded.no(excludedPatterns);
+ }
+
+ public Set<Pattern> getExcludedPatterns() {
+ return excludedPatterns;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/struts/blob/dc270c2e/core/src/test/java/com/opensymphony/xwork2/interceptor/ParametersInterceptorTest.java
----------------------------------------------------------------------
diff --cc core/src/test/java/com/opensymphony/xwork2/interceptor/ParametersInterceptorTest.java
index abf0f72,0000000..225d053
mode 100644,000000..100644
--- a/core/src/test/java/com/opensymphony/xwork2/interceptor/ParametersInterceptorTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/interceptor/ParametersInterceptorTest.java
@@@ -1,856 -1,0 +1,858 @@@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.opensymphony.xwork2.interceptor;
+
+import com.opensymphony.xwork2.*;
+import com.opensymphony.xwork2.config.entities.ActionConfig;
+import com.opensymphony.xwork2.config.providers.MockConfigurationProvider;
+import com.opensymphony.xwork2.config.providers.XWorkConfigurationProvider;
+import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
+import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
+import com.opensymphony.xwork2.mock.MockActionInvocation;
+import com.opensymphony.xwork2.ognl.OgnlValueStack;
+import com.opensymphony.xwork2.ognl.OgnlValueStackFactory;
+import com.opensymphony.xwork2.ognl.SecurityMemberAccess;
+import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
+import com.opensymphony.xwork2.util.CompoundRoot;
+import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.ValueStackFactory;
+import junit.framework.Assert;
+import ognl.OgnlContext;
+import ognl.PropertyAccessor;
+
+import java.io.File;
+import java.util.*;
+
+
+/**
+ * Unit test for {@link ParametersInterceptor}.
+ *
+ * @author Jason Carreira
+ */
+public class ParametersInterceptorTest extends XWorkTestCase {
+
+ public void testParameterNameAware() {
+ ParametersInterceptor pi = createParametersInterceptor();
+ final Map<String, Object> actual = injectValueStackFactory(pi);
+ ValueStack stack = createStubValueStack(actual);
+ final Map<String, Object> expected = new HashMap<String, Object>() {
+ {
+ put("fooKey", "fooValue");
+ put("barKey", "barValue");
+ }
+ };
+ Object a = new ParameterNameAware() {
+ public boolean acceptableParameterName(String parameterName) {
+ return expected.containsKey(parameterName);
+ }
+ };
+ final Map<String, Object> parameters = new HashMap<String, Object>() {
+ {
+ put("fooKey", "fooValue");
+ put("barKey", "barValue");
+ put("error-key", "error");
+ put("error key", "error");
+ put("error:key", "error");
+ put("error+key", "error");
+ put("test%test", "test%test");
+ }
+ };
+ pi.setParameters(a, stack, parameters);
+ assertEquals(expected, actual);
+ }
+
+ public void testInsecureParameters() throws Exception {
+ // given
+ loadConfigurationProviders(new XWorkConfigurationProvider(), new XmlConfigurationProvider("xwork-param-test.xml"));
+ final Map<String, Object> params = new HashMap<String, Object>() {
+ {
+ put("name", "(#context[\"xwork.MethodAccessor.denyMethodExecution\"]= new " +
+ "java.lang.Boolean(false), #_memberAccess[\"allowStaticMethodAccess\"]= new java.lang.Boolean(true), " +
+ "@java.lang.Runtime@getRuntime().exec('mkdir /tmp/PWNAGE'))(meh)");
+ put("top['name'](0)", "true");
+ }
+ };
+
+ ParametersInterceptor pi = new ParametersInterceptor();
+ container.inject(pi);
+ ValueStack vs = ActionContext.getContext().getValueStack();
+
+ // when
+ ValidateAction action = new ValidateAction();
+ pi.setParameters(action, vs, params);
+
+ // then
- assertEquals(1, action.getActionMessages().size());
++ assertEquals(2, action.getActionMessages().size());
+
+ String msg1 = action.getActionMessage(0);
++ String msg2 = action.getActionMessage(1);
+
- assertTrue(msg1.contains("Error setting expression 'top['name'](0)' with value 'true'"));
++ assertEquals("Error setting expression 'name' with value '(#context[\"xwork.MethodAccessor.denyMethodExecution\"]= new java.lang.Boolean(false), #_memberAccess[\"allowStaticMethodAccess\"]= new java.lang.Boolean(true), @java.lang.Runtime@getRuntime().exec('mkdir /tmp/PWNAGE'))(meh)'", msg1);
++ assertEquals("Error setting expression 'top['name'](0)' with value 'true'", msg2);
+ assertNull(action.getName());
+ }
+
+ public void testClassPollutionBlockedByPattern() throws Exception {
+ // given
+ final String pollution1 = "class.classLoader.jarPath";
+ final String pollution2 = "model.class.classLoader.jarPath";
+
+ loadConfigurationProviders(new XWorkConfigurationProvider(), new XmlConfigurationProvider("xwork-param-test.xml"));
+ final Map<String, Object> params = new HashMap<String, Object>() {
+ {
+ put(pollution1, "bad");
+ put(pollution2, "very bad");
+ }
+ };
+
+ final Map<String, Boolean> excluded = new HashMap<>();
+ ParametersInterceptor pi = new ParametersInterceptor() {
+
+ @Override
+ protected boolean isExcluded(String paramName) {
+ boolean result = super.isExcluded(paramName);
+ excluded.put(paramName, result);
+ return result;
+ }
+
+ };
+
+ container.inject(pi);
+ ValueStack vs = ActionContext.getContext().getValueStack();
+
+ // when
+ ValidateAction action = new ValidateAction();
+ pi.setParameters(action, vs, params);
+
+ // then
+ assertEquals(0, action.getActionMessages().size());
+ assertTrue(excluded.get(pollution1));
+ assertTrue(excluded.get(pollution2));
+ }
+
+ public void testClassPollutionBlockedByOgnl() throws Exception {
+ // given
+ final String pollution1 = "class.classLoader.jarPath";
+ final String pollution2 = "model.class.classLoader.jarPath";
+ final String pollution3 = "class.classLoader.defaultAssertionStatus";
+
+ loadConfigurationProviders(new XWorkConfigurationProvider(), new XmlConfigurationProvider("xwork-class-param-test.xml"));
+ final Map<String, Object> params = new HashMap<String, Object>() {
+ {
+ put(pollution1, "bad");
+ put(pollution2, "very bad");
+ put(pollution3, true);
+ }
+ };
+
+ final Map<String, Boolean> excluded = new HashMap<>();
+ ParametersInterceptor pi = new ParametersInterceptor() {
+
+ @Override
+ protected boolean isExcluded(String paramName) {
+ boolean result = super.isExcluded(paramName);
+ excluded.put(paramName, result);
+ return result;
+ }
+
+ };
+
+ container.inject(pi);
+ ValueStack vs = ActionContext.getContext().getValueStack();
+
+ // when
+ ValidateAction action = new ValidateAction();
+ pi.setParameters(action, vs, params);
+
+ // then
+ assertEquals(3, action.getActionMessages().size());
+
+ String msg1 = action.getActionMessage(0);
+ String msg2 = action.getActionMessage(1);
+ String msg3 = action.getActionMessage(2);
+
+ assertEquals("Error setting expression 'class.classLoader.defaultAssertionStatus' with value 'true'", msg1);
+ assertEquals("Error setting expression 'class.classLoader.jarPath' with value 'bad'", msg2);
+ assertEquals("Error setting expression 'model.class.classLoader.jarPath' with value 'very bad'", msg3);
+
+ assertFalse(excluded.get(pollution1));
+ assertFalse(excluded.get(pollution2));
+ assertFalse(excluded.get(pollution3));
+ }
+
+ public void testDoesNotAllowMethodInvocations() throws Exception {
+ Map<String, Object> params = new HashMap<>();
+ params.put("@java.lang.System@exit(1).dummy", "dumb value");
+
+ HashMap<String, Object> extraContext = new HashMap<>();
+ extraContext.put(ActionContext.PARAMETERS, params);
+
+ ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.MODEL_DRIVEN_PARAM_TEST, null, extraContext);
+ assertEquals(Action.SUCCESS, proxy.execute());
+
+ String property = System.getProperty("xwork.security.test");
+ assertNull(property);
+ }
+
+ public void testModelDrivenParameters() throws Exception {
+ Map<String, Object> params = new HashMap<>();
+ final String fooVal = "com.opensymphony.xwork2.interceptor.ParametersInterceptorTest.foo";
+ params.put("foo", fooVal);
+
+ final String nameVal = "com.opensymphony.xwork2.interceptor.ParametersInterceptorTest.name";
+ params.put("name", nameVal);
+ params.put("count", "15");
+
+ HashMap<String, Object> extraContext = new HashMap<>();
+ extraContext.put(ActionContext.PARAMETERS, params);
+
+ ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.MODEL_DRIVEN_PARAM_TEST, null, extraContext);
+ assertEquals(Action.SUCCESS, proxy.execute());
+
+ ModelDrivenAction action = (ModelDrivenAction) proxy.getAction();
+ TestBean model = (TestBean) action.getModel();
+ assertEquals(nameVal, model.getName());
+ assertEquals(15, model.getCount());
+ assertEquals(fooVal, action.getFoo());
+ }
+
+ public void testParametersDoesNotAffectSession() throws Exception {
+ Map<String, Object> params = new HashMap<>();
+ params.put("blah", "This is blah");
+ params.put("#session.foo", "Foo");
+ params.put("\u0023session[\'user\']", "0wn3d");
+ params.put("\\u0023session[\'user\']", "0wn3d");
+ params.put("\u0023session.user2", "0wn3d");
+ params.put("\\u0023session.user2", "0wn3d");
+ params.put("('\u0023'%20%2b%20'session[\'user3\']')(unused)", "0wn3d");
+ params.put("('\\u0023' + 'session[\\'user4\\']')(unused)", "0wn3d");
+ params.put("('\u0023'%2b'session[\'user5\']')(unused)", "0wn3d");
+ params.put("('\\u0023'%2b'session[\'user5\']')(unused)", "0wn3d");
+
+ HashMap<String, Object> extraContext = new HashMap<>();
+ extraContext.put(ActionContext.PARAMETERS, params);
+
+ ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, null, extraContext);
+ ValueStack stack = proxy.getInvocation().getStack();
+ HashMap<String, Object> session = new HashMap<>();
+ stack.getContext().put("session", session);
+ proxy.execute();
+ assertEquals("This is blah", ((SimpleAction) proxy.getAction()).getBlah());
+ assertNull(session.get("foo"));
+ assertNull(session.get("user"));
+ assertNull(session.get("user2"));
+ assertNull(session.get("user3"));
+ assertNull(session.get("user4"));
+ assertNull(session.get("user5"));
+ }
+
+ public void testArrayClassPollutionBlockedByPattern() throws Exception {
+ // given
+ final String pollution1 = "model.class.classLoader.jarPath";
+ final String pollution2 = "model['class']['classLoader']['jarPath']";
+ final String pollution3 = "model[\"class\"]['classLoader']['jarPath']";
+ final String pollution4 = "class.classLoader.jarPath";
+ final String pollution5 = "class['classLoader']['jarPath']";
+ final String pollution6 = "class[\"classLoader\"]['jarPath']";
+
+ loadConfigurationProviders(new XWorkConfigurationProvider(), new XmlConfigurationProvider("xwork-param-test.xml"));
+ final Map<String, Object> params = new HashMap<String, Object>() {
+ {
+ put(pollution1, "bad");
+ put(pollution2, "bad");
+ put(pollution3, "bad");
+ put(pollution4, "bad");
+ put(pollution5, "bad");
+ put(pollution6, "bad");
+ }
+ };
+
+ final Map<String, Boolean> excluded = new HashMap<String, Boolean>();
+ ParametersInterceptor pi = new ParametersInterceptor() {
+
+ @Override
+ protected boolean isExcluded(String paramName) {
+ boolean result = super.isExcluded(paramName);
+ excluded.put(paramName, result);
+ return result;
+ }
+
+ };
+
+ container.inject(pi);
+ ValueStack vs = ActionContext.getContext().getValueStack();
+
+ // when
+ ValidateAction action = new ValidateAction();
+ pi.setParameters(action, vs, params);
+
+ // then
+ assertEquals(0, action.getActionMessages().size());
+ assertTrue(excluded.get(pollution1));
+ assertTrue(excluded.get(pollution2));
+ assertTrue(excluded.get(pollution3));
+ assertTrue(excluded.get(pollution4));
+ assertTrue(excluded.get(pollution5));
+ assertTrue(excluded.get(pollution6));
+ }
+
+ public void testAccessToOgnlInternals() throws Exception {
+ // given
+ Map<String, Object> params = new HashMap<>();
+ params.put("blah", "This is blah");
+ params.put("('\\u0023_memberAccess[\\'allowStaticMethodAccess\\']')(meh)", "true");
+ params.put("('(aaa)(('\\u0023context[\\'xwork.MethodAccessor.denyMethodExecution\\']\\u003d\\u0023foo')(\\u0023foo\\u003dnew java.lang.Boolean(\"false\")))", "");
+ params.put("(asdf)(('\\u0023rt.exit(1)')(\\u0023rt\\u003d@java.lang.Runtime@getRuntime()))", "1");
+
+ HashMap<String, Object> extraContext = new HashMap<>();
+ extraContext.put(ActionContext.PARAMETERS, params);
+
+ ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, null, extraContext);
+ ValueStack stack = proxy.getInvocation().getStack();
+
+ // when
+ proxy.execute();
+ proxy.getAction();
+
+ //then
+ assertEquals("This is blah", ((SimpleAction) proxy.getAction()).getBlah());
+ boolean allowMethodAccess = ((SecurityMemberAccess) ((OgnlContext) stack.getContext()).getMemberAccess()).getAllowStaticMethodAccess();
+ assertFalse(allowMethodAccess);
+ }
+
+ public void testParameters() throws Exception {
+ Map<String, Object> params = new HashMap<>();
+ params.put("blah", "This is blah");
+
+ HashMap<String, Object> extraContext = new HashMap<>();
+ extraContext.put(ActionContext.PARAMETERS, params);
+
+ ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, null, extraContext);
+ proxy.execute();
+ assertEquals("This is blah", ((SimpleAction) proxy.getAction()).getBlah());
+ }
+
+ public void testParametersWithSpacesInTheName() throws Exception {
+ Map<String, Object> params = new HashMap<>();
+ params.put("theProtectedMap['p0 p1']", "test1");
+ params.put("theProtectedMap['p0p1 ']", "test2");
+ params.put("theProtectedMap[' p0p1 ']", "test3");
+ params.put("theProtectedMap[' p0 p1 ']", "test4");
+
+ HashMap<String, Object> extraContext = new HashMap<>();
+ extraContext.put(ActionContext.PARAMETERS, params);
+
+ ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, null, extraContext);
+ proxy.execute();
+ Map<String, String> existingMap = ((SimpleAction) proxy.getAction()).getTheProtectedMap();
+ assertEquals(0, existingMap.size());
+ }
+
+ public void testParametersWithChineseInTheName() throws Exception {
+ Map<String, Object> params = new HashMap<>();
+ params.put("theProtectedMap['名字']", "test1");
+
+ HashMap<String, Object> extraContext = new HashMap<>();
+ extraContext.put(ActionContext.PARAMETERS, params);
+
+ ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, null, extraContext);
+ proxy.execute();
+ Map<String, String> existingMap = ((SimpleAction) proxy.getAction()).getTheProtectedMap();
+ assertEquals(1, existingMap.size());
+ }
+
+ public void testLargeParameterNameWithDefaultLimit() throws Exception {
+ ParametersInterceptor parametersInterceptor = createParametersInterceptor();
+ doTestParameterNameLengthRestriction(parametersInterceptor, ParametersInterceptor.PARAM_NAME_MAX_LENGTH);
+ }
+
+ public void testLargeParameterNameWithCustomLimit() throws Exception {
+ ParametersInterceptor parametersInterceptor = createParametersInterceptor();
+ int limit = 20;
+ parametersInterceptor.setParamNameMaxLength(limit);
+ doTestParameterNameLengthRestriction(parametersInterceptor, limit);
+ }
+
+ private void doTestParameterNameLengthRestriction(ParametersInterceptor parametersInterceptor,
+ int paramNameMaxLength) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < paramNameMaxLength + 1; i++) {
+ sb.append("x");
+ }
+
+ Map<String, Object> actual = new LinkedHashMap<>();
+ parametersInterceptor.setValueStackFactory(createValueStackFactory(actual));
+ ValueStack stack = createStubValueStack(actual);
+
+ Map<String, Object> parameters = new HashMap<>();
+ parameters.put(sb.toString(), "");
+ parameters.put("huuhaa", "");
+
+ Action action = new SimpleAction();
+ parametersInterceptor.setParameters(action, stack, parameters);
+ assertEquals(1, actual.size());
+ }
+
+ public void testExcludedTrickyParameters() throws Exception {
+ Map<String, Object> params = new HashMap<String, Object>() {
+ {
+ put("blah", "This is blah");
+ put("name", "try_1");
+ put("(name)", "try_2");
+ put("['name']", "try_3");
+ put("['na' + 'me']", "try_4");
+ put("{name}[0]", "try_5");
+ put("(new string{'name'})[0]", "try_6");
+ put("#{key: 'name'}.key", "try_7");
+
+ }
+ };
+
+ HashMap<String, Object> extraContext = new HashMap<>();
+ extraContext.put(ActionContext.PARAMETERS, params);
+
+ ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, null, extraContext);
+
+ ActionConfig config = configuration.getRuntimeConfiguration().getActionConfig("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME);
+ ParametersInterceptor pi = (ParametersInterceptor) config.getInterceptors().get(0).getInterceptor();
+ pi.setExcludeParams("name");
+
+ proxy.execute();
+
+ SimpleAction action = (SimpleAction) proxy.getAction();
+ assertNull(action.getName());
+ assertEquals("This is blah", (action).getBlah());
+ }
+
+ public void testAcceptedTrickyParameters() throws Exception {
+ Map<String, Object> params = new HashMap<String, Object>() {
+ {
+ put("blah", "This is blah");
+ put("baz", "123");
+ put("name", "try_1");
+ put("(name)", "try_2");
+ put("['name']", "try_3");
+ put("['na' + 'me']", "try_4");
+ put("{name}[0]", "try_5");
+ put("(new string{'name'})[0]", "try_6");
+ put("#{key: 'name'}.key", "try_7");
+ }
+ };
+
+ HashMap<String, Object> extraContext = new HashMap<>();
+ extraContext.put(ActionContext.PARAMETERS, params);
+
+ ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, null, extraContext);
+
+ ActionConfig config = configuration.getRuntimeConfiguration().getActionConfig("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME);
+ ParametersInterceptor pi = (ParametersInterceptor) config.getInterceptors().get(0).getInterceptor();
+ pi.setAcceptParamNames("blah, baz");
+
+ proxy.execute();
+
+ SimpleAction action = (SimpleAction) proxy.getAction();
+ assertNull("try_1", action.getName());
+ assertEquals("This is blah", (action).getBlah());
+ assertEquals(123, action.getBaz());
+ }
+
+
+ public void testParametersNotAccessPrivateVariables() throws Exception {
+ Map<String, Object> params = new HashMap<>();
+ params.put("protectedMap.foo", "This is blah");
+ params.put("theProtectedMap.boo", "This is blah");
+
+ HashMap<String, Object> extraContext = new HashMap<>();
+ extraContext.put(ActionContext.PARAMETERS, params);
+
+ ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, null, extraContext);
+ proxy.execute();
+ SimpleAction action = (SimpleAction) proxy.getAction();
+ assertEquals(1, action.getTheProtectedMap().size());
+ assertNotNull(action.getTheProtectedMap().get("boo"));
+ assertNull(action.getTheProtectedMap().get("foo"));
+ }
+
+ public void testParametersNotAccessProtectedMethods() throws Exception {
+ Map<String, Object> params = new HashMap<>();
+ params.put("theSemiProtectedMap.foo", "This is blah");
+ params.put("theProtectedMap.boo", "This is blah");
+
+ HashMap<String, Object> extraContext = new HashMap<>();
+ extraContext.put(ActionContext.PARAMETERS, params);
+
+ ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, null, extraContext);
+ proxy.execute();
+ SimpleAction action = (SimpleAction) proxy.getAction();
+ assertEquals(1, action.getTheProtectedMap().size());
+ assertNotNull(action.getTheProtectedMap().get("boo"));
+ assertNull(action.getTheProtectedMap().get("foo"));
+ }
+
+ /**
+ * This test demonstrates a vulnerability which allows to execute arbitrary code.
+ * For further details and explanations see https://cwiki.apache.org/confluence/display/WW/S2-009
+ *
+ * @throws Exception
+ */
+ public void testEvalExpressionAsParameterName() throws Exception {
+ Map<String, Object> params = new HashMap<>();
+ params.put("blah", "(#context[\"xwork.MethodAccessor.denyMethodExecution\"]= new " +
+ "java.lang.Boolean(false), #_memberAccess[\"allowStaticMethodAccess\"]= new java.lang.Boolean(true), " +
+ "@java.lang.Runtime@getRuntime().exec('mkdir /tmp/PWNAGE'))(meh)");
+ params.put("top['blah'](0)", "true");
+
+ HashMap<String, Object> extraContext = new HashMap<>();
+ extraContext.put(ActionContext.PARAMETERS, params);
+
+ ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, null, extraContext);
+ proxy.execute();
+ @SuppressWarnings("unused")
+ SimpleAction action = (SimpleAction) proxy.getAction();
+ File pwn = new File("/tmp/PWNAGE");
+ boolean dirExists = pwn.exists();
+ @SuppressWarnings("unused")
+ boolean deleted = pwn.delete();
+ Assert.assertFalse("Remote exploit: The PWN folder has been created", dirExists);
+ }
+
+ public void testParametersOverwriteField() throws Exception {
+ Map<String, Object> params = new LinkedHashMap<>();
+ params.put("existingMap.boo", "This is blah");
+
+ HashMap<String, Object> extraContext = new HashMap<>();
+ extraContext.put(ActionContext.PARAMETERS, params);
+
+ ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, null, extraContext);
+ proxy.execute();
+ SimpleAction action = (SimpleAction) proxy.getAction();
+ assertEquals(1, action.getTheExistingMap().size());
+ assertNotNull(action.getTheExistingMap().get("boo"));
+ assertNull(action.getTheExistingMap().get("existingKey"));
+ }
+
+ public void testNonexistentParametersGetLoggedInDevMode() throws Exception {
+ XmlConfigurationProvider provider = new XmlConfigurationProvider("xwork-test-beans.xml");
+ container.inject(provider);
+ loadConfigurationProviders(provider,
+ new MockConfigurationProvider(Collections.singletonMap("devMode", "true")));
+ Map<String, Object> params = new HashMap<>();
+ params.put("not_a_property", "There is no action property named like this");
+
+ HashMap<String, Object> extraContext = new HashMap<>();
+ extraContext.put(ActionContext.PARAMETERS, params);
+
+ ActionConfig config = configuration.getRuntimeConfiguration().getActionConfig("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME);
+ container.inject(config.getInterceptors().get(0).getInterceptor());
+ ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, null, extraContext);
+ proxy.execute();
+ final String actionMessage = "" + ((SimpleAction) proxy.getAction()).getActionMessages().toArray()[0];
+ assertTrue(actionMessage.contains("Error setting expression 'not_a_property' with value 'There is no action property named like this'"));
+ }
+
+ public void testNonexistentParametersAreIgnoredInProductionMode() throws Exception {
+ XmlConfigurationProvider provider = new XmlConfigurationProvider("xwork-test-beans.xml");
+ container.inject(provider);
+ loadConfigurationProviders(provider,
+ new MockConfigurationProvider(Collections.singletonMap("devMode", "false")));
+ Map<String, Object> params = new HashMap<>();
+ params.put("not_a_property", "There is no action property named like this");
+
+ HashMap<String, Object> extraContext = new HashMap<>();
+ extraContext.put(ActionContext.PARAMETERS, params);
+
+ ActionConfig config = configuration.getRuntimeConfiguration().getActionConfig("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME);
+ container.inject(config.getInterceptors().get(0).getInterceptor());
+ ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, null, extraContext);
+ proxy.execute();
+ assertTrue(((SimpleAction) proxy.getAction()).getActionMessages().isEmpty());
+ }
+
+ public void testNoParametersAction() throws Exception {
+ ParametersInterceptor interceptor = new ParametersInterceptor();
+ interceptor.init();
+
+ MockActionInvocation mai = new MockActionInvocation();
+ Action action = new NoParametersAction();
+ mai.setAction(action);
+
+ interceptor.doIntercept(mai);
+ interceptor.destroy();
+ }
+
+ public void testNoOrdered() throws Exception {
+ ParametersInterceptor pi = createParametersInterceptor();
+ final Map<String, Object> actual = new LinkedHashMap<>();
+ pi.setValueStackFactory(createValueStackFactory(actual));
+ ValueStack stack = createStubValueStack(actual);
+
+ Map<String, Object> parameters = new HashMap<>();
+ parameters.put("user.address.city", "London");
+ parameters.put("user.name", "Superman");
+
+ Action action = new SimpleAction();
+ pi.setParameters(action, stack, parameters);
+
+ assertEquals("ordered should be false by default", false, pi.isOrdered());
+ assertEquals(2, actual.size());
+ assertEquals("London", actual.get("user.address.city"));
+ assertEquals("Superman", actual.get("user.name"));
+
+ // is not ordered
+ List<Object> values = new ArrayList<Object>(actual.values());
+ assertEquals("London", values.get(0));
+ assertEquals("Superman", values.get(1));
+ }
+
+ public void testOrdered() throws Exception {
+ ParametersInterceptor pi = new ParametersInterceptor();
+ pi.setOrdered(true);
+ container.inject(pi);
+ final Map<String, Object> actual = new LinkedHashMap<>();
+ pi.setValueStackFactory(createValueStackFactory(actual));
+ ValueStack stack = createStubValueStack(actual);
+
+ Map<String, Object> parameters = new HashMap<>();
+ parameters.put("user.address.city", "London");
+ parameters.put("user.address['postal']", "QJR387");
+ parameters.put("user.name", "Superman");
+
+ Action action = new SimpleAction();
+ pi.setParameters(action, stack, parameters);
+
+ assertEquals(true, pi.isOrdered());
+ assertEquals(3, actual.size());
+ assertEquals("London", actual.get("user.address.city"));
+ assertEquals("QJR387", actual.get("user.address['postal']"));
+ assertEquals("Superman", actual.get("user.name"));
+
+ // should be ordered so user.name should be first
+ List<Object> values = new ArrayList<Object>(actual.values());
+ assertEquals("Superman", values.get(0));
+ assertEquals("London", values.get(1));
+ assertEquals("QJR387", values.get(2));
+ }
+
+ public void testSetOrdered() throws Exception {
+ ParametersInterceptor pi = createParametersInterceptor();
+ assertEquals("ordered should be false by default", false, pi.isOrdered());
+ pi.setOrdered(true);
+ assertEquals(true, pi.isOrdered());
+ }
+
+ public void testExcludedParametersAreIgnored() throws Exception {
+ ParametersInterceptor pi = createParametersInterceptor();
+ pi.setExcludeParams("dojo\\..*");
+ final Map<String, Object> actual = injectValueStackFactory(pi);
+ ValueStack stack = injectValueStack(actual);
+
+ final Map<String, Object> expected = new HashMap<String, Object>() {
+ {
+ put("fooKey", "fooValue");
+ }
+ };
+
+ Map<String, Object> parameters = new HashMap<String, Object>() {
+ {
+ put("dojo.test", "dojoValue");
+ put("fooKey", "fooValue");
+ }
+ };
+ pi.setParameters(new NoParametersAction(), stack, parameters);
+ assertEquals(expected, actual);
+ }
+
+ public void testInternalParametersAreIgnored() throws Exception {
+ // given
+ ParametersInterceptor interceptor = createParametersInterceptor();
+ final Map<String, Object> actual = injectValueStackFactory(interceptor);
+ ValueStack stack = injectValueStack(actual);
+
+
+ final Map<String, Object> expected = new HashMap<String, Object>() {
+ {
+ put("ordinary.bean", "value");
+ }
+ };
+
+ Map<String, Object> parameters = new HashMap<String, Object>() {
+ {
+ put("ordinary.bean", "value");
+ put("#some.internal.object", "true");
+ put("(bla)#some.internal.object", "true");
+ put("#some.internal.object(bla)#some.internal.object", "true");
+ put("#_some.internal.object", "true");
+ put("\u0023_some.internal.object", "true");
+ put("\u0023_some.internal.object,[dfd],bla(\u0023_some.internal.object)", "true");
+ put("\\u0023_some.internal.object", "true");
+ }
+ };
+
+ // when
+ interceptor.setParameters(new NoParametersAction(), stack, parameters);
+
+ // then
+ assertEquals(expected, actual);
+ }
+
+ private ValueStack injectValueStack(Map<String, Object> actual) {
+ ValueStack stack = createStubValueStack(actual);
+ container.inject(stack);
+ return stack;
+ }
+
+ private Map<String, Object> injectValueStackFactory(ParametersInterceptor interceptor) {
+ final Map<String, Object> actual = new HashMap<>();
+ interceptor.setValueStackFactory(createValueStackFactory(actual));
+ return actual;
+ }
+
+ private ParametersInterceptor createParametersInterceptor() {
+ ParametersInterceptor pi = new ParametersInterceptor();
+ container.inject(pi);
+ return pi;
+ }
+
+ private ValueStackFactory createValueStackFactory(final Map<String, Object> context) {
+ OgnlValueStackFactory factory = new OgnlValueStackFactory() {
+ @Override
+ public ValueStack createValueStack(ValueStack stack) {
+ return createStubValueStack(context);
+ }
+ };
+ container.inject(factory);
+ return factory;
+ }
+
+ private ValueStack createStubValueStack(final Map<String, Object> actual) {
+ ValueStack stack = new OgnlValueStack(
+ container.getInstance(XWorkConverter.class),
+ (CompoundRootAccessor) container.getInstance(PropertyAccessor.class, CompoundRoot.class.getName()),
+ container.getInstance(TextProvider.class, "system"), true) {
+ @Override
+ public void setValue(String expr, Object value) {
+ actual.put(expr, value);
+ }
+
+ @Override
+ public void setParameter(String expr, Object value) {
+ actual.put(expr, value);
+ }
+ };
+ container.inject(stack);
+ return stack;
+ }
+
+ /*
+ public void testIndexedParameters() throws Exception {
+ Map params = new HashMap();
+ params.put("indexedProp[33]", "This is blah");
+
+ HashMap extraContext = new HashMap();
+ extraContext.put(ActionContext.PARAMETERS, params);
+
+ ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, extraContext);
+ proxy.execute();
+ assertEquals("This is blah", ((SimpleAction) proxy.getAction()).getIndexedProp(33));
+ }
+ */
+
+
+ private class NoParametersAction implements Action, NoParameters {
+
+ public String execute() throws Exception {
+ return SUCCESS;
+ }
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ XmlConfigurationProvider provider = new XmlConfigurationProvider("xwork-test-beans.xml");
+ container.inject(provider);
+ loadConfigurationProviders(provider, new MockConfigurationProvider());
+
+ ActionConfig config = configuration.getRuntimeConfiguration().getActionConfig("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME);
+ container.inject(config.getInterceptors().get(0).getInterceptor());
+ }
+
+}
+
+class ValidateAction implements ValidationAware {
+
+ private List<String> messages = new LinkedList<>();
+ private String name;
+
+ public void setActionErrors(Collection<String> errorMessages) {
+ }
+
+ public Collection<String> getActionErrors() {
+ return null;
+ }
+
+ public void setActionMessages(Collection<String> messages) {
+ }
+
+ public Collection<String> getActionMessages() {
+ return messages;
+ }
+
+ public void setFieldErrors(Map<String, List<String>> errorMap) {
+ }
+
+ public Map<String, List<String>> getFieldErrors() {
+ return null;
+ }
+
+ public void addActionError(String anErrorMessage) {
+ }
+
+ public void addActionMessage(String aMessage) {
+ messages.add(aMessage);
+ }
+
+ public void addFieldError(String fieldName, String errorMessage) {
+ }
+
+ public boolean hasActionErrors() {
+ return false;
+ }
+
+ public boolean hasActionMessages() {
+ return messages.size() > 0;
+ }
+
+ public boolean hasErrors() {
+ return false;
+ }
+
+ public boolean hasFieldErrors() {
+ return false;
+ }
+
+ public String getActionMessage(int index) {
+ return messages.get(index);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/struts/blob/dc270c2e/core/src/test/java/com/opensymphony/xwork2/security/DefaultExcludedPatternsCheckerTest.java
----------------------------------------------------------------------
diff --cc core/src/test/java/com/opensymphony/xwork2/security/DefaultExcludedPatternsCheckerTest.java
index 367e199,0000000..faf807e
mode 100644,000000..100644
--- a/core/src/test/java/com/opensymphony/xwork2/security/DefaultExcludedPatternsCheckerTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/security/DefaultExcludedPatternsCheckerTest.java
@@@ -1,106 -1,0 +1,141 @@@
+package com.opensymphony.xwork2.security;
+
+import com.opensymphony.xwork2.XWorkTestCase;
+
+import java.util.ArrayList;
++import java.util.Arrays;
+import java.util.List;
+
+public class DefaultExcludedPatternsCheckerTest extends XWorkTestCase {
+
+ public void testHardcodedPatterns() throws Exception {
+ // given
+ List<String> params = new ArrayList<String>() {
+ {
+ add("%{#application['test']}");
+ add("%{#application.test}");
+ add("%{#Application['test']}");
+ add("%{#Application.test}");
+ add("%{#session['test']}");
+ add("%{#session.test}");
+ add("%{#Session['test']}");
+ add("%{#Session.test}");
+ add("%{#struts['test']}");
+ add("%{#struts.test}");
+ add("%{#Struts['test']}");
+ add("%{#Struts.test}");
+ add("%{#request['test']}");
+ add("%{#request.test}");
+ add("%{#Request['test']}");
+ add("%{#Request.test}");
+ add("%{#servletRequest['test']}");
+ add("%{#servletRequest.test}");
+ add("%{#ServletRequest['test']}");
+ add("%{#ServletRequest.test}");
+ add("%{#servletResponse['test']}");
+ add("%{#servletResponse.test}");
+ add("%{#ServletResponse['test']}");
+ add("%{#ServletResponse.test}");
++ add("%{#servletContext['test']}");
++ add("%{#servletContext.test}");
++ add("%{#ServletContext['test']}");
++ add("%{#ServletContext.test}");
+ add("%{#parameters['test']}");
+ add("%{#parameters.test}");
+ add("%{#Parameters['test']}");
+ add("%{#Parameters.test}");
+ add("#context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse')");
+ add("%{#context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse')}");
+ add("#_memberAccess[\"allowStaticMethodAccess\"]= new java.lang.Boolean(true)");
+ add("%{#_memberAccess[\"allowStaticMethodAccess\"]= new java.lang.Boolean(true)}");
+ add("form.class.classLoader");
+ add("form[\"class\"][\"classLoader\"]");
+ add("form['class']['classLoader']");
+ add("class['classLoader']");
+ add("class[\"classLoader\"]");
+ add("class.classLoader.resources.dirContext.docBase=tttt");
+ add("Class.classLoader.resources.dirContext.docBase=tttt");
+ }
+ };
+
+ DefaultExcludedPatternsChecker checker = new DefaultExcludedPatternsChecker();
+ checker.setAdditionalExcludePatterns(".*(^|\\.|\\[|'|\")class(\\.|\\[|'|\").*");
+
+ for (String param : params) {
+ // when
+ ExcludedPatternsChecker.IsExcluded actual = checker.isExcluded(param);
+
+ // then
+ assertTrue("Access to " + param + " is possible!", actual.isExcluded());
+ }
+ }
+
++ public void testDefaultExcludePatterns() throws Exception {
++ // given
++ List<String> prefixes = Arrays.asList("#[0].%s", "[0].%s", "top.%s", "%{[0].%s}", "%{#[0].%s}", "%{top.%s}", "%{#top.%s}", "%{#%s}", "%{%s}", "#%s");
++ List<String> inners = Arrays.asList("servletRequest", "servletResponse", "servletContext", "application", "session", "struts", "request", "response", "dojo", "parameters");
++ List<String> suffixes = Arrays.asList("['test']", "[\"test\"]", ".test");
++
++ DefaultExcludedPatternsChecker checker = new DefaultExcludedPatternsChecker();
++ checker.setAdditionalExcludePatterns(".*(^|\\.|\\[|'|\")class(\\.|\\[|'|\").*");
++
++ List<String> params = new ArrayList<String>();
++ for (String prefix : prefixes) {
++ for (String inner : inners) {
++ String innerUp = inner.substring(0, 1).toUpperCase() + inner.substring(1);
++ for (String suffix : suffixes) {
++ params.add(prefix.replace("%s", inner + suffix));
++ params.add(prefix.replace("%s", innerUp + suffix));
++ }
++ }
++ }
++
++ for (String param : params) {
++ System.out.println(param);
++ // when
++ ExcludedPatternsChecker.IsExcluded actual = checker.isExcluded(param);
++
++ // then
++ assertTrue("Access to " + param + " is possible!", actual.isExcluded());
++ }
++ }
++
+ public void testParamWithClassInName() throws Exception {
+ // given
+ List<String> properParams = new ArrayList<>();
+ properParams.add("eventClass");
+ properParams.add("form.eventClass");
+ properParams.add("form[\"eventClass\"]");
+ properParams.add("form['eventClass']");
+ properParams.add("class.super@demo.com");
+ properParams.add("super.class@demo.com");
+
+ ExcludedPatternsChecker checker = new DefaultExcludedPatternsChecker();
+
+ for (String properParam : properParams) {
+ // when
+ ExcludedPatternsChecker.IsExcluded actual = checker.isExcluded(properParam);
+
+ // then
+ assertFalse("Param '" + properParam + "' is excluded!", actual.isExcluded());
+ }
+ }
+
+ public void testStrutsTokenIsExcluded() throws Exception {
+ // given
+ List<String> tokens = new ArrayList<>();
+ tokens.add("struts.token.name");
+ tokens.add("struts.token");
+
+ ExcludedPatternsChecker checker = new DefaultExcludedPatternsChecker();
+
+ for (String token : tokens) {
+ // when
+ ExcludedPatternsChecker.IsExcluded actual = checker.isExcluded(token);
+
+ // then
+ assertTrue("Param '" + token + "' is not excluded!", actual.isExcluded());
+ }
+ }
+
+}