Dear Wiki user, You have subscribed to a wiki page or wiki category on "Struts Wiki" for change notification.
The following page has been changed by Roberto Velasco: http://wiki.apache.org/struts/HDIV ------------------------------------------------------------------------------ Obviously, in this case the use of HDIV is not transparent as it is when we use the extended tags. Anyway, the validation phase made by the HDIV filter doesn't change in any case. + + = SPI (ParameterProcessing) Integration = + + '''HDIV team:''' As we mentioned earlier, from our point of view it is more adecuate to integrate HDIV with Struts via SPI due to the following reasons: + + * We avoid a direct dependency between Struts and HDIV. + * Offers an extension point for Struts tags that can be used for other projects apart from the ones related with security or HDIV. + + The new extension point provided by the SPI offers these functionalities: + * Add new parameters to forms and links + * Modify the value of the parameters + * Modify the name of the parameters + + The SPI could be used for both Struts 1 and Struts 2. Being defined in a so high level it could be used for any web framework, although this + would be a secondary objective. + + In order to support the SPI option, we have developed the following software components: + 1. SPI + 2. Struts 1.3.8 tags' version using the SPI + 3. Two implementations of the SPI: empty and HDIV's implementation + 4. Web application using these new components: struts-examples + + The SPI, the new version of SPI-consuming tags and the empty SPI implementation would be part of Struts, without any HDIV dependency. In the case of Struts 2, a new version of tags must be implemented. We could implement it if necessary. + As an additional information, we describe more deeply each of the developed components: + + + ==== 1.SPI ==== + It is consumed by the HTML tags in order to offer extension points and extend tag's core behaviour. Thus, we avoid extending each tag separately. The name of the SPI is ParameterProcessing and this is its definition: + + + {{{ + + package org.apache.struts.config; + + import java.util.Map; + import javax.servlet.http.HttpServletRequest; + + /** + * <p> + * It is consumed by the HTML tags in order to offer extension points and extend + * tag's core behaviour. + * </p> + * <p> + * Struts will distribute one implementation of this interface maintaining + * present behaviour: org.apache.struts.config.impl.EmptyParameterProcessing. It + * doesn't process any form or link parameter, leaving values as they are + * received as parameters. + * </p> + * <p> + * By default, Struts will be configured to use HDIV's implementation + * (org.hdiv.config.impl.HDIVParameterProcessing) which guarantees data integrity + * and confidentiality. + * </p> + * + * @author hdiv.org + */ + public interface ParameterProcessing { + + /** + * Init method. + * + * @param request The servlet request we are processing + */ + public void init(HttpServletRequest request); + + /** + * <p> + * It is called by each form of the html page returned by the server. The + * value returned by this method will be the value assigned to the form's + * "action" attribute. + * </p> + * + * @param action Action value. + * @return Returns the value of form´s "action" attribute + */ + public String processStartForm(String action); + + /** + * <p> + * It is called each time the "name" attribute of the form parameter needs + * to be rendered. The value returned by this method will be the value + * assigned to the form's "name" attribute. + * </p> + * + * @param name HTTP parameter name + * @param type parameter's type (select, radio, hidden, etc.). Most of the + * times the value for this parameter is the value of the tag's "type" + * attribute. Sometimes it is needed to explicitly indicate the type + * parameter, because some HTML tags lack it. + * @return Value for the "name" attribute for the <code>name</code> + * parameter. + */ + public String processFormParameterName(String name, String type); + + /** + * <p> + * It is called each time the "value" attribute of the form parameter needs + * to be rendered. The value returned by this method will be the value + * assigned to the form's "value" attribute. + * </p> + * <p> + * In the default implementation configured by Struts, it generates a new + * encoded value for the parameter <code>name</code> and the value + * <code>value</code> passed as parameters. The returned value guarantees + * the confidentiality in the cipher and memory strategies if + * confidentiality is activated. + * </p> + * + * @param name HTTP parameter name + * @param value parameter's value + * @param type parameter's type (select, radio, hidden, etc.). Most of the + * times the value for this parameter is the value of the tag's "type" + * attribute. Sometimes it is needed to explicitly indicate the type + * parameter, because some HTML tags lack it. + * @return Value for the "value" attribute of the form's <code>name</code> + * parameter + */ + public String processFormParameterValue(String name, String value, String type); + + /** + * <p> + * It is invoked before the form is closed and it returns the extra + * parameters, the ones not defined using HTML tags, that must be added to + * the form. For instance, parameters for controlling the application's + * flow, random token to avoid CSRF attacks, etc. + * </p> + * <p> + * In the default implementation configured by Struts, the HDIV parameter + * that guarantees data integrity and random token to avoid CSRF attacks are + * returned. If our application uses Spring Web Flow, we can add the + * <code>_flowExecutionKey</code> parameter to the forms and links + * automatically by using the hdiv-webflow-x.x library. See HDIV's + * repository: <a href="http://repo1.maven.org/maven2/org/hdiv/">HDIV + * (Central Repository)</a> + * </p> + * + * @return Returns parameters' map that we need to add to form as new + * fields. + */ + public Map getExtraFormParameters(); + + /** + * <p> + * It is invoked each time the "href" attribute of a url generated by the + * <code>link</code>, <code>frame</code>, <code>redirect</code> and + * <code>forward</code> tags needs to be rendered. + * </p> + * <p> + * In the default implementation configured by Struts, it generates new + * encoded values for the <code>url</code> parameters only if + * confidentiality is activated, and adds HDIV's parameter and a random + * token parameter to avoid data tampering and CSRF attacks respectively. + * </p> + * + * @param url request url + * @param charEncoding character encoding + * @return url Processed url + */ + public String processURL(String url, String charEncoding); + + } + + + + + }}} + + ==== 2.Struts 1.3.8 tags' version using the SPI ==== + + We have modified Struts 1.3.8 HTML and LOGIC (redirect and forward) tags by adding calls to the SPI methods. + We have implemented tags so that each time the attributes "name" or "value" need to be rendered they call SPI methods which process these values and obtain the processed value. + Let's see an example with the tag "hidden". Keep in mind that this tag extends BaseFieldTag class which renderizes the HTML of the hidden field. + + {{{ + + /** + * Custom tag for input fields of type "hidden". + * + * @version hdiv.org + */ + public class HiddenTag extends BaseFieldTag { + + ... + /** + * @return Returns the value to be rendered in the ânameâ attribute. + * @throws JspException if a JSP exception has occurred + * @version hdiv.org + */ + public String processName() throws JspException { + return processFormParameterName(prepareName(), this.type); + } + + /** + * @return Returns the value to be rendered in the âvalueâ attribute. + * @throws JspException if a JSP exception has occurred + * @version hdiv.org + */ + public String processValue() throws JspException { + return processFormParameterValue(prepareName(), prepareValue(), this.type); + } + + ... + } + + }}} + + {{{ + + /** + * Convenience base class for the various input tags for text fields. + * + * @version hdiv.org + */ + public abstract class BaseFieldTag extends BaseInputTag { + + ... + + /** + * Renders a fully formed <input> element. + * @throws JspException + */ + protected String renderInputElement() throws JspException { + StringBuffer results = new StringBuffer("<input"); + prepareAttribute(results, "type", this.type); + + prepareAttribute(results, "name", processName()); <---- new implementation + + prepareAttribute(results, "accesskey", getAccesskey()); + prepareAttribute(results, "accept", getAccept()); + prepareAttribute(results, "maxlength", getMaxlength()); + prepareAttribute(results, "size", getCols()); + prepareAttribute(results, "tabindex", getTabindex()); + + prepareAttribute(results, "value", this.formatValue(processValue())); <---- new implementation + + results.append(this.prepareEventHandlers()); + results.append(this.prepareStyles()); + prepareOtherAttributes(results); + results.append(this.getElementClose()); + return results.toString(); + } + /** + * @return Returns the value to be rendered in the âvalueâ attribute. + * @throws JspException if a JSP exception has occurred + * @version hdiv.org + */ + public abstract String processValue() throws JspException; + /** + * @return Returns the value to be rendered in the ânameâ attribute. + * @throws JspException if a JSP exception has occurred + * @version hdiv.org + */ + public abstract String processName() throws JspException; + ... + } + + }}} + + {{{ + /** + * Base class for tags that render form elements capable of including JavaScript + * event handlers and/or CSS Style attributes. This class does not implement the + * doStartTag() or doEndTag() methods. Subclasses should provide appropriate + * implementations of these. + * + * @version hdiv.org + */ + public abstract class BaseHandlerTag extends BodyTagSupport { + + ... + + public String processFormParameterValue(String name, String value, String type) { + + ParameterProcessing paramProcessing = TagUtils.getInstance().getParameterProcessing(pageContext); + return paramProcessing.processFormParameterValue(name, value, type); + } + + public String processFormParameterName(String name, String type) { + + ParameterProcessing paramProcessing = TagUtils.getInstance().getParameterProcessing(pageContext); + return paramProcessing.processURL(url, charEncoding); + } + + ... + } + + }}} + + {{{ + /** + * Base class for tags that render form elements capable of including JavaScript + * event handlers and/or CSS Style attributes. This class does not implement the + * doStartTag() or doEndTag() methods. Subclasses should provide appropriate + * implementations of these. + * + * @version hdiv.org + */ + public class TagUtils { + + ... + + /** + * <p>Returns the ParameterProcessing class on the specified module.</p> + * + * @param pageContext PageContext we are operating in + * @return Returns the ParameterProcessing class on the specified module. + * @author hdiv.org + */ + public ParameterProcessing getParameterProcessing(PageContext pageContext) { + + ModuleConfig config = getInstance().getModuleConfig(pageContext); + String paramProcessingClass = config.getControllerConfig().getParameterProcessingClass(); + + return (ParameterProcessing) pageContext.getAttribute(paramProcessingClass, + PageContext.REQUEST_SCOPE); + } + + }}} + + We always invoke methods from the SPI to obtain the values of the attributes "name" and "value" using processName() and processValue() methods. + This is the main rule that we have followed for all the tags. As we can see in the definition of the SPI, there are methods to be invoked in other cases, for example in the beginning and in the end of a form or when generating an url; For these cases "form" and "link" tags have been implemented. Let's see the implementation of the tag "form": + + {{{ + public class FormTag extends TagSupport { + + ... + + /** + * Renders the action attribute + */ + protected void renderAction(StringBuffer results) { + + String calcAction = (this.action == null ? postbackAction : this.action); + HttpServletResponse response = (HttpServletResponse) this.pageContext.getResponse(); + + String url = response.encodeURL(TagUtils.getInstance().getActionMappingURL(calcAction, this.pageContext)); + + results.append(" action=\""); + results.append(processStartForm(url)); <---- new implementation + results.append("\""); + } + + public String processStartForm(String action) { + + ParameterProcessing paramProcessing = TagUtils.getInstance().getParameterProcessing(pageContext); + return paramProcessing.processStartForm(action); + } + + public int doEndTag() throws JspException { + renderExtraParams(); + ... + } + + /** + * Adds fields to form + * @throws JspException + * @author hdiv.org + */ + public void renderExtraParams() throws JspException { + + ParameterProcessing paramProcessing = TagUtils.getInstance().getParameterProcessing(pageContext); + Map extraParams = paramProcessing.getExtraFormParameters(); + + if (extraParams != null) { + String key = null; + for (Iterator iter = extraParams.keySet().iterator(); iter.hasNext();) { + key = (String) iter.next(); + TagUtils.getInstance().write(pageContext, renderField(key, (String) extraParams.get(key))); + } + } + } + + /** + * Renders an HTML <b><input></b> element of type hidden. + * + * @param name hidden parameter name + * @param value value + * @return HTML <b><input></b> element of type hidden + * @author hdiv.org + */ + public String renderField(String name, String value) { + StringBuffer sb = new StringBuffer(); + sb.append("<input type=\"hidden\""); + renderAttribute(sb, "name", name); + renderAttribute(sb, "value", value); + sb.append(">\n"); + + return sb.toString(); + } + + ... + } + }}} + + + In this case, we invoke '''processStartForm''' method to get the value for the "action" attribute in the form. And before the end of the form, we invoke '''getExtraFormParameters''' method to get the extra parameters to be added to the form. For instance, parameters for controlling the application's flow like _flowExecutionKey in Spring Web Flow, random token to avoid CSRF attacks, and _HDIV_STATE_ parameter to guarantee integrity and confidentiality. + + ==== 3. Two implementations of the SPI ==== + + * empty (EmptyParameterProcessing): it maintains the Struts' present behaviour. + * HDIV (HDIVParameterProcesing): it guarantees data integrity and confidentiality. + + In order to configure the SPI implementation, we must define the name of the class in the parameterProcessingClass attribute of the controller. Thus, the SPI implementation to use is defined for each module, making it possible to define different implementations for different modules. '''By default''', if we don't define any value for this new attribute, the '''HDIVâs implementation will be used''', which guarantees data integrity and confidentiality. + * struts-config-1_3.dtd file has been modified by adding the new "parameterProcessingClass" attribute. + + + See the example in point 4 to get more information about this configuration. + + ActionServlet: The servlet has been modified to make it create a new instance of the SPI for each request made using the class defined in the controller. + + ==== 4. Web application using these new components: struts-examples ==== + + We have configured the struts-examples application provided with the Struts 1.3.8 distribution to make it use different SPI implementations. + * Default SPI configuration: No implementation has been configured for â/exerciseâ, â/uploadâ and â/hdivâ modules. This means that SPIâs default implementation (HDIVParameterProcessing) will be used, which guarantees data integrity and confidentiality. + + + * We have configured for â/validationâ and â/attacksâ modules SPI's empty implementation to maintain Struts' present behaviour. + + {{{ + <controller parameterProcessingClass="org.apache.struts.config.impl.EmptyParameterProcessing"> + }}} + +