5

Currently I am using Struts 2.3.12 in my project and all the things are working fine. Now I have requirement to upgrade Struts version to 2.3.20 to address some security issue.

I changed the Struts and required Struts plugins version to 2.3.20 in my project pom.xml and build the project war. Now, I am trying to access my application home URL then getting following exception:

There is no Action mapped for namespace [/web/public] and action name [reset-password!reset] associated with context path [/ims]. - [unknown location]

com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:185)
org.apache.struts2.impl.StrutsActionProxy.prepare(StrutsActionProxy.java:63)
org.apache.struts2.impl.StrutsActionProxyFactory.createActionProxy(StrutsActionProxyFactory.java:37)
com.opensymphony.xwork2.DefaultActionProxyFactory.createActionProxy(DefaultActionProxyFactory.java:58)
org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:554)
org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:81)
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
org.displaytag.filter.ResponseOverrideFilter.doFilter(ResponseOverrideFilter.java:125)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:172)
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
org.josso.tc55.agent.SSOAgentValve.invoke(SSOAgentValve.java:472)
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:174)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:875)
org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)
java.lang.Thread.run(Thread.java:662)

I couldn't get a single clue on what is happening.

I looked into the release note of struts 2.3.20 but I am not getting any hint.

I'm using strust2-convention-plugin.

I am sharing my web.xml and struts.xml files. It looks like as following:

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="jail" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>ims</display-name>

    <!-- JCaptcha servlet mapping -->
    <servlet>
        <servlet-name>jcaptcha</servlet-name>
        <servlet-class>com.sapienza.jail.controller.jcaptcha.JailImageCaptchaServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>jcaptcha</servlet-name>
        <url-pattern>/web/public/jcaptcha.jpg</url-pattern>
    </servlet-mapping>
    
    <!-- Filters -->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/web/*</url-pattern>
    </filter-mapping>
    
    <filter>
        <filter-name>ResponseOverrideFilter</filter-name>
        <filter-class>org.displaytag.filter.ResponseOverrideFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>ResponseOverrideFilter</filter-name>
        <url-pattern>/web/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/web/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/web/public/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>*.action</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>*.jsp</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/struts/*</url-pattern>
    </filter-mapping>

    <!-- JSP configuration -->
    <jsp-config>
        <jsp-property-group>
            <url-pattern>*.jsp</url-pattern>
            <el-ignored>false</el-ignored>
            <page-encoding>UTF-8</page-encoding>
            <include-prelude>/jsp/common/taglibs.jspf</include-prelude>
        </jsp-property-group>
    </jsp-config>
    <welcome-file-list>
        <welcome-file>/jsp/common/home.jsp</welcome-file>
    </welcome-file-list>

    <!-- Spring Listener -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

    <!-- Skin listener -->
    <listener>
        <listener-class>com.sapienza.jail.listener.ResourceListener</listener-class>
    </listener>

    <!-- LDAP Synchronisation Listeneer -->
    <listener>
        <listener-class>com.sapienza.jail.listener.LdapSyncListener</listener-class>
    </listener>

    <!-- Tiles listener -->
    <listener>
        <listener-class>org.apache.struts2.tiles.StrutsTilesListener</listener-class>
    </listener>

    <context-param>
        <param-name>org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG</param-name>
        <param-value>/WEB-INF/tiles/skins-definitions.xml,/WEB-INF/tiles/pages-definitions.xml</param-value>
    </context-param>
    <context-param>
        <param-name>org.apache.tiles.evaluator.AttributeEvaluator</param-name>
        <param-value>org.apache.tiles.evaluator.el.ELAttributeEvaluator</param-value>
    </context-param>
    
</web-app>

struts.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    
    <include file="struts-default.xml"/>
    
    <constant name="struts.objectFactory" value="spring"/>
    <constant name="struts.devMode" value="true"/>
    <constant name="struts.convention.default.parent.package" value="base-configuration"/>
    <constant name="struts.convention.classes.reload" value="true"/>
    <constant name="struts.enableJSONValidation" value="true"/>
    
    <!-- struts configuration common for the whole application -->
    <include file="struts-base.xml"/>
    
</struts>

struts-base.xml:

<struts>

    <!-- This package is abstract. It is not mean to declare any actions, only 
        common components such as interceptors, global results ... -->
    <package name="base-configuration" abstract="true" extends="tiles-default">

        <result-types>
            <result-type name="jasper" class="org.apache.struts2.views.jasperreports.JasperReportsResult"/>
            <result-type name="json" class="org.apache.struts2.json.JSONResult"/>
            <result-type name="tiles" class="org.apache.struts2.views.tiles.TilesResult"/>
        </result-types>

        <!-- create a custom paramsPrepareParamsStack using our log4j interceptor -->
        <interceptors>
            <!-- declaration of the custom interceptor using log4j to log exceptions. -->
            <interceptor name="log4jExceptionMappingInterceptor" class="log4jExceptionMappingInterceptor" />

            <!-- declaration of the custom security interceptor -->
            <interceptor name="securityInterceptor" class="securityInterceptor" />

            <!-- declaration of the custom SearchBean interceptor -->
            <interceptor name="searchBeanInterceptor" class="searchBeanInterceptor" />

            <!-- declaration of the custom WhiteSpaceTrim interceptor -->
            <interceptor name="whiteSpaceTrimmerInterceptor" class="whiteSpaceTrimmerInterceptor" />

            <!-- Struts2 JSON Validation -->
             <interceptor name="jsonValidation" class="org.apache.struts2.json.JSONValidationInterceptor" />

            <interceptor-stack name="imsDefaultStack">
                <!-- insert log4j interceptor inserted in the custom stack -->
                <interceptor-ref name="log4jExceptionMappingInterceptor" />
                <!-- insert the custom security interceptor -->
                <interceptor-ref name="securityInterceptor" />
                <interceptor-ref name="alias" />
                <interceptor-ref name="params" />
                <interceptor-ref name="servletConfig" />
                <interceptor-ref name="prepare" />
                <interceptor-ref name="i18n" />
                <interceptor-ref name="chain" />
                <interceptor-ref name="checkbox" />
                <interceptor-ref name="staticParams" />
                <interceptor-ref name="params" />
                <!-- excludes base CRUD methods from the validation process -->
                <!-- validation interceptor triggers the xml validation -->
                <interceptor-ref name="validation">
                    <param name="validateAnnotatedMethodOnly">true</param>
                    <param name="excludeMethods">input,back,cancel,list,view,initCreate,initUpdate,delete</param>
                </interceptor-ref>
                <!-- ajax validation interceptor -->
                <interceptor-ref name="jsonValidation">
                    <param name="excludeMethods">input</param>
                </interceptor-ref>
                <!-- workflow interceptor triggers programmatic validation (calls validate()) -->
                <interceptor-ref name="workflow">
                    <param name="excludeMethods">input,back,cancel,list,view,initCreate,initUpdate,delete</param>
                </interceptor-ref>
            </interceptor-stack>

            <!-- this new custom stack will be used for public URL -->
            <interceptor-stack name="imsNoSecurityStack">
                <!-- insert log4j interceptor inserted in the custom stack -->
                <interceptor-ref name="log4jExceptionMappingInterceptor" />
                <interceptor-ref name="alias" />
                <interceptor-ref name="params" />
                <interceptor-ref name="servletConfig" />
                <interceptor-ref name="prepare" />
                <interceptor-ref name="i18n" />
                <interceptor-ref name="chain" />
                <interceptor-ref name="checkbox" />
                <interceptor-ref name="staticParams" />
                <interceptor-ref name="params" />
                <!-- excludes base CRUD methods from the validation process -->
                <!-- validation interceptor triggers the xml validation -->
                <interceptor-ref name="validation">
                    <param name="validateAnnotatedMethodOnly">true</param>
                    <param name="excludeMethods">input,back,cancel,list,view,initCreate,initUpdate,delete</param>
                </interceptor-ref>
                <!-- ajax validation interceptor -->
                <interceptor-ref name="jsonValidation">
                    <param name="excludeMethods">input</param>
                </interceptor-ref>
                <!-- workflow interceptor triggers programmatic validation (calls validate()) -->
                <interceptor-ref name="workflow">
                    <param name="excludeMethods">input,back,cancel,list,view,initCreate,initUpdate,delete</param>
                </interceptor-ref>
            </interceptor-stack>
        </interceptors>

        <!-- the new custom stack will be the default one used in the sub packages. -->
        <default-interceptor-ref name="imsDefaultStack" />

        <!-- exception handling -->
        <global-results>
            <result name="error">/jsp/common/error.jsp</result>
            <result name="securityError">/jsp/common/access-denied.jsp</result>
            <result name="ldapError">/jsp/common/ldap-connection-error.jsp</result>
        </global-results>
        
        <!-- any unhandled exceptions will return the error page displaying the 
                message of the exception. -->
        <global-exception-mappings>
            <exception-mapping result="error" exception="java.lang.Exception" />
            <exception-mapping result="securityError" exception="com.sapienza.jail.exception.NoApplicationAccess" />
            <exception-mapping result="ldapError" exception="com.sapienza.jail.exception.LDAPConnectionException" />
        </global-exception-mappings>

    </package>

</struts>

I am using annotation based action mapping in my class as following

@Results({
    @Result(name="index", type="tiles", location="testPage"),
    @Result(name = "redirect", location = "user/search-user!view", type =   "redirectAction")
})
@Namespace("/web/public")
@Action
public class HomeAction extends BaseAction {

    private static final Logger logger = Logger.getLogger(HomeAction.class);
    private static final String SESSIONBASKET = "userSessionBasket";
    //-------------------------------------------------------------------------
    // Dependencies injected by spring via setters
    //-------------------------------------------------------------------------
    
    //-------------------------------------------------------------------------
    // Constructor and methods
    //-------------------------------------------------------------------------
    public HomeAction() {
    }   
    
    @Override
    public String execute() {
        if (isInHttpSession(SESSIONBASKET)){
            getSession().removeAttribute(SESSIONBASKET);
        }
        return result(REDIRECT_RESULT);
    }

    
    //-------------------------------------------------------------------------
    // Getters and Setters
    //-------------------------------------------------------------------------

}
Roman C
  • 49,761
  • 33
  • 66
  • 176
S Panday
  • 61
  • 1
  • 6
  • Are you still using DMI (`!reset`) ? Please show your struts.xml and web.xml – Andrea Ligios Feb 25 '15 at 17:22
  • Yes, I am stil using DMI. – S Panday Feb 25 '15 at 17:30
  • Since you said you're migrating to 2.3.20 for security reasons, then DMI should be avoided as much as possible, for the same reason: http://security.coverity.com/blog/2013/Oct/making-struts2-app-more-secure-disable-dynamic-method-invocation.html . Also take a look at this: http://stackoverflow.com/a/20746720/1654265 – Andrea Ligios Feb 25 '15 at 17:36
  • @AndreaLigios Added the web.xml and struts.xml files. I am using the annotation based action mapping in project – S Panday Feb 25 '15 at 17:58

3 Answers3

1

Been struggling with the upgrade from struts 2.3.16 to 2.3.20 for a while. Not sure we're facing the same problem, but, still, I'm sharing the resolution that worked for me.

The REST plugin actions, which should have been indexed by suffix using the conventions: e.g. struts.convention.action.suffix = Controller

Was not working at all after upgrading all the struts2-* jar files and xwork-core.jar

Nothing was printed in logs.

Finally, came across with this post: http://comments.gmane.org/gmane.comp.jakarta.struts.user/186383 "I had the same problem this morning after updating just the struts2 and xwork jar files. I updated the asm, asm-commons, asm-tree, and commons-lang3 jar files to those found in the struts-2.3.20-lib.zip file and the problem went away."

After upgrading the asm-*.jar, as well, the problems went away.

The only thing I could not understand, was that the 2.3.20 release, downgrades some jar files, like commons-validator to 1.3.1 (from 1.4.0) and common-collections to 1.3.1 (from 3.2.1).

Hope it helps your projects as well.

Cheers

vfonseca
  • 91
  • 6
1

Finally I found the culprit, It was due to conflicting asm jar which is being including twice with versions(3.1 and 5.1) in my application lib forder. After upgrading to struts 2.3.20 it was downloading asm 5.1 and asm 3.1 was being included from parent app pom.

Also you have to enable DMI explicitly by adding following constant in your struts.xml.

<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
S Panday
  • 61
  • 1
  • 6
0

Since the version is changed the Struts default ActionMapper implementation changed significantly. Many security fixes were applied during that.

You could check the security bulletins.

The problem is that you use DMI with URL mapping. The DMI is turned off by default. The DMI feature may not work in the current version of Struts, and you should change your action's mapping.

But prior to upgrading to 2.3.20 you could try upgrading to 2.3.16.3.

To turn on DMI try to enable it using a constant:

<constant name="struts.enable.DynamicMethodInvocation" value="true"/> 
Roman C
  • 49,761
  • 33
  • 66
  • 176
  • I explicitly enabled DMI by adding, constant as you metioned, in my struts.xml but it does not help me out. Actually I have a large application and using DMI in whole application so it will be very tough job to remove DMI quickly. Is there any way, so currently I can go with DMI with upgraded version – S Panday Feb 26 '15 at 04:05
  • What is the Struts version? – Roman C Feb 26 '15 at 08:33
  • Struts version is 2.3.20 – S Panday Feb 26 '15 at 10:14