Parameters with no mutators and accessors (setters/getters) along with the parameters interceptor in Struts 2
Asked Answered
E

3

7

In the following action class, I'm using the parameters interceptor.

@Namespace("/admin_side")
@ResultPath("/WEB-INF/content")
@ParentPackage(value = "struts-default")
@InterceptorRefs(@InterceptorRef(value="store", params={"operationMode", "AUTOMATIC"}))
public final class TestAction extends ActionSupport implements Serializable, ValidationAware, Preparable
{
    private static final long serialVersionUID = 1L;

    private String param1;
    private String param2;

    //Getters and setters.

    public TestAction() {}

    @Action(value = "TestMessage",
        results = {
            @Result(name=ActionSupport.SUCCESS, type="redirectAction", params={"namespace", "/admin_side", "actionName", "Test"}),
            @Result(name = ActionSupport.INPUT, location = "Test.jsp")},
        interceptorRefs={
            @InterceptorRef(value="paramsPrepareParamsStack", params={"params.acceptParamNames", "param1, param2", "params.excludeParams", "extraParam", "validation.validateAnnotatedMethodOnly", "true"})
        })
    public String insert() {
        // Do something. Add or update a row to the database (one at a time).
        addActionMessage("Action message");
        addActionError("Error message");
        return ActionSupport.SUCCESS;
    }

    @Action(value = "Test",
    results = {
        @Result(name = ActionSupport.SUCCESS, location = "Test.jsp"),
        @Result(name = ActionSupport.INPUT, location = "Test.jsp")},
    interceptorRefs = {
        @InterceptorRef(value = "paramsPrepareParamsStack", params = {"params.acceptParamNames", "param1, param2", "params.excludeParams", "extraParam", "validation.validateAnnotatedMethodOnly", "true", "validation.excludeMethods", "load"})})
    public String load() throws Exception {
        // This method is just required to return an initial view on page load.
        return ActionSupport.SUCCESS;
    }

    @Override
    public void prepare() throws Exception {}
}

The following is <s:form>:

<s:form namespace="/admin_side" action="Test" validate="true" id="dataForm" name="dataForm">
    <s:if test="hasActionMessages()">
        <s:actionmessage theme="jquery"/>
    </s:if>

    <s:if test="hasActionErrors()">
        <s:actionerror theme="jquery"/>
    </s:if>

    <s:hidden name="param1"/>
    <s:hidden name="param2"/>
    <s:hidden name="extraParam"/>
    <s:submit value="Submit" action="TestMessage"/>
</s:form>

Here, the hidden form field extraParam is not declared and consequently, has no setter and getter in the action class.

In this case, the following message appears on the server terminal, when this form is submitted.

SEVERE: Developer Notification (set struts.devMode to false to disable this message): Unexpected Exception caught setting 'extraParam' on 'class actions.TestAction: Error setting expression 'extraParam' with value ['', ]

params.excludeParams does not exclude the parameter extraParam as in the action class.

Can we somehow prevent such exceptions while using the parameters interceptor. Such messages are unnecessarily added to action messages and displayed through <s:actionmessage/>, if used, when they are not supposed to be shown at all.


If this paramsPrepareParamsStack is replaced with defaultStack in the action class then, such messages don't appear. It just gives a warning as follows.

WARNING: Parameter [extraParam] is on the excludeParams list of patterns!

Please don't just say, set struts.devMode to false to disable such messages.

Edveh answered 6/2, 2014 at 15:31 Comment(5)
Why do you think that parameters are inherited?Vulnerable
"parameters are inherited?" I don't understand!Edveh
if you have some configuration and it has some parameters to the action or interceptor, and you extend them from the parent package and it becomes not the same as if you specify an annotation on the class or on the method.Vulnerable
@RomanC : You may please answer the question. I don't understand the thing you're mentioning.Edveh
Please add answer(s), if someone has.Edveh
V
2

I've already said in the comment that interceptor parameters are not inherited by the interceptor configs of the parent packages if you define your own set of parameters that override the default settings. See Interceptor Parameter Overriding Inheritance.

There are also some techniques used to obtain two different maps of interceptor parameters, see Getting Interceptor Parameters in Struts2.

The convention plugin creates XWork package configs that inherited from some parent package. See my answer for Struts 2 Convention Plugin Define Multiple Parent Packages.

So, all you have to do is to override the default parameter set by the parent configuration if you want to add your own parameters to the set. Either interceptor tag or interceptor-stack tag and you should do it for each interceptor-ref tag.

The convention plugin uses @InterceprorRef annotation for the same purpose but with a caveat that if applied on the class, it applies on each action of that class. So, be careful when using this annotation on the class level. You are overriding the interceptor stack parameters, so you should use a prefix followed by dot of the interceptor name referenced in the stack for each parameter name, but this only works if you have unique names of the interceptor-refs in the stack.

If you have two references of the params interceptor in the paramsPrepareParamsStack then you can't override the second params interceptor-ref unless you create your own interceptor stack and specify parameter overrides on each reference of the interceptor.

Vulnerable answered 10/5, 2014 at 11:12 Comment(1)
Thanks. I will try to put it into practice later on.Edveh
H
1

Lets take a look at the paramsPrepareParamsStack:

 <interceptor-stack name="paramsPrepareParamsStack">
      <interceptor-ref name="exception"/>
      <interceptor-ref name="alias"/>
      <interceptor-ref name="i18n"/>
      <interceptor-ref name="checkbox"/>
      <interceptor-ref name="multiselect"/>
      <interceptor-ref name="params">
          <param name="excludeParams">dojo\..*,^struts\..*</param>
      </interceptor-ref>
      <interceptor-ref name="servletConfig"/>
      <interceptor-ref name="prepare"/>
      <interceptor-ref name="chain"/>
      <interceptor-ref name="modelDriven"/>
      <interceptor-ref name="fileUpload"/>
      <interceptor-ref name="staticParams"/>
      <interceptor-ref name="actionMappingParams"/>
      <interceptor-ref name="params">
          <param name="excludeParams">dojo\..*,^struts\..*</param>
       </interceptor-ref>
       <interceptor-ref name="conversionError"/>
       <interceptor-ref name="validation">
           <param name="excludeMethods">input,back,cancel,browse</param>
       </interceptor-ref>
       <interceptor-ref name="workflow">
           <param name="excludeMethods">input,back,cancel,browse</param>
       </interceptor-ref>
 </interceptor-stack>

There are 2 params interceptors. When you are setting excludeParams parameter in your action class, then this is probably set for the first params interceptor - parameter for the second interceptor stays default. Now, when the second params interceptor (with default excludeParams) is invoked, then given exception is thrown.

You can try to duplicate setting of the excludeParams parameter to set its also for the second interceptor:

 @InterceptorRef(value = "paramsPrepareParamsStack", params = {"params.acceptParamNames", "param1, param2", "params.excludeParams", "extraParam", "params.excludeParams", "extraParam", "validation.validateAnnotatedMethodOnly", "true", "validation.excludeMethods", "load"})})
Hilburn answered 16/2, 2014 at 22:4 Comment(4)
The code snippet in the question is just an example. In reality, there are no defined parameters as extraParam as even end users can supply any number of malicious parameters (depending upon the length of the URL they are interested in) that can cause such an exception as mentioned in the question. params.acceptParamNames should only accept those parameters which are listed. The rest must be forbidden without causing such messages as in the question to appear.Edveh
As I mentioned, there are 2 params interceptors in paramsPrepareParamsStack. When you are setting params.acceptParamNames this is set only for the first interceptor. You nedd to set this parameter also for the second interceptor.Hilburn
Specifying either params.acceptParamNames or params.excludeParams twice on the parameters interceptor doesn't make a difference. It doesn't prevent the exception as mentioned in the question. Therefore, I currently don't consider accepting the answer so that it is listed in the unanswered question list. If you encounter a solution either deliberately or accidently later on, please don't forget to update the answer, no matter how much time it takes, may be years. This is the only place for me where I can learn. Thanks.Edveh
I accidently awarded the bounty to a wrong answer, first time. I feel guilty and shame for it. The action once completed can never be undone. Please forgive me. I really apologize to my mistake.Edveh
N
1

I'm not saying exactly,

sample code following as:

<s:form action="save" method="post">
    <s:textfield key="personBean.firstName" /> 
    <s:textfield key="personBean.lastName" /> 
    <s:textfield key="personBean.email" />
    <s:textfield key="personBean.phoneNumber" />
    <s:select key="personBean.sport" list="sports" />
    <s:radio key="personBean.gender" list="genders" />
    <s:select key="personBean.residency" list="states" listKey="stateAbbr" listValue="stateName"/>
    <s:checkbox key="personBean.over21" />
    <s:checkboxlist key="personBean.carModels" list="carModelsAvailable" />
    <s:submit key="submit" />
</s:form>

Maybe its not working goto this link:

Nab answered 17/2, 2014 at 12:51 Comment(1)
Thank you but in fact, I don't understand.Edveh

© 2022 - 2024 — McMap. All rights reserved.