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 2018/06/21 07:20:09 UTC

[struts] branch struts-2-5-x updated: Validates action, namespace and method in the same way

This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch struts-2-5-x
in repository https://gitbox.apache.org/repos/asf/struts.git


The following commit(s) were added to refs/heads/struts-2-5-x by this push:
     new 6e87474  Validates action, namespace and method in the same way
6e87474 is described below

commit 6e87474f9ad0549f07dd2c37d50a9ccd0977c6e5
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Thu Jun 21 09:19:46 2018 +0200

    Validates action, namespace and method in the same way
---
 .../java/org/apache/struts2/StrutsConstants.java   |   5 +
 .../dispatcher/mapper/DefaultActionMapper.java     |  35 +++-
 .../dispatcher/mapper/DefaultActionMapperTest.java | 197 ++++++++++++---------
 .../org/apache/struts2/rest/RestActionMapper.java  |   2 +-
 4 files changed, 150 insertions(+), 89 deletions(-)

diff --git a/core/src/main/java/org/apache/struts2/StrutsConstants.java b/core/src/main/java/org/apache/struts2/StrutsConstants.java
index d01e150..81a4f80 100644
--- a/core/src/main/java/org/apache/struts2/StrutsConstants.java
+++ b/core/src/main/java/org/apache/struts2/StrutsConstants.java
@@ -282,6 +282,11 @@ public final class StrutsConstants {
 
     public static final String STRUTS_EXPRESSION_PARSER = "struts.expression.parser";
 
+    /** namespaces names' whitelist **/
+    public static final String STRUTS_ALLOWED_NAMESPACE_NAMES = "struts.allowed.namespace.names";
+    /** default namespace name to use when namespace didn't match the whitelist **/
+    public static final String STRUTS_DEFAULT_NAMESPACE_NAME = "struts.default.namespace.name";
+
     /** 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 **/
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 224e36a..95bd5c1 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
@@ -31,7 +31,6 @@ import org.apache.logging.log4j.Logger;
 import org.apache.struts2.RequestUtils;
 import org.apache.struts2.ServletActionContext;
 import org.apache.struts2.StrutsConstants;
-import org.apache.struts2.StrutsException;
 import org.apache.struts2.util.PrefixTrie;
 
 import javax.servlet.http.HttpServletRequest;
@@ -117,6 +116,10 @@ public class DefaultActionMapper implements ActionMapper {
     protected boolean allowSlashesInActionNames = false;
     protected boolean alwaysSelectFullNamespace = false;
     protected PrefixTrie prefixTrie = null;
+
+    protected Pattern allowedNamespaceNames = Pattern.compile("[a-zA-Z0-9._/\\-]*");
+    protected String defaultNamespaceName = "/";
+
     protected Pattern allowedActionNames = Pattern.compile("[a-zA-Z0-9._!/\\-]*");
     protected String defaultActionName = "index";
 
@@ -202,6 +205,16 @@ public class DefaultActionMapper implements ActionMapper {
         this.alwaysSelectFullNamespace = BooleanUtils.toBoolean(alwaysSelectFullNamespace);
     }
 
+    @Inject(value = StrutsConstants.STRUTS_ALLOWED_NAMESPACE_NAMES, required = false)
+    public void setAllowedNamespaceNames(String allowedNamespaceNames) {
+        this.allowedNamespaceNames = Pattern.compile(allowedNamespaceNames);
+    }
+
+    @Inject(value = StrutsConstants.STRUTS_DEFAULT_NAMESPACE_NAME, required = false)
+    public void setDefaultNamespaceName(String defaultNamespaceName) {
+        this.defaultNamespaceName = defaultNamespaceName;
+    }
+
     @Inject(value = StrutsConstants.STRUTS_ALLOWED_ACTION_NAMES, required = false)
     public void setAllowedActionNames(String allowedActionNames) {
         this.allowedActionNames = Pattern.compile(allowedActionNames);
@@ -389,11 +402,29 @@ public class DefaultActionMapper implements ActionMapper {
             }
         }
 
-        mapping.setNamespace(namespace);
+        mapping.setNamespace(cleanupNamespaceName(namespace));
         mapping.setName(cleanupActionName(name));
     }
 
     /**
+     * Checks namespace name against allowed pattern if not matched returns default namespace
+     *
+     * @param rawNamespace name extracted from URI
+     * @return safe namespace name
+     */
+    protected String cleanupNamespaceName(final String rawNamespace) {
+        if (allowedNamespaceNames.matcher(rawNamespace).matches()) {
+            return rawNamespace;
+        } else {
+            LOG.warn(
+                "{} did not match allowed namespace names {} - default namespace {} will be used!",
+                rawNamespace, allowedActionNames, defaultActionName
+            );
+            return defaultNamespaceName;
+        }
+    }
+
+    /**
      * Checks action name against allowed pattern if not matched returns default action name
      *
      * @param rawActionName action name extracted from URI
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 3c012e8..479494b 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
@@ -27,12 +27,12 @@ import com.opensymphony.xwork2.config.entities.PackageConfig;
 import com.opensymphony.xwork2.config.impl.DefaultConfiguration;
 import com.opensymphony.xwork2.inject.Container;
 import org.apache.struts2.ServletActionContext;
-import org.apache.struts2.StrutsException;
 import org.apache.struts2.StrutsInternalTestCase;
 import org.apache.struts2.result.StrutsResultSupport;
 import org.apache.struts2.views.jsp.StrutsMockHttpServletRequest;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -65,7 +65,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         };
     }
 
-    public void testGetMapping() throws Exception {
+    public void testGetMapping() {
         req.setupGetRequestURI("/my/namespace/actionName.action");
         req.setupGetServletPath("/my/namespace/actionName.action");
         req.setupGetAttribute(null);
@@ -79,7 +79,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertNull(mapping.getMethod());
     }
 
-    public void testGetMappingWithMethod() throws Exception {
+    public void testGetMappingWithMethod() {
         req.setupGetParameterMap(new HashMap());
         req.setupGetRequestURI("/my/namespace/actionName!add.action");
         req.setupGetServletPath("/my/namespace/actionName!add.action");
@@ -95,7 +95,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("add", mapping.getMethod());
     }
 
-    public void testGetMappingWithSlashedName() throws Exception {
+    public void testGetMappingWithSlashedName() {
 
         req.setupGetRequestURI("/my/foo/actionName.action");
         req.setupGetServletPath("/my/foo/actionName.action");
@@ -111,7 +111,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertNull(mapping.getMethod());
     }
 
-    public void testGetMappingWithSlashedNameAtRootButNoSlashPackage() throws Exception {
+    public void testGetMappingWithSlashedNameAtRootButNoSlashPackage() {
 
         req.setupGetRequestURI("/foo/actionName.action");
         req.setupGetServletPath("/foo/actionName.action");
@@ -127,7 +127,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertNull(mapping.getMethod());
     }
 
-    public void testGetMappingWithSlashedNameAtRoot() throws Exception {
+    public void testGetMappingWithSlashedNameAtRoot() {
         config = new DefaultConfiguration();
         PackageConfig pkg = new PackageConfig.Builder("myns")
             .namespace("/my/namespace").build();
@@ -158,7 +158,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
 
 
 
-    public void testGetMappingWithNamespaceSlash() throws Exception {
+    public void testGetMappingWithNamespaceSlash() {
 
         req.setupGetRequestURI("/my-hh/abc.action");
         req.setupGetServletPath("/my-hh/abc.action");
@@ -181,7 +181,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("my-hh/abc", mapping.getName());
     }
 
-    public void testGetMappingWithUnknownNamespace() throws Exception {
+    public void testGetMappingWithUnknownNamespace() {
         req.setupGetRequestURI("/bo/foo/actionName.action");
         req.setupGetServletPath("/bo/foo/actionName.action");
         req.setupGetAttribute(null);
@@ -195,7 +195,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertNull(mapping.getMethod());
     }
 
-    public void testGetMappingWithUnknownNamespaceButFullNamespaceSelect() throws Exception {
+    public void testGetMappingWithUnknownNamespaceButFullNamespaceSelect() {
         req.setupGetRequestURI("/bo/foo/actionName.action");
         req.setupGetServletPath("/bo/foo/actionName.action");
         req.setupGetAttribute(null);
@@ -210,7 +210,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertNull(mapping.getMethod());
     }
 
-    public void testGetMappingWithActionName_methodAndName() throws Exception {
+    public void testGetMappingWithActionName_methodAndName() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         mapper.setAllowDynamicMethodCalls("true");
         ActionMapping mapping = mapper.getMappingFromActionName("actionName!add");
@@ -218,24 +218,24 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("add", mapping.getMethod());
     }
 
-    public void testGetMappingWithActionName_name() throws Exception {
+    public void testGetMappingWithActionName_name() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         ActionMapping mapping = mapper.getMappingFromActionName("actionName");
         assertEquals("actionName", mapping.getName());
-        assertEquals(null, mapping.getMethod());
+        assertNull(mapping.getMethod());
     }
 
-    public void testGetMappingWithActionName_noDynamicMethod() throws Exception {
+    public void testGetMappingWithActionName_noDynamicMethod() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         mapper.setAllowDynamicMethodCalls("false");
         ActionMapping mapping = mapper.getMappingFromActionName("actionName!add");
         assertEquals("actionName!add", mapping.getName());
-        assertEquals(null, mapping.getMethod());
+        assertNull(mapping.getMethod());
     }
 
-    public void testGetMappingWithActionName_noDynamicMethodColonPrefix() throws Exception {
+    public void testGetMappingWithActionName_noDynamicMethodColonPrefix() {
 
-        Map parameterMap = new HashMap();
+        Map<String, Object> parameterMap = new HashMap<>();
         parameterMap.put(DefaultActionMapper.METHOD_PREFIX + "someMethod", "");
 
         StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest();
@@ -247,16 +247,16 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         ActionMapping actionMapping = defaultActionMapper.getMapping(request, configManager);
 
         assertEquals("someServletPath", actionMapping.getName());
-        assertEquals(null, actionMapping.getMethod());
+        assertNull(actionMapping.getMethod());
     }
 
-    public void testGetMappingWithActionName_null() throws Exception {
+    public void testGetMappingWithActionName_null() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         ActionMapping mapping = mapper.getMappingFromActionName(null);
         assertNull(mapping);
     }
 
-    public void testGetUri() throws Exception {
+    public void testGetUri() {
         req.setupGetParameterMap(new HashMap());
         req.setupGetRequestURI("/my/namespace/actionName.action");
         req.setupGetServletPath("/my/namespace/actionName.action");
@@ -268,7 +268,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("/my/namespace/actionName.action", mapper.getUriFromActionMapping(mapping));
     }
 
-    public void testGetUriWithSemicolonPresent() throws Exception {
+    public void testGetUriWithSemicolonPresent() {
         req.setupGetParameterMap(new HashMap());
         req.setupGetRequestURI("/my/namespace/actionName.action;abc=123rty56");
         req.setupGetServletPath("/my/namespace/actionName.action;abc=123rty56");
@@ -280,7 +280,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("/my/namespace/actionName.action", mapper.getUriFromActionMapping(mapping));
     }
 
-    public void testGetUriWithMethod() throws Exception {
+    public void testGetUriWithMethod() {
         req.setupGetParameterMap(new HashMap());
         req.setupGetRequestURI("/my/namespace/actionName!add.action");
         req.setupGetServletPath("/my/namespace/actionName!add.action");
@@ -293,8 +293,8 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("/my/namespace/actionName!add.action", mapper.getUriFromActionMapping(mapping));
     }
 
-    public void testGetUriWithOriginalExtension() throws Exception {
-        ActionMapping mapping = new ActionMapping("actionName", "/ns", null, new HashMap());
+    public void testGetUriWithOriginalExtension() {
+        ActionMapping mapping = new ActionMapping("actionName", "/ns", null, new HashMap<String, Object>());
 
         ActionMapping orig = new ActionMapping();
         orig.setExtension("foo");
@@ -304,7 +304,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("/ns/actionName.foo", mapper.getUriFromActionMapping(mapping));
     }
 
-    public void testGetMappingWithNoExtension() throws Exception {
+    public void testGetMappingWithNoExtension() {
         req.setupGetParameterMap(new HashMap());
         req.setupGetRequestURI("/my/namespace/actionName");
         req.setupGetServletPath("/my/namespace/actionName");
@@ -320,7 +320,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertNull(mapping.getMethod());
     }
 
-    public void testGetMappingWithNoExtensionButUriHasExtension() throws Exception {
+    public void testGetMappingWithNoExtensionButUriHasExtension() {
         req.setupGetParameterMap(new HashMap());
         req.setupGetRequestURI("/my/namespace/actionName.html");
         req.setupGetServletPath("/my/namespace/actionName.html");
@@ -340,7 +340,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
     // === test name & namespace ===
     // =============================
 
-    public void testParseNameAndNamespace1() throws Exception {
+    public void testParseNameAndNamespace1() {
         ActionMapping actionMapping = new ActionMapping();
 
         DefaultActionMapper defaultActionMapper = new DefaultActionMapper();
@@ -350,7 +350,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals(actionMapping.getNamespace(), "");
     }
 
-    public void testParseNameAndNamespace2() throws Exception {
+    public void testParseNameAndNamespace2() {
         ActionMapping actionMapping = new ActionMapping();
 
         DefaultActionMapper defaultActionMapper = new DefaultActionMapper();
@@ -360,7 +360,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals(actionMapping.getNamespace(), "/");
     }
 
-    public void testParseNameAndNamespace3() throws Exception {
+    public void testParseNameAndNamespace3() {
         ActionMapping actionMapping = new ActionMapping();
 
         DefaultActionMapper defaultActionMapper = new DefaultActionMapper();
@@ -370,7 +370,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals(actionMapping.getNamespace(), "/my");
     }
 
-    public void testParseNameAndNamespace_NoSlashes() throws Exception {
+    public void testParseNameAndNamespace_NoSlashes() {
         ActionMapping actionMapping = new ActionMapping();
 
         DefaultActionMapper defaultActionMapper = new DefaultActionMapper();
@@ -381,7 +381,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals(actionMapping.getNamespace(), "");
     }
 
-    public void testParseNameAndNamespace_AllowSlashes() throws Exception {
+    public void testParseNameAndNamespace_AllowSlashes() {
         ActionMapping actionMapping = new ActionMapping();
 
         DefaultActionMapper defaultActionMapper = new DefaultActionMapper();
@@ -397,8 +397,8 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
     // === test special prefix ===
     // ===========================
 
-    public void testActionPrefixWhenDisabled() throws Exception {
-        Map parameterMap = new HashMap();
+    public void testActionPrefixWhenDisabled() {
+        Map<String, Object> parameterMap = new HashMap<>();
         parameterMap.put(DefaultActionMapper.ACTION_PREFIX + "myAction", "");
 
         StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest();
@@ -411,8 +411,8 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("someServletPath", actionMapping.getName());
     }
 
-    public void testActionPrefixWhenEnabled() throws Exception {
-        Map parameterMap = new HashMap();
+    public void testActionPrefixWhenEnabled() {
+        Map<String, Object> parameterMap = new HashMap<>();
         parameterMap.put(DefaultActionMapper.ACTION_PREFIX + "myAction", "");
 
         StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest();
@@ -426,8 +426,8 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("myAction", actionMapping.getName());
     }
 
-    public void testActionPrefixWhenSlashesAndCrossNamespaceDisabled() throws Exception {
-        Map parameterMap = new HashMap();
+    public void testActionPrefixWhenSlashesAndCrossNamespaceDisabled() {
+        Map<String, Object> parameterMap = new HashMap<>();
         parameterMap.put(DefaultActionMapper.ACTION_PREFIX + "my/Action", "");
 
         StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest();
@@ -442,8 +442,8 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("my/Action", actionMapping.getName());
     }
 
-    public void testActionPrefixWhenSlashesButSlashesDisabledAndCrossNamespaceDisabled() throws Exception {
-        Map parameterMap = new HashMap();
+    public void testActionPrefixWhenSlashesButSlashesDisabledAndCrossNamespaceDisabled() {
+        Map<String, Object> parameterMap = new HashMap<>();
         parameterMap.put(DefaultActionMapper.ACTION_PREFIX + "my/Action", "");
 
         StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest();
@@ -458,8 +458,8 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("Action", actionMapping.getName());
     }
 
-    public void testActionPrefixWhenSlashesButSlashesDisabledAndCrossNamespace() throws Exception {
-        Map parameterMap = new HashMap();
+    public void testActionPrefixWhenSlashesButSlashesDisabledAndCrossNamespace() {
+        Map<String, Object> parameterMap = new HashMap<>();
         parameterMap.put(DefaultActionMapper.ACTION_PREFIX + "my/Action", "");
 
         StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest();
@@ -475,8 +475,8 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("my/Action", actionMapping.getName());
     }
 
-    public void testActionPrefixWhenCrossNamespace() throws Exception {
-        Map parameterMap = new HashMap();
+    public void testActionPrefixWhenCrossNamespace() {
+        Map<String, Object> parameterMap = new HashMap<>();
         parameterMap.put(DefaultActionMapper.ACTION_PREFIX + "/my/Action", "");
 
         StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest();
@@ -491,8 +491,8 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("/my/Action", actionMapping.getName());
     }
 
-    public void testActionPrefix_fromImageButton() throws Exception {
-        Map parameterMap = new HashMap();
+    public void testActionPrefix_fromImageButton() {
+        Map<String, Object> parameterMap = new HashMap<>();
         parameterMap.put(DefaultActionMapper.ACTION_PREFIX + "myAction", "");
         parameterMap.put(DefaultActionMapper.ACTION_PREFIX + "myAction.x", "");
         parameterMap.put(DefaultActionMapper.ACTION_PREFIX + "myAction.y", "");
@@ -508,8 +508,8 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("myAction", actionMapping.getName());
     }
 
-    public void testActionPrefix_fromIEImageButton() throws Exception {
-        Map parameterMap = new HashMap();
+    public void testActionPrefix_fromIEImageButton() {
+        Map<String, Object> parameterMap = new HashMap<>();
         parameterMap.put(DefaultActionMapper.ACTION_PREFIX + "myAction.x", "");
         parameterMap.put(DefaultActionMapper.ACTION_PREFIX + "myAction.y", "");
 
@@ -524,8 +524,8 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("myAction", actionMapping.getName());
     }
 
-    public void testRedirectPrefix() throws Exception {
-        Map parameterMap = new HashMap();
+    public void testRedirectPrefix() {
+        Map<String, Object> parameterMap = new HashMap<>();
         parameterMap.put("redirect:" + "http://www.google.com", "");
 
         StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest();
@@ -540,8 +540,8 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertNull(result);
     }
 
-    public void testUnsafeRedirectPrefix() throws Exception {
-        Map parameterMap = new HashMap();
+    public void testUnsafeRedirectPrefix() {
+        Map<String, Object> parameterMap = new HashMap<>();
         parameterMap.put("redirect:" + "http://%{3*4}", "");
 
         StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest();
@@ -556,8 +556,8 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertNull(result);
     }
 
-    public void testRedirectActionPrefix() throws Exception {
-        Map parameterMap = new HashMap();
+    public void testRedirectActionPrefix() {
+        Map<String, Object> parameterMap = new HashMap<>();
         parameterMap.put("redirectAction:" + "myAction", "");
 
         StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest();
@@ -573,8 +573,8 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertNull(result);
     }
 
-    public void testUnsafeRedirectActionPrefix() throws Exception {
-        Map parameterMap = new HashMap();
+    public void testUnsafeRedirectActionPrefix() {
+        Map<String, Object> parameterMap = new HashMap<>();
         parameterMap.put("redirectAction:" + "%{3*4}", "");
 
         StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest();
@@ -590,8 +590,8 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertNull(result);
     }
 
-    public void testRedirectActionPrefixWithEmptyExtension() throws Exception {
-        Map parameterMap = new HashMap();
+    public void testRedirectActionPrefixWithEmptyExtension() {
+        Map<String, Object> parameterMap = new HashMap<>();
         parameterMap.put("redirectAction:" + "myAction", "");
 
         StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest();
@@ -608,8 +608,8 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertNull(result);
     }
 
-    public void testCustomActionPrefix() throws Exception {
-        Map parameterMap = new HashMap();
+    public void testCustomActionPrefix() {
+        Map<String, Object> parameterMap = new HashMap<>();
         parameterMap.put("foo:myAction", "");
 
         final StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest();
@@ -627,39 +627,39 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals(actionMapping.getName(), "myAction");
     }
 
-    public void testDropExtension() throws Exception {
+    public void testDropExtension() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         String name = mapper.dropExtension("foo.action", new ActionMapping());
-        assertTrue("Name not right: "+name, "foo".equals(name));
+        assertEquals("Name not right: " + name, "foo", name);
 
         name = mapper.dropExtension("foo.action.action", new ActionMapping());
-        assertTrue("Name not right: "+name, "foo.action".equals(name));
+        assertEquals("Name not right: " + name, "foo.action", name);
 
     }
 
-    public void testDropExtensionWhenBlank() throws Exception {
+    public void testDropExtensionWhenBlank() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         mapper.setExtensions("action,,");
         String name = mapper.dropExtension("foo.action", new ActionMapping());
-        assertTrue("Name not right: "+name, "foo".equals(name));
+        assertEquals("Name not right: " + name, "foo", name);
         name = mapper.dropExtension("foo", new ActionMapping());
-        assertTrue("Name not right: "+name, "foo".equals(name));
+        assertEquals("Name not right: " + name, "foo", name);
         assertNull(mapper.dropExtension("foo.bar", new ActionMapping()));
         assertNull(mapper.dropExtension("foo.", new ActionMapping()));
     }
 
-    public void testDropExtensionEmbeddedDot() throws Exception {
+    public void testDropExtensionEmbeddedDot() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         mapper.setExtensions("action,,");
 
         String name = mapper.dropExtension("/foo/bar-1.0/baz.action", new ActionMapping());
-        assertTrue("Name not right: "+name, "/foo/bar-1.0/baz".equals(name));
+        assertEquals("Name not right: " + name, "/foo/bar-1.0/baz", name);
 
         name = mapper.dropExtension("/foo/bar-1.0/baz", new ActionMapping());
-        assertTrue("Name not right: "+name, "/foo/bar-1.0/baz".equals(name));
+        assertEquals("Name not right: " + name, "/foo/bar-1.0/baz", name);
     }
 
-    public void testGetUriFromActionMapper1() throws Exception {
+    public void testGetUriFromActionMapper1() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         ActionMapping actionMapping = new ActionMapping();
         actionMapping.setMethod("myMethod");
@@ -670,7 +670,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("/myNamespace/myActionName!myMethod.action", uri);
     }
 
-    public void testGetUriFromActionMapper2() throws Exception {
+    public void testGetUriFromActionMapper2() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         ActionMapping actionMapping = new ActionMapping();
         actionMapping.setMethod("myMethod");
@@ -681,7 +681,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("/myActionName!myMethod.action", uri);
     }
 
-    public void testGetUriFromActionMapper3() throws Exception {
+    public void testGetUriFromActionMapper3() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         ActionMapping actionMapping = new ActionMapping();
         actionMapping.setMethod("myMethod");
@@ -693,7 +693,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
     }
 
 
-    public void testGetUriFromActionMapper4() throws Exception {
+    public void testGetUriFromActionMapper4() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         ActionMapping actionMapping = new ActionMapping();
         actionMapping.setName("myActionName");
@@ -703,7 +703,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("/myActionName.action", uri);
     }
 
-    public void testGetUriFromActionMapper5() throws Exception {
+    public void testGetUriFromActionMapper5() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         ActionMapping actionMapping = new ActionMapping();
         actionMapping.setName("myActionName");
@@ -714,7 +714,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
     }
 
     //
-    public void testGetUriFromActionMapper6() throws Exception {
+    public void testGetUriFromActionMapper6() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         ActionMapping actionMapping = new ActionMapping();
         actionMapping.setMethod("myMethod");
@@ -725,7 +725,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("/myNamespace/myActionName!myMethod.action?test=bla", uri);
     }
 
-    public void testGetUriFromActionMapper7() throws Exception {
+    public void testGetUriFromActionMapper7() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         ActionMapping actionMapping = new ActionMapping();
         actionMapping.setMethod("myMethod");
@@ -736,7 +736,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("/myActionName!myMethod.action?test=bla", uri);
     }
 
-    public void testGetUriFromActionMapper8() throws Exception {
+    public void testGetUriFromActionMapper8() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         ActionMapping actionMapping = new ActionMapping();
         actionMapping.setMethod("myMethod");
@@ -748,7 +748,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
     }
 
 
-    public void testGetUriFromActionMapper9() throws Exception {
+    public void testGetUriFromActionMapper9() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         ActionMapping actionMapping = new ActionMapping();
         actionMapping.setName("myActionName?test=bla");
@@ -758,7 +758,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("/myActionName.action?test=bla", uri);
     }
 
-    public void testGetUriFromActionMapper10() throws Exception {
+    public void testGetUriFromActionMapper10() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         ActionMapping actionMapping = new ActionMapping();
         actionMapping.setName("myActionName?test=bla");
@@ -768,7 +768,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("/myActionName.action?test=bla", uri);
     }
 
-    public void testGetUriFromActionMapper11() throws Exception {
+    public void testGetUriFromActionMapper11() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         ActionMapping actionMapping = new ActionMapping();
         actionMapping.setName("myActionName.action");
@@ -778,7 +778,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("/myActionName.action", uri);
     }
 
-    public void testGetUriFromActionMapper12() throws Exception {
+    public void testGetUriFromActionMapper12() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         ActionMapping actionMapping = new ActionMapping();
         actionMapping.setName("myActionName.action");
@@ -788,7 +788,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("/myActionName.action", uri);
     }
 
-    public void testGetUriFromActionMapper_justActionAndMethod() throws Exception {
+    public void testGetUriFromActionMapper_justActionAndMethod() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         ActionMapping actionMapping = new ActionMapping();
         actionMapping.setMethod("myMethod");
@@ -799,7 +799,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("myActionName!myMethod", uri);
     }
 
-    public void testGetUriFromActionMapperWhenBlankExtension() throws Exception {
+    public void testGetUriFromActionMapperWhenBlankExtension() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         mapper.setExtensions(",,");
         ActionMapping actionMapping = new ActionMapping();
@@ -811,7 +811,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("/myNamespace/myActionName!myMethod", uri);
     }
 
-    public void testSetExtension() throws Exception {
+    public void testSetExtension() {
         DefaultActionMapper mapper = new DefaultActionMapper();
         mapper.setExtensions("");
         assertNull(mapper.extensions);
@@ -828,15 +828,40 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals(Arrays.asList("html", "", "xml"), mapper.extensions);
 
         mapper.setExtensions("xml");
-        assertEquals(Arrays.asList("xml"), mapper.extensions);
+        assertEquals(Collections.singletonList("xml"), mapper.extensions);
 
         mapper.setExtensions(",");
-        assertEquals(Arrays.asList(""), mapper.extensions);
+        assertEquals(Collections.singletonList(""), mapper.extensions);
+
+
+    }
+
+    public void testAllowedNamespaceNames() {
+        DefaultActionMapper mapper = new DefaultActionMapper();
+
+        String namespace = "/";
+        assertEquals(namespace, mapper.cleanupNamespaceName(namespace));
+
+        namespace = "${namespace}";
+        assertEquals(mapper.defaultNamespaceName, mapper.cleanupNamespaceName(namespace));
+
+        namespace = "${${%{namespace}}}";
+        assertEquals(mapper.defaultNamespaceName, mapper.cleanupNamespaceName(namespace));
+
+        namespace = "${#foo='namespace',#foo}";
+        assertEquals(mapper.defaultNamespaceName, mapper.cleanupNamespaceName(namespace));
+
+        namespace = "/test-namespace/namespace/";
+        assertEquals("/test-namespace/namespace/", mapper.cleanupNamespaceName(namespace));
 
+        namespace = "/test_namespace/namespace-test/";
+        assertEquals("/test_namespace/namespace-test/", mapper.cleanupNamespaceName(namespace));
 
+        namespace = "/test_namespace/namespace.test/";
+        assertEquals("/test_namespace/namespace.test/", mapper.cleanupActionName(namespace));
     }
 
-    public void testAllowedActionNames() throws Exception {
+    public void testAllowedActionNames() {
         DefaultActionMapper mapper = new DefaultActionMapper();
 
         String actionName = "action";
@@ -861,7 +886,7 @@ public class DefaultActionMapperTest extends StrutsInternalTestCase {
         assertEquals("test!bar.action", mapper.cleanupActionName(actionName));
     }
 
-    public void testAllowedMethodNames() throws Exception {
+    public void testAllowedMethodNames() {
         DefaultActionMapper mapper = new DefaultActionMapper();
 
         assertEquals("", mapper.cleanupMethodName(""));
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 1503ae2..d2631f0 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
@@ -364,7 +364,7 @@ public class RestActionMapper extends DefaultActionMapper {
             name = uri.substring(namespace.length() + 1);
         }
 
-        mapping.setNamespace(namespace);
+        mapping.setNamespace(cleanupNamespaceName(namespace));
         mapping.setName(name);
     }