Search code examples
javareflectionstruts2ognlvaluestack

Struts 2 calling static method when struts.ognl.allowStaticMethodAccess is false


The struts 2 set the struts.ognl.allowStaticMethodAccess to false, for security issues. The static method invocation may be useful in some cases for example when dealing with expression base validators Struts 2 using StringUtils in validator expersions.

One way to solve this problem is to define a helper method in the action, for example, if we want to use Math class we should add below:

public double randomMath(){
  return Math.random();
}


public double asinMath(double a){
  return Math.asin(a);
}

....

And use it as ${randomMath} or ${asinMath(1)}

As you can see for every method in Math class we need to define a public method in our action, with same signature.

Is there a better way to avoid these boilerplate getters?!


Solution

  • OGNL allows execution of methods, but the static access is disabled by default, so you cannot use static method in expressions. However, you can teach OGNL which classes needs to access the static methods.

    OGNL developer guide: Method Accessors

    Method calls are another area where OGNL needs to do lookups for methods based on dynamic information. The MethodAccessor interface provides a hook into how OGNL calls a method. When a static or instance method is requested the implementor of this interface is called to actually execute the method.

    public interface MethodAccessor
    {
    
        Object callStaticMethod( Map context, Class targetClass, String methodName, List args )
            throws MethodFailedException;
    
        Object callMethod( Map context, Object target, String methodName, List args )
            throws MethodFailedException;
    
    }
    

    You can set a method accessor on a class-by-class basis using OgnlRuntime.setMethodAccessor(). The is a default method accessor for Object (which simply finds an appropriate method based on method name and argument types and uses reflection to call the method).


    You can code something

    public class StringUtil extends StringUtils implements MethodAccessor {
      //implement above methods
    }  
    

    Action class

    public static final String MESSAGE = "hello.message";
    
    /**
     * Field for Message property.
     */
    private String message;
    
    /**
     * Return Message property.
     *
     * @return Message property
     */
    public String getMessage() {
        return message;
    }
    private StringUtil stringUtil = new StringUtil();
    
    public StringUtil getStringUtil() {
      return stringUtil;
    }
    
    public String execute() throws Exception {
        setMessage(getText(MESSAGE));
        OgnlRuntime.setMethodAccessor(StringUtil.class, stringUtil);
        return SUCCESS;
    }
    

    In JSP

    <s:if test="!stringUtil.isEmpty(message)">
      <h2><s:property value="message"/></h2>
    </s:if>