Struts and Synchronizer Token

Alright, many might already know this, but it’s new to me so here goes.

I thought I had used most of the features of Struts, but I still find new features. Feature of the day: Synchronizer Token.

For those of you unfamiliar with the Synchronizer Token pattern, it ensures data can only be submitted once from a webform.

Call ActionServlet.saveToken(HttpRequest) before the display of the form to set the token, and then check ActionServlet.isTokenValid(HttpRequest) upon submit. If the token is valid you reset it with ActionServlet.resetToken(HttpRequest), which makes sure the next call to isTokenValid will fail.

I wish it was possible to set several tokens though. If a user opens more than one browser window and ends up having two forms that use the tokens open, the last form will overwrite the first forms token and thus make it fail when submitted. I know it’s a marginal case, and not one that is likely to happen very often, but I don’t think it would be a big problem to implement.

7 thoughts on “Struts and Synchronizer Token

  1. Craig McClanahan

    It is much more likely that such a feature would be implemented if someone (especially someone who believed it to be “not a big problem” to implement πŸ™‚ were to file an enhancement request in the bug tracking system, and then add a patch (as an attachment) that implements the requested feature.

    Reply
  2. Anders

    I’m completely aware of it, and I’ve been playing around with the thought of contributing. But right now I can’t really find the time to. I wish I could though. πŸ™‚

    Reply
  3. dan

    I have implemented a locking on the session as a whole so that only one request can be done per user. This loses some performance on read-only calls that could have been served, but I am willing to trade that in in exchange for maintenance and simplicity. The code I use is:


    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception
    {
    if (sessionLock.lock(request))
    {
    try
    {
    ActionForward af = super.execute(mapping, form, request, response);

    return af;
    }
    catch (Exception e)
    {
    throw e;
    }
    finally
    {
    sessionLock.unlock(request);
    }
    }

    // should be a nice page asking user to be patient
    return null;
    }

    Reply
  4. Anonymous

    As dan said, there is only one way to solve this.

    Restrict the user to work on one page at a time.
    When token is issued to the user, store it in Session, irrespective of whether last token was sent back by the user.

    In this way, if user open new window a new token is issued to him, and the last one becomes invalid. and so the first window form.

    hope this helps

    Reply
  5. Anonymous

    The technical part of this can be easily implemented. For each form, there are two random keys. 1 key is used as key, while another as value. They are stored as hidden field, and also in the session object. When user submit, the system sync the session, use the 1st key to look up for the 2nd. If found, then remove both from the session. If not, then this is a resubmit. The next time the form is requested, a new pair of keys is generated. The only problem with this is that memory may get leaked. A simple solution is to limit the number of keys per form. Another is to have it removed after certain wait time.

    Reply
  6. Amey

    Does ne 1 have a working code for synchronizer token? I am new to Struts.
    Your help is appreciated.
    I was pulling my hair off for this prob..
    Thanks
    Amey.

    Reply
  7. Anders Post author

    It’s not much more code you need than what’s in the blogentry. You just have to grok how to incorporate it into your own code. Read the docs people.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *