package hirondelle.web4j.security;

import hirondelle.web4j.action.Action;
import hirondelle.web4j.model.BadRequestException;
import hirondelle.web4j.model.ConvertParamError;
import hirondelle.web4j.model.ModelFromRequest;
import hirondelle.web4j.request.RequestParser;

/**
 Perform <a href="#HardValidation">hard validation</a> on each incoming request.
 
 <P>See {@link hirondelle.web4j.BuildImpl} for important information on how this item is configured. 
 {@link hirondelle.web4j.BuildImpl#forApplicationFirewall()} 
 returns the configured implementation of this interface.
 
 <P>The main intent of an application firewall is to defend against malicious attacks. As a side effect, 
 an application firewall will often detect obvious bugs during unit testing - usually unexpected request 
 parameters.  
 
 <P><span class="highlight">The <a href="http://www.owasp.org/">Open Web Application Security Project</a>
 is a superb resource for learning about web application security. Implementors of this interface are 
 highly recommended to read and use its guidelines.</span>
 
 <P><span class="highlight">WEB4J divides validation tasks into <em>hard validation</em> and 
 <em>soft validation</em>.</span> They are distinguished by : 
 <ul>
 <li>when they are applied
 <li>their behavior when they fail
 </ul>
 
 <P><b><a name="HardValidation">"Hard" Validation</a></b><br>
 Hard validation is applied earlier in processing. A failed hard validation 
 represents either a bug, or a malicious request (a "hack").
 When a hard validation fails, a curt and unpolished response can be sent. 
 Hard validations are performed by an <tt>ApplicationFirewall</tt>, ultimately called by the 
 {@link hirondelle.web4j.Controller}, as the first step in processing a request, 
 before any {@link Action} is executed. Items for hard validation might include :
 <ul>
 <li>overall request size
 <li>parameter names 
 <li>parameter values (<em>not business validations</em>, however - see below) 
 <li>HTTP headers
 <li>cookies
 </ul> 
 
 <P><span class="highlight">For request parameters, hard validation must include only those checks whose failure 
 would constitute a bug or a malicious request.</span> 
 
 <P><b><a name="SoftValidation">"Soft" Validation</b><br>
 Soft validation is applied later in processing.
 If a soft validation fails, resulting response pages use a polished presentation.
 They are applied to items that are input <em>directly</em> by the user, for example the content 
 of a <tt>text</tt> input control. Invalid values are handled as part of the normal operation of 
 the program. Soft validations are "problem domain" validations, and are usually implemented in a 
 Model Object constructor. 
 
 <P>To clarify, here are two examples, using the default implementation of
 {@link ApplicationFirewallImpl}.
 
 <P><b>Example 1</b> 
 <br>A <tt>select</tt> control named <tt>Spin</tt> submits two fixed values, <tt>UP</tt> and 
 <tt>DOWN</tt>. Under normal operation of the program, no other values are expected. In this 
 case, the submitted request parameter should undergo these checks :
 
 <P> <em>Hard validation</em> - must be one of the two values <tt>UP</tt> or <tt>DOWN</tt>.  
 This is implemented by simply defining, in the 
 {@link Action} that handles this parameter, a single field : 
<PRE>
public static final RequestParameter SPIN = RequestParameter.<a href="RequestParameter.html#withRegexCheck(java.lang.String,%20java.lang.String)">withRegexCheck</a>("Spin", "(UP|DOWN)");
</PRE>
 {@link ApplicationFirewallImpl} uses such fields to determine, for each {@link Action}, how to 
 do hard validation for request parameters. It checks permitted parameter names, and permitted parameter values
 versus a regular expression.
 
 <P> <em>Soft validation</em> - none. In this case, the hard validation checks the parameter value completely, 
 so there is no further validation to be performed.
 </ul> 

 <P><b>Example 2</b> 
 <br>A text input control named <tt>Age</tt> accepts any text as input. That text should correspond to 
 an integer in the range <tt>0..130</tt>. In this case, the validation is <em>shared</em> between 
 hard validation and soft validation :
 
 <P><em>Hard validation</em> - can only make a basic sanity check. For instance, a check that the parameter value 
 is not an unreasonable size - under 5K, for instance. This is meant only to detect obvious hacks. It has 
 nothing to do with business logic. That is, this size check does <em>not</em> correspond to the maximum number of
 characters expected (3), since failure of a hard validation produces a response which should <em>not</em> be seen by 
 the typical user during normal operation of the program. In this case, the field declared in the {@link Action}
 is : 
<PRE>
public static final RequestParameter AGE = RequestParameter.<a href="RequestParameter.html#withLengthCheck(java.lang.String)">withLengthCheck</a>("Age");
</PRE>
 (The actual maximum length is set in <tt>web.xml</tt>.)
 
 <P><em>Soft validation #1</em> - first, make sure the user input can be translated into an {@link Integer}. This is a very 
 common task, and is implemented by {@link RequestParser}, using its various <tt>toXXX</tt> methods (and, 
 at a higher lever, by {@link ModelFromRequest}). When user input cannot be parsed into 
 an {@link Integer}, then an error message is displayed to the user. See {@link ConvertParamError}.
 
 <P><em>Soft validation #2</em> - make sure the {@link Integer} returned by the previous validation is in the 
 range <tt>0..150</tt>. This is an example of a typical business validation. These are usually implemented 
 in the constructor of a Model Object. Again, if a problem is detected, then an error message 
 is displayed to to the user. 
 
 <P>{@link hirondelle.web4j.model.Check} and {@link hirondelle.web4j.model.Validator} are provided to help you   
 implement soft validations.
*/
public interface ApplicationFirewall {

  /**
   Perform <a href="#HardValidation">hard validation</a> on each HTTP request.
   
   <P>If a problem is detected, then a {@link BadRequestException} is thrown, indicating the
   standard HTTP status code, as defined in {@link javax.servlet.http.HttpServletRequest}. 
   (An error message may also be included, if desired.) 
   The response will then be sent immediately, without further processing, using   
   {@link javax.servlet.http.HttpServletResponse#sendError(int)}, or
   {@link javax.servlet.http.HttpServletResponse#sendError(int, java.lang.String)} if  
   {@link BadRequestException#getErrorMessage()} has content.
  
   @param aAction corresponding to this request. If the underlying request is unknown 
   to {@link RequestParser#getWebAction()}, then that method will throw a 
   {@link BadRequestException}, and this method will not be called.
   @param aRequestParser provides the raw underlying request, through 
   {@link RequestParser#getRequest()};
  */
  void doHardValidation(Action aAction, RequestParser aRequestParser) throws BadRequestException;

}
