How to integrate with request validation (strikeone)

The process of request validation is described in outline in the support article on security features. This article is aimed at developers who need to know a bit more of the nitty-gritty in order to use, or abuse, validation. it's assumed the reader has read the outline article - I'm not going to repeat anything that's already there.

Important code:
  • Foswiki::Validation
  • Foswiki::writeCompletePage

Overview of Validation

First, an overview of how validation works. The secret to integrating with validation is to understand each of these steps and make sure they are implemented in the right way for any validated requests you make.

Step 1: Getting the validation code into a Foswiki page

This is done in Foswiki::writeCompletePage. This function is called by all the standard scripts as the last step in the rendering pipeline. It:
  1. finds all forms, and edits them to add a hidden input containing the validation key,
  2. calculates the expected value of this key when it is combined with the secret cookie, and stores it in the CGI session,
  3. adds an onsubmit handler to each form, to invoke the JS that combines the key with the secret cookie,
  4. adds the strikeone.js module into the HEAD of the page,
  5. adds the secret cookie to the response.
Of course, if you write your own REST handler and don't return through a path that includes a call to writeCompletePage, you won't get these steps performed.

Note that forms that need a validation key must use method="post".

Step 2: Composing the validation key when the form is submitted

When the user submits the form, the onsubmit handler in strikeone.js is called. This combines the secret cookie with the validation_key parameter in the form to generate a new key, which it writes back into the validation_key parameter in the DOM. This step has to be done by Javascript, because it requires access to the cookie and the DOM to compose the key.

Step 3: Handling validation in the server

For standard system scripts such as save and upload, the Foswiki::UI package that implements the script will call Foswiki::UI::checkValidationKey. This function checks that the key is valid and if not, throws a Foswiki::ValidationException. This exception is handled in Foswiki::UI and results in a redirect to the confirmation screen. If the key is valid, and {Validation}{ExpireKeyOnUse} is true, it will be deleted from the session (expired).

Use Cases

Now that you have an overview of the validation process, here are some typical use cases.

Javascript wants to make lots of requests

Let's say you have written some Javascript that is going to be uploading a series of files (uploading files is one example of a validated request; this equally applies to, for example, saving a topic). There are a number of different approaches to this problem, and which one you use depends on your requirements (and your skill level).

Each upload has to be validated against the key issued when the original page was rendered. If you were to use the standard upload script repeatedly with the same computed key, then the key would be expired during the first request as described in Step 3 above, so that won't work. You need to either prevent the key from being invalidated on the server, or get a new key for each new request.

Approach 1: prevent the key from being invalidated

Unfortunately there is no simple way to prevent a key from being invalidated when you are using the standard scripts; if there were, it would be too easy for a footpad to spoof the mechanism and override validation. The generic scripts are actually pretty dangerous, because they support so much functionality. So it's much safer to require a custom upload mechanism that is tailored to your application, that checks but does not invalidate the key. This can easily be done as a REST handler - for an example, see Foswiki::Plugins::JHotDrawPlugin::_restUpload for an example.

Approach 2: get a new key from the server

It's possible to retrieve a fresh key from the server by making a request using the view script for a page that contains a form. A valid key can then be extracted from the DOM of that new page. My advice? Use apparoach 1.

If you have JQuery at hand this might be quite easy. For the ease of use, add an ID to the form on your landing page containing the form.
  // xhr is the xhr instance containing our requested landing page
  var retrievedKey = $( xhr.responseText ).find("#myValidationForm>input[name=validation_key]").attr("value");

  // distribute this new key to all input fields in the current DOM
  $("input[name=validation_key]").attr( "value", retrievedKey );

Of course this approach does not work with concurrent requests.

I want my REST handler to generate an HTML page with validated forms on it

As long as HTML is run though Foswiki::writeCompletePage, then it will get the validation code attached to any embedded forms, as described in Step 1. If your REST handler returns with a perl true result, then this result will be run through Foswiki::writeCompletePage, and validation will work as normal. This is the recommended approach.

I want my REST requests to be validated

Any REST handler can invoke validation. It is possible for a REST handler to simply call Foswiki::UI::checkValidationKey, but if you do this you are recommended to trap the Foswiki::ValidationException in the handler; otherwise the UI code will try to redirect to confirmation, which is not usually what you want in a REST handler!

Contributors: CrawfordCurrie, OliverKrueger

BasicForm edit

TopicClassification DeveloperDocumentation
TopicSummary Developer how-to integrate with request validation (strikeone)
InterestedParties
Topic revision: r7 - 06 Jun 2010 - 13:05:17 - CrawfordCurrie
 
The copyright of the content on this website is held by the contributing authors, except where stated elsewhere. see CopyrightStatement. Creative Commons LicenseGet Foswiki at sourceforge.net. Fast, secure and Free Open Source software downloads