Repository: struts Updated Branches: refs/heads/support-2-3 030ffa335 -> 23e018132
WW-4669 Returns default action/method instead of throwing exception Project: http://git-wip-us.apache.org/repos/asf/struts/repo Commit: http://git-wip-us.apache.org/repos/asf/struts/commit/23e01813 Tree: http://git-wip-us.apache.org/repos/asf/struts/tree/23e01813 Diff: http://git-wip-us.apache.org/repos/asf/struts/diff/23e01813 Branch: refs/heads/support-2-3 Commit: 23e0181328bd095f50f80d4a1bf47c1620f992a0 Parents: 030ffa3 Author: Lukasz Lenart <lukaszlen...@apache.org> Authored: Fri Jul 29 10:09:24 2016 +0200 Committer: Lukasz Lenart <lukaszlen...@apache.org> Committed: Tue Aug 30 09:20:41 2016 +0200 ---------------------------------------------------------------------- .../org/apache/struts2/StrutsConstants.java | 7 ++++ .../dispatcher/mapper/DefaultActionMapper.java | 44 ++++++++++++++++++-- .../mapper/DefaultActionMapperTest.java | 44 ++++++++------------ .../apache/struts2/rest/RestActionMapper.java | 5 ++- 4 files changed, 68 insertions(+), 32 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/struts/blob/23e01813/core/src/main/java/org/apache/struts2/StrutsConstants.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/struts2/StrutsConstants.java b/core/src/main/java/org/apache/struts2/StrutsConstants.java index 619ed66..09c7e05 100644 --- a/core/src/main/java/org/apache/struts2/StrutsConstants.java +++ b/core/src/main/java/org/apache/struts2/StrutsConstants.java @@ -272,6 +272,13 @@ public final class StrutsConstants { /** actions names' whitelist **/ public static final String STRUTS_ALLOWED_ACTION_NAMES = "struts.allowed.action.names"; + /** default action name to use when action didn't match the whitelist **/ + public static final String STRUTS_DEFAULT_ACTION_NAME = "struts.default.action.name"; + + /** methods names' whitelist **/ + public static final String STRUTS_ALLOWED_METHOD_NAMES = "struts.allowed.method.names"; + /** default method name to use when method didn't match the whitelist **/ + public static final String STRUTS_DEFAULT_METHOD_NAME = "struts.default.method.name"; /** enables action: prefix **/ public static final String STRUTS_MAPPER_ACTION_PREFIX_ENABLED = "struts.mapper.action.prefix.enabled"; http://git-wip-us.apache.org/repos/asf/struts/blob/23e01813/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java b/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java index d696d13..8850311 100644 --- a/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java +++ b/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java @@ -121,6 +121,11 @@ public class DefaultActionMapper implements ActionMapper { protected boolean alwaysSelectFullNamespace = false; protected PrefixTrie prefixTrie = null; protected Pattern allowedActionNames = Pattern.compile("[a-zA-Z0-9._!/\\-]*"); + protected String defaultActionName = "index"; + + protected Pattern allowedMethodNames = Pattern.compile("[a-zA-Z_]*[0-9]*"); + protected String defaultMethodName = "execute"; + private boolean allowActionPrefix = false; private boolean allowActionCrossNamespaceAccess = false; @@ -137,7 +142,7 @@ public class DefaultActionMapper implements ActionMapper { put(METHOD_PREFIX, new ParameterAction() { public void execute(String key, ActionMapping mapping) { if (allowDynamicMethodCalls) { - mapping.setMethod(cleanupActionName(key.substring(METHOD_PREFIX.length()))); + mapping.setMethod(cleanupMethodName(key.substring(METHOD_PREFIX.length()))); } } }); @@ -149,7 +154,7 @@ public class DefaultActionMapper implements ActionMapper { if (allowDynamicMethodCalls) { int bang = name.indexOf('!'); if (bang != -1) { - String method = cleanupActionName(name.substring(bang + 1)); + String method = cleanupMethodName(name.substring(bang + 1)); mapping.setMethod(method); name = name.substring(0, bang); } @@ -205,6 +210,21 @@ public class DefaultActionMapper implements ActionMapper { this.allowedActionNames = Pattern.compile(allowedActionNames); } + @Inject(value = StrutsConstants.STRUTS_DEFAULT_ACTION_NAME, required = false) + public void setDefaultActionName(String defaultActionName) { + this.defaultActionName = defaultActionName; + } + + @Inject(value = StrutsConstants.STRUTS_ALLOWED_METHOD_NAMES, required = false) + public void setAllowedMethodNames(String allowedMethodNames) { + this.allowedMethodNames = Pattern.compile(allowedMethodNames); + } + + @Inject(value = StrutsConstants.STRUTS_DEFAULT_METHOD_NAME, required = false) + public void setDefaultMethodName(String defaultMethodName) { + this.defaultMethodName = defaultMethodName; + } + @Inject(value = StrutsConstants.STRUTS_MAPPER_ACTION_PREFIX_ENABLED) public void setAllowActionPrefix(String allowActionPrefix) { this.allowActionPrefix = "true".equalsIgnoreCase(allowActionPrefix); @@ -376,7 +396,7 @@ public class DefaultActionMapper implements ActionMapper { } /** - * Cleans up action name from suspicious characters + * Checks action name against allowed pattern if not matched returns default action name * * @param rawActionName action name extracted from URI * @return safe action name @@ -385,7 +405,23 @@ public class DefaultActionMapper implements ActionMapper { if (allowedActionNames.matcher(rawActionName).matches()) { return rawActionName; } else { - throw new StrutsException("Action [" + rawActionName + "] does not match allowed action names pattern [" + allowedActionNames + "]!"); + LOG.warn("{} did not match allowed action names {} - default action {} will be used!", rawActionName, allowedActionNames, defaultActionName); + return defaultActionName; + } + } + + /** + * Checks method name (when DMI is enabled) against allowed pattern if not matched returns default action name + * + * @param rawMethodName method name extracted from URI + * @return safe method name + */ + protected String cleanupMethodName(final String rawMethodName) { + if (allowedMethodNames.matcher(rawMethodName).matches()) { + return rawMethodName; + } else { + LOG.warn("{} did not match allowed method names {} - default method {} will be used!", rawMethodName, allowedMethodNames, defaultMethodName); + return defaultMethodName; } } http://git-wip-us.apache.org/repos/asf/struts/blob/23e01813/core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java b/core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java index 0f1baef..729e63e 100644 --- a/core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java +++ b/core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java @@ -845,37 +845,14 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase { String actionName = "action"; assertEquals(actionName, mapper.cleanupActionName(actionName)); - Throwable expected = null; - actionName = "${action}"; - try { - mapper.cleanupActionName(actionName); - fail(); - } catch (Throwable t) { - expected = t; - } - assertTrue(expected instanceof StrutsException); - assertEquals("Action [${action}] does not match allowed action names pattern [" + mapper.allowedActionNames.pattern() + "]!", expected.getMessage()); + assertEquals(mapper.defaultActionName, mapper.cleanupActionName(actionName)); actionName = "${${%{action}}}"; - try { - mapper.cleanupActionName(actionName); - fail(); - } catch (Throwable t) { - expected = t; - } - assertTrue(expected instanceof StrutsException); - assertEquals("Action [${${%{action}}}] does not match allowed action names pattern [" + mapper.allowedActionNames.pattern() + "]!", expected.getMessage()); + assertEquals(mapper.defaultActionName, mapper.cleanupActionName(actionName)); actionName = "${#foo='action',#foo}"; - try { - mapper.cleanupActionName(actionName); - fail(); - } catch (Throwable t) { - expected = t; - } - assertTrue(expected instanceof StrutsException); - assertEquals("Action [${#foo='action',#foo}] does not match allowed action names pattern [" + mapper.allowedActionNames.pattern() + "]!", expected.getMessage()); + assertEquals(mapper.defaultActionName, mapper.cleanupActionName(actionName)); actionName = "test-action"; assertEquals("test-action", mapper.cleanupActionName(actionName)); @@ -887,4 +864,19 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase { assertEquals("test!bar.action", mapper.cleanupActionName(actionName)); } + public void testAllowedMethodNames() throws Exception { + DefaultActionMapper mapper = new DefaultActionMapper(); + + assertEquals("", mapper.cleanupMethodName("")); + assertEquals("test", mapper.cleanupMethodName("test")); + assertEquals("test_method", mapper.cleanupMethodName("test_method")); + assertEquals("_test", mapper.cleanupMethodName("_test")); + assertEquals("test1", mapper.cleanupMethodName("test1")); + + assertEquals(mapper.defaultMethodName, mapper.cleanupMethodName("2test")); + assertEquals(mapper.defaultMethodName, mapper.cleanupMethodName("%{exp}")); + assertEquals(mapper.defaultMethodName, mapper.cleanupMethodName("${%{foo}}")); + assertEquals(mapper.defaultMethodName, mapper.cleanupMethodName("${#foo='method',#foo}")); + } + } http://git-wip-us.apache.org/repos/asf/struts/blob/23e01813/plugins/rest/src/main/java/org/apache/struts2/rest/RestActionMapper.java ---------------------------------------------------------------------- diff --git a/plugins/rest/src/main/java/org/apache/struts2/rest/RestActionMapper.java b/plugins/rest/src/main/java/org/apache/struts2/rest/RestActionMapper.java index 41029ea..e861344 100644 --- a/plugins/rest/src/main/java/org/apache/struts2/rest/RestActionMapper.java +++ b/plugins/rest/src/main/java/org/apache/struts2/rest/RestActionMapper.java @@ -112,6 +112,7 @@ public class RestActionMapper extends DefaultActionMapper { private boolean allowDynamicMethodCalls = false; public RestActionMapper() { + this.defaultMethodName = indexMethodName; } public String getIdParameterName() { @@ -290,7 +291,7 @@ public class RestActionMapper extends DefaultActionMapper { fullName = fullName.substring(0, lastSlashPos); } - mapping.setName(fullName); + mapping.setName(cleanupActionName(fullName)); } return mapping; } @@ -311,7 +312,7 @@ public class RestActionMapper extends DefaultActionMapper { mapping.setName(actionName); if (allowDynamicMethodCalls) { - mapping.setMethod(cleanupActionName(actionMethod)); + mapping.setMethod(cleanupMethodName(actionMethod)); } else { mapping.setMethod(null); }