001    package hirondelle.web4j.security;
002    
003    import hirondelle.web4j.action.Action;
004    import hirondelle.web4j.model.BadRequestException;
005    import hirondelle.web4j.model.ConvertParamError;
006    import hirondelle.web4j.model.ModelFromRequest;
007    import hirondelle.web4j.request.RequestParser;
008    
009    /**
010     Perform <a href="#HardValidation">hard validation</a> on each incoming request.
011     
012     <P>See {@link hirondelle.web4j.BuildImpl} for important information on how this item is configured. 
013     {@link hirondelle.web4j.BuildImpl#forApplicationFirewall()} 
014     returns the configured implementation of this interface.
015     
016     <P>The main intent of an application firewall is to defend against malicious attacks. As a side effect, 
017     an application firewall will often detect obvious bugs during unit testing - usually unexpected request 
018     parameters.  
019     
020     <P><span class="highlight">The <a href="http://www.owasp.org/">Open Web Application Security Project</a>
021     is a superb resource for learning about web application security. Implementors of this interface are 
022     highly recommended to read and use its guidelines.</span>
023     
024     <P><span class="highlight">WEB4J divides validation tasks into <em>hard validation</em> and 
025     <em>soft validation</em>.</span> They are distinguished by : 
026     <ul>
027     <li>when they are applied
028     <li>their behavior when they fail
029     </ul>
030     
031     <P><b><a name="HardValidation">"Hard" Validation</a></b><br>
032     Hard validation is applied earlier in processing. A failed hard validation 
033     represents either a bug, or a malicious request (a "hack").
034     When a hard validation fails, a curt and unpolished response can be sent. 
035     Hard validations are performed by an <tt>ApplicationFirewall</tt>, ultimately called by the 
036     {@link hirondelle.web4j.Controller}, as the first step in processing a request, 
037     before any {@link Action} is executed. Items for hard validation might include :
038     <ul>
039     <li>overall request size
040     <li>parameter names 
041     <li>parameter values (<em>not business validations</em>, however - see below) 
042     <li>HTTP headers
043     <li>cookies
044     </ul> 
045     
046     <P><span class="highlight">For request parameters, hard validation must include only those checks whose failure 
047     would constitute a bug or a malicious request.</span> 
048     
049     <P><b><a name="SoftValidation">"Soft" Validation</b><br>
050     Soft validation is applied later in processing.
051     If a soft validation fails, resulting response pages use a polished presentation.
052     They are applied to items that are input <em>directly</em> by the user, for example the content 
053     of a <tt>text</tt> input control. Invalid values are handled as part of the normal operation of 
054     the program. Soft validations are "problem domain" validations, and are usually implemented in a 
055     Model Object constructor. 
056     
057     <P>To clarify, here are two examples, using the default implementation of
058     {@link ApplicationFirewallImpl}.
059     
060     <P><b>Example 1</b> 
061     <br>A <tt>select</tt> control named <tt>Spin</tt> submits two fixed values, <tt>UP</tt> and 
062     <tt>DOWN</tt>. Under normal operation of the program, no other values are expected. In this 
063     case, the submitted request parameter should undergo these checks :
064     
065     <P> <em>Hard validation</em> - must be one of the two values <tt>UP</tt> or <tt>DOWN</tt>.  
066     This is implemented by simply defining, in the 
067     {@link Action} that handles this parameter, a single field : 
068    <PRE>
069    public static final RequestParameter SPIN = RequestParameter.<a href="RequestParameter.html#withRegexCheck(java.lang.String,%20java.lang.String)">withRegexCheck</a>("Spin", "(UP|DOWN)");
070    </PRE>
071     {@link ApplicationFirewallImpl} uses such fields to determine, for each {@link Action}, how to 
072     do hard validation for request parameters. It checks permitted parameter names, and permitted parameter values
073     versus a regular expression.
074     
075     <P> <em>Soft validation</em> - none. In this case, the hard validation checks the parameter value completely, 
076     so there is no further validation to be performed.
077     </ul> 
078    
079     <P><b>Example 2</b> 
080     <br>A text input control named <tt>Age</tt> accepts any text as input. That text should correspond to 
081     an integer in the range <tt>0..130</tt>. In this case, the validation is <em>shared</em> between 
082     hard validation and soft validation :
083     
084     <P><em>Hard validation</em> - can only make a basic sanity check. For instance, a check that the parameter value 
085     is not an unreasonable size - under 5K, for instance. This is meant only to detect obvious hacks. It has 
086     nothing to do with business logic. That is, this size check does <em>not</em> correspond to the maximum number of
087     characters expected (3), since failure of a hard validation produces a response which should <em>not</em> be seen by 
088     the typical user during normal operation of the program. In this case, the field declared in the {@link Action}
089     is : 
090    <PRE>
091    public static final RequestParameter AGE = RequestParameter.<a href="RequestParameter.html#withLengthCheck(java.lang.String)">withLengthCheck</a>("Age");
092    </PRE>
093     (The actual maximum length is set in <tt>web.xml</tt>.)
094     
095     <P><em>Soft validation #1</em> - first, make sure the user input can be translated into an {@link Integer}. This is a very 
096     common task, and is implemented by {@link RequestParser}, using its various <tt>toXXX</tt> methods (and, 
097     at a higher lever, by {@link ModelFromRequest}). When user input cannot be parsed into 
098     an {@link Integer}, then an error message is displayed to the user. See {@link ConvertParamError}.
099     
100     <P><em>Soft validation #2</em> - make sure the {@link Integer} returned by the previous validation is in the 
101     range <tt>0..150</tt>. This is an example of a typical business validation. These are usually implemented 
102     in the constructor of a Model Object. Again, if a problem is detected, then an error message 
103     is displayed to to the user. 
104     
105     <P>{@link hirondelle.web4j.model.Check} and {@link hirondelle.web4j.model.Validator} are provided to help you   
106     implement soft validations.
107    */
108    public interface ApplicationFirewall {
109    
110      /**
111       Perform <a href="#HardValidation">hard validation</a> on each HTTP request.
112       
113       <P>If a problem is detected, then a {@link BadRequestException} is thrown, indicating the
114       standard HTTP status code, as defined in {@link javax.servlet.http.HttpServletRequest}. 
115       (An error message may also be included, if desired.) 
116       The response will then be sent immediately, without further processing, using   
117       {@link javax.servlet.http.HttpServletResponse#sendError(int)}, or
118       {@link javax.servlet.http.HttpServletResponse#sendError(int, java.lang.String)} if  
119       {@link BadRequestException#getErrorMessage()} has content.
120      
121       @param aAction corresponding to this request. If the underlying request is unknown 
122       to {@link RequestParser#getWebAction()}, then that method will throw a 
123       {@link BadRequestException}, and this method will not be called.
124       @param aRequestParser provides the raw underlying request, through 
125       {@link RequestParser#getRequest()};
126      */
127      void doHardValidation(Action aAction, RequestParser aRequestParser) throws BadRequestException;
128    
129    }