struts-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From craig...@apache.org
Subject cvs commit: jakarta-struts/src/share/org/apache/struts/taglib/html Constants.java FormTag.java
Date Sun, 07 Jan 2001 04:37:07 GMT
craigmcc    01/01/06 20:37:07

  Modified:    src/example/org/apache/struts/example
                        ApplicationResources.properties
                        EditRegistrationAction.java
                        SaveRegistrationAction.java
               src/share/org/apache/struts/action Action.java
                        ActionServlet.java
               src/share/org/apache/struts/taglib/html Constants.java
                        FormTag.java
  Log:
  Add transactional token support to Struts, and use it in the example
  application to ensure that a user does not go to the edit registration
  screen, press Save, use the back arrow on their browser, and press Save
  again.
  
  Use of transactional token support is totally under the control of your
  Action classes.  See the following changes in the example app:
  * EditRegistrationAction - Call saveToken() just before forwarding
  * SaveRegistrationAction - Call isTokenValid() before accepting this
    transaction, then call resetToken() to make sure the same transaction
    is not accepted twice.
  
  The approach taken has been inspired by the input of many Struts users,
  including Robert Leland, William Jaynes, and David Geary.  In addition,
  a similar model is used in:
  
  	Fields, Duane K. and Kolb, Mark A., WEB DEVELOPMENT WITH
  		JAVA SERVER PAGES, Manning Publications, 2000
  
  NOTE:  There is still a problem with the subscription.jsp page, probably
  related to recent changes in BeanUtils and PropertyUtils, that I am
  going to look at next.
  
  Revision  Changes    Path
  1.5       +1 -0      jakarta-struts/src/example/org/apache/struts/example/ApplicationResources.properties
  
  Index: ApplicationResources.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/example/org/apache/struts/example/ApplicationResources.properties,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- ApplicationResources.properties	2000/10/15 03:34:51	1.4
  +++ ApplicationResources.properties	2001/01/07 04:37:04	1.5
  @@ -14,6 +14,7 @@
   error.password.match=<li>Password and confirmation password must match</li>
   error.password.mismatch=<li>Invalid username and/or password, please try again</li>
   error.replyToAddress.format=<li>Invalid format for Reply To Address</li>
  +error.transaction.token=<li>Cannot submit this form out of order</li>
   error.type.invalid=<li>Server Type must be 'imap' or 'pop3'</li>
   error.type.required=<li>Server Type is required</li>
   error.username.required=<li>Username is required</li>
  
  
  
  1.10      +9 -4      jakarta-struts/src/example/org/apache/struts/example/EditRegistrationAction.java
  
  Index: EditRegistrationAction.java
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/example/org/apache/struts/example/EditRegistrationAction.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- EditRegistrationAction.java	2000/10/16 05:02:38	1.9
  +++ EditRegistrationAction.java	2001/01/07 04:37:04	1.10
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/example/EditRegistrationAction.java,v
1.9 2000/10/16 05:02:38 craigmcc Exp $
  - * $Revision: 1.9 $
  - * $Date: 2000/10/16 05:02:38 $
  + * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/example/EditRegistrationAction.java,v
1.10 2001/01/07 04:37:04 craigmcc Exp $
  + * $Revision: 1.10 $
  + * $Date: 2001/01/07 04:37:04 $
    *
    * ====================================================================
    *
  @@ -87,7 +87,7 @@
    * User (if any).
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.9 $ $Date: 2000/10/16 05:02:38 $
  + * @version $Revision: 1.10 $ $Date: 2001/01/07 04:37:04 $
    */
   
   public final class EditRegistrationAction extends Action {
  @@ -171,6 +171,11 @@
                   throw new ServletException("RegistrationForm.populate", t);
               }
   	}
  +
  +        // Set a transactional control token to prevent double posting
  +        if (servlet.getDebug() >= 1)
  +            servlet.log(" Setting transactional control token");
  +        saveToken(request);
   
   	// Forward control to the edit user registration page
           if (servlet.getDebug() >= 1)
  
  
  
  1.13      +15 -5     jakarta-struts/src/example/org/apache/struts/example/SaveRegistrationAction.java
  
  Index: SaveRegistrationAction.java
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/example/org/apache/struts/example/SaveRegistrationAction.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- SaveRegistrationAction.java	2000/12/29 22:33:54	1.12
  +++ SaveRegistrationAction.java	2001/01/07 04:37:05	1.13
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/example/SaveRegistrationAction.java,v
1.12 2000/12/29 22:33:54 craigmcc Exp $
  - * $Revision: 1.12 $
  - * $Date: 2000/12/29 22:33:54 $
  + * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/example/SaveRegistrationAction.java,v
1.13 2001/01/07 04:37:05 craigmcc Exp $
  + * $Revision: 1.13 $
  + * $Date: 2001/01/07 04:37:05 $
    *
    * ====================================================================
    *
  @@ -89,7 +89,7 @@
    * registration is created, the user is also implicitly logged on.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.12 $ $Date: 2000/12/29 22:33:54 $
  + * @version $Revision: 1.13 $ $Date: 2001/01/07 04:37:05 $
    */
   
   public final class SaveRegistrationAction extends Action {
  @@ -153,11 +153,20 @@
   	    return (mapping.findForward("success"));
   	}
   
  +        // Validate the transactional control token
  +	ActionErrors errors = new ActionErrors();
  +        if (servlet.getDebug() >= 1) {
  +            servlet.log(" Checking transactional control token");
  +        }
  +        if (!isTokenValid(request))
  +            errors.add(ActionErrors.GLOBAL_ERROR,
  +                       new ActionError("error.transaction.token"));
  +        resetToken(request);
  +
   	// Validate the request parameters specified by the user
           if (servlet.getDebug() >= 1)
               servlet.log(" Performing extra validations");
   	String value = null;
  -	ActionErrors errors = new ActionErrors();
   	value = regform.getUsername();
   	if (("Create".equals(action)) &&
   	    (database.get(value) != null))
  @@ -178,6 +187,7 @@
   	// Report any errors we have discovered back to the original form
   	if (!errors.empty()) {
   	    saveErrors(request, errors);
  +            saveToken(request);
   	    return (new ActionForward(mapping.getInput()));
   	}
   
  
  
  
  1.15      +137 -17   jakarta-struts/src/share/org/apache/struts/action/Action.java
  
  Index: Action.java
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/Action.java,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- Action.java	2001/01/05 22:12:56	1.14
  +++ Action.java	2001/01/07 04:37:05	1.15
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/Action.java,v 1.14
2001/01/05 22:12:56 craigmcc Exp $
  - * $Revision: 1.14 $
  - * $Date: 2001/01/05 22:12:56 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/Action.java,v 1.15
2001/01/07 04:37:05 craigmcc Exp $
  + * $Revision: 1.15 $
  + * $Date: 2001/01/07 04:37:05 $
    *
    * ====================================================================
    *
  @@ -64,6 +64,8 @@
   
   
   import java.io.IOException;
  +import java.security.MessageDigest;
  +import java.security.NoSuchAlgorithmException;
   import java.util.Locale;
   import javax.servlet.ServletException;
   import javax.servlet.ServletRequest;
  @@ -71,7 +73,7 @@
   import javax.servlet.http.HttpServletRequest;
   import javax.servlet.http.HttpServletResponse;
   import javax.servlet.http.HttpSession;
  -import org.apache.struts.taglib.form.Constants;
  +import org.apache.struts.taglib.html.Constants;
   import org.apache.struts.util.ErrorMessages;
   import org.apache.struts.util.MessageResources;
   
  @@ -105,7 +107,7 @@
    * by this Action.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.14 $ $Date: 2001/01/05 22:12:56 $
  + * @version $Revision: 1.15 $ $Date: 2001/01/07 04:37:05 $
    */
   
   public class Action {
  @@ -208,7 +210,15 @@
           "org.apache.struts.action.mapping.multipartclass";
   
   
  +    /**
  +     * The session attributes key under which our transaction token is
  +     * stored, if it is used.
  +     */
  +    public static final String TRANSACTION_TOKEN_KEY =
  +        "org.apache.struts.action.TOKEN";
  +
   
  +
       // ----------------------------------------------------- Instance Variables
   
   
  @@ -379,34 +389,43 @@
   
   
       /**
  -     * Return the user's currently selected Locale.
  +     * Generate a new transaction token, to be used for enforcing a single
  +     * request for a particular transaction.
        *
        * @param request The request we are processing
        */
  -    protected Locale getLocale(HttpServletRequest request) {
  +    protected String generateToken(HttpServletRequest request) {
   
  -	HttpSession session = request.getSession();
  -	Locale locale = (Locale) session.getAttribute(LOCALE_KEY);
  -	if (locale == null)
  -	    locale = defaultLocale;
  -	return (locale);
  +        HttpSession session = request.getSession();
  +        try {
  +            byte id[] = session.getId().getBytes();
  +            byte now[] =
  +                new Long(System.currentTimeMillis()).toString().getBytes();
  +            MessageDigest md = MessageDigest.getInstance("MD5");
  +            md.update(id);
  +            md.update(now);
  +            return (toHex(md.digest()));
  +        } catch (IllegalStateException e) {
  +            return (null);
  +        } catch (NoSuchAlgorithmException e) {
  +            return (null);
  +        }
   
       }
   
   
       /**
  -     * Set the user's currently selected Locale.
  +     * Return the user's currently selected Locale.
        *
        * @param request The request we are processing
  -     * @param locale The user's selected Locale to be set, or null
  -     *  to select the server's default Locale
        */
  -    protected void setLocale(HttpServletRequest request, Locale locale) {
  +    protected Locale getLocale(HttpServletRequest request) {
   
   	HttpSession session = request.getSession();
  +	Locale locale = (Locale) session.getAttribute(LOCALE_KEY);
   	if (locale == null)
   	    locale = defaultLocale;
  -	session.setAttribute(LOCALE_KEY, locale);
  +	return (locale);
   
       }
   
  @@ -441,6 +460,59 @@
   
   
       /**
  +     * Return <code>true</code> if there is a transaction token stored in
  +     * the user's current session, and the value submitted as a request
  +     * parameter with this action matches it.  Returns <code>false</code>
  +     * under any of the following circumstances:
  +     * <ul>
  +     * <li>No session associated with this request</li>
  +     * <li>No transaction token saved in the session</li>
  +     * <li>No transaction token included as a request parameter</li>
  +     * <li>The included transaction token value does not match the
  +     *     transaction token in the user's session</li>
  +     * </ul>
  +     *
  +     * @param request The servlet request we are processing
  +     */
  +    protected boolean isTokenValid(HttpServletRequest request) {
  +
  +        // Retrieve the saved transaction token from our session
  +        HttpSession session = request.getSession(false);
  +        if (session == null)
  +            return (false);
  +        String saved = (String) session.getAttribute(TRANSACTION_TOKEN_KEY);
  +        if (saved == null)
  +            return (false);
  +
  +        // Retrieve the transaction token included in this request
  +        String token = (String) request.getParameter(Constants.TOKEN_KEY);
  +        if (token == null)
  +            return (false);
  +
  +        // Do the values match?
  +        return (saved.equals(token));
  +
  +    }
  +
  +
  +    /**
  +     * Reset the saved transaction token in the user's session.  This
  +     * indicates that transactional token checking will not be needed
  +     * on the next request that is submitted.
  +     *
  +     * @param request The servlet request we are processing
  +     */
  +    protected void resetToken(HttpServletRequest request) {
  +
  +        HttpSession session = request.getSession(false);
  +        if (session == null)
  +            return;
  +        session.removeAttribute(TRANSACTION_TOKEN_KEY);
  +
  +    }
  +
  +
  +    /**
        * Save the specified error messages keys into the appropriate request
        * attribute for use by the &lt;struts:errors&gt; tag, if any messages
        * are required.  Otherwise, ensure that the request attribute is not
  @@ -460,6 +532,54 @@
   
   	// Save the error messages we need
   	request.setAttribute(ERROR_KEY, errors);
  +
  +    }
  +
  +
  +    /**
  +     * Save a new transaction token in the user's current session, creating
  +     * a new session if necessary.
  +     *
  +     * @param request The servlet request we are processing
  +     */
  +    protected void saveToken(HttpServletRequest request) {
  +
  +        HttpSession session = request.getSession();
  +        String token = generateToken(request);
  +        if (token != null)
  +            session.setAttribute(TRANSACTION_TOKEN_KEY, token);
  +
  +    }
  +
  +
  +    /**
  +     * Set the user's currently selected Locale.
  +     *
  +     * @param request The request we are processing
  +     * @param locale The user's selected Locale to be set, or null
  +     *  to select the server's default Locale
  +     */
  +    protected void setLocale(HttpServletRequest request, Locale locale) {
  +
  +	HttpSession session = request.getSession();
  +	if (locale == null)
  +	    locale = defaultLocale;
  +	session.setAttribute(LOCALE_KEY, locale);
  +
  +    }
  +
  +
  +    /**
  +     * Convert a byte array to a String of hexadecimal digits and return it.
  +     *
  +     * @param buffer The byte array to be converted
  +     */
  +    protected String toHex(byte buffer[]) {
  +
  +        StringBuffer sb = new StringBuffer();
  +        for (int i = 0; i < buffer.length; i++)
  +            sb.append(Integer.toHexString((int) buffer[i] & 0xff));
  +        return (sb.toString());
   
       }
   
  
  
  
  1.53      +5 -5      jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java
  
  Index: ActionServlet.java
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v
  retrieving revision 1.52
  retrieving revision 1.53
  diff -u -r1.52 -r1.53
  --- ActionServlet.java	2001/01/06 22:14:34	1.52
  +++ ActionServlet.java	2001/01/07 04:37:06	1.53
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v
1.52 2001/01/06 22:14:34 craigmcc Exp $
  - * $Revision: 1.52 $
  - * $Date: 2001/01/06 22:14:34 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v
1.53 2001/01/07 04:37:06 craigmcc Exp $
  + * $Revision: 1.53 $
  + * $Date: 2001/01/07 04:37:06 $
    *
    * ====================================================================
    *
  @@ -82,7 +82,7 @@
   import javax.sql.DataSource;
   import org.apache.struts.digester.Digester;
   import org.apache.struts.digester.Rule;
  -import org.apache.struts.taglib.form.Constants;
  +import org.apache.struts.taglib.html.Constants;
   import org.apache.struts.util.BeanUtils;
   import org.apache.struts.util.FastHashMap;
   import org.apache.struts.util.GenericDataSource;
  @@ -227,7 +227,7 @@
    * </ul>
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.52 $ $Date: 2001/01/06 22:14:34 $
  + * @version $Revision: 1.53 $ $Date: 2001/01/07 04:37:06 $
    */
   
   public class ActionServlet
  
  
  
  1.2       +8 -2      jakarta-struts/src/share/org/apache/struts/taglib/html/Constants.java
  
  Index: Constants.java
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/taglib/html/Constants.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Constants.java	2001/01/06 21:50:39	1.1
  +++ Constants.java	2001/01/07 04:37:06	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/taglib/html/Constants.java,v
1.1 2001/01/06 21:50:39 mschachter Exp $
  - * $Revision: 1.1 $
  - * $Date: 2001/01/06 21:50:39 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/taglib/html/Constants.java,v
1.2 2001/01/07 04:37:06 craigmcc Exp $
  + * $Revision: 1.2 $
  + * $Date: 2001/01/07 04:37:06 $
    *
    * ====================================================================
    *
  @@ -98,6 +98,12 @@
        * The attribute key for the select tag itself.
        */
       public static final String SELECT_KEY = Package + ".SELECT";
  +
  +
  +    /**
  +     * The property under which a transaction token is reported.
  +     */
  +    public static final String TOKEN_KEY = Package + ".TOKEN";
   
   
   }
  
  
  
  1.2       +19 -4     jakarta-struts/src/share/org/apache/struts/taglib/html/FormTag.java
  
  Index: FormTag.java
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/taglib/html/FormTag.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- FormTag.java	2001/01/06 21:50:39	1.1
  +++ FormTag.java	2001/01/07 04:37:06	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/taglib/html/FormTag.java,v
1.1 2001/01/06 21:50:39 mschachter Exp $
  - * $Revision: 1.1 $
  - * $Date: 2001/01/06 21:50:39 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/taglib/html/FormTag.java,v
1.2 2001/01/07 04:37:06 craigmcc Exp $
  + * $Revision: 1.2 $
  + * $Date: 2001/01/07 04:37:06 $
    *
    * ====================================================================
    *
  @@ -65,6 +65,7 @@
   
   import java.io.IOException;
   import javax.servlet.http.HttpServletResponse;
  +import javax.servlet.http.HttpSession;
   import javax.servlet.jsp.JspException;
   import javax.servlet.jsp.JspWriter;
   import javax.servlet.jsp.PageContext;
  @@ -84,7 +85,7 @@
    * properties correspond to the various fields of the form.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.1 $ $Date: 2001/01/06 21:50:39 $
  + * @version $Revision: 1.2 $ $Date: 2001/01/07 04:37:06 $
    */
   
   public class FormTag extends TagSupport {
  @@ -539,6 +540,20 @@
   	    results.append("\"");
   	}
   	results.append(">");
  +
  +        // Add a transaction token (if present in our session)
  +        HttpSession session = pageContext.getSession();
  +        if (session != null) {
  +            String token =
  +                (String) session.getAttribute(Action.TRANSACTION_TOKEN_KEY);
  +            if (token != null) {
  +                results.append("<input type=\"hidden\" name=\"");
  +                results.append(Constants.TOKEN_KEY);
  +                results.append("\" value=\"");
  +                results.append(token);
  +                results.append("\">");
  +            }
  +        }
   
   	// Print this field to our output writer
   	JspWriter writer = pageContext.getOut();
  
  
  

Mime
View raw message