2011/08/05 - Jakarta Cactus has been retired.

For more information, please explore the Attic.

Clover coverage report - Cactus 1.8dev for J2EE API 1.3
Coverage timestamp: Sun Mar 26 2006 18:50:18 BRT
file stats: LOC: 388   Methods: 14
NCLOC: 186   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
FormAuthentication.java 0% 0% 0% 0%
coverage
 1   
 /* 
 2   
  * ========================================================================
 3   
  * 
 4   
  * Copyright 2001-2004 The Apache Software Foundation.
 5   
  *
 6   
  * Licensed under the Apache License, Version 2.0 (the "License");
 7   
  * you may not use this file except in compliance with the License.
 8   
  * You may obtain a copy of the License at
 9   
  * 
 10   
  *   http://www.apache.org/licenses/LICENSE-2.0
 11   
  * 
 12   
  * Unless required by applicable law or agreed to in writing, software
 13   
  * distributed under the License is distributed on an "AS IS" BASIS,
 14   
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15   
  * See the License for the specific language governing permissions and
 16   
  * limitations under the License.
 17   
  * 
 18   
  * ========================================================================
 19   
  */
 20   
 package org.apache.cactus.client.authentication;
 21   
 
 22   
 import java.net.HttpURLConnection;
 23   
 import java.net.MalformedURLException;
 24   
 import java.net.URL;
 25   
 
 26   
 import org.apache.cactus.Cookie;
 27   
 import org.apache.cactus.WebRequest;
 28   
 import org.apache.cactus.internal.WebRequestImpl;
 29   
 import org.apache.cactus.internal.client.connector.http.HttpClientConnectionHelper;
 30   
 import org.apache.cactus.internal.configuration.Configuration;
 31   
 import org.apache.cactus.internal.configuration.WebConfiguration;
 32   
 import org.apache.cactus.util.ChainedRuntimeException;
 33   
 import org.apache.commons.httpclient.HttpMethod;
 34   
 import org.apache.commons.httpclient.HttpState;
 35   
 import org.apache.commons.logging.Log;
 36   
 import org.apache.commons.logging.LogFactory;
 37   
 
 38   
 /**
 39   
  * Form-based authentication implementation. An instance of this class
 40   
  * can be reused across several tests as it caches the session cookie.
 41   
  * Thus the first time it is used to authenticate the user, it calls
 42   
  * the security URL (which is by default the context URL prepended by
 43   
  * "j_security_check"), caches the returned session cookie and adds the
 44   
  * cookie for the next request. The second time it is called, it simply
 45   
  * addes the session cookie for the next request.
 46   
  * 
 47   
  * @since 1.5
 48   
  *
 49   
  * @version $Id: FormAuthentication.java 238991 2004-05-22 11:34:50Z vmassol $
 50   
  */
 51   
 public class FormAuthentication extends AbstractAuthentication
 52   
 {
 53   
     /**
 54   
      * The logger.
 55   
      */
 56   
     private static final Log LOGGER = 
 57   
         LogFactory.getLog(FormAuthentication.class);
 58   
 
 59   
     /**
 60   
      * The expected HTTP response status code when the authentication
 61   
      * is succeeded.
 62   
      */
 63   
     private int expectedAuthResponse = HttpURLConnection.HTTP_MOVED_TEMP;
 64   
 
 65   
     /**
 66   
      * The URL to use when attempting to log in, if for whatever reason 
 67   
      * the default URL is incorrect.
 68   
      */
 69   
     private URL securityCheckURL;
 70   
 
 71   
     /**
 72   
      * The cookie name of the session.
 73   
      */
 74   
     private String sessionCookieName = "JSESSIONID";
 75   
 
 76   
     /**
 77   
      * We store the session cookie.
 78   
      */
 79   
     private Cookie jsessionCookie;
 80   
 
 81   
     /**
 82   
      * {@link WebRequest} object that will be used to connect to the
 83   
      * security URL. 
 84   
      */
 85   
     private WebRequest securityRequest = new WebRequestImpl();
 86   
       
 87   
     /**
 88   
      * @param theName user name of the Credential
 89   
      * @param thePassword user password of the Credential
 90   
      */
 91  0
     public FormAuthentication(String theName, String thePassword)
 92   
     {
 93  0
         super(theName, thePassword);
 94   
     }
 95   
     
 96   
     /**
 97   
      * @see Authentication#configure
 98   
      */
 99  0
     public void configure(HttpState theState, HttpMethod theMethod,
 100   
         WebRequest theRequest, Configuration theConfiguration)
 101   
     {
 102   
         // Only authenticate the first time this instance is used.
 103  0
         if (this.jsessionCookie == null)
 104   
         {
 105  0
            authenticate(theRequest, theConfiguration);
 106   
         }
 107   
 
 108   
         // Sets the session id cookie for the next request.
 109  0
         if (this.jsessionCookie != null)
 110   
         {
 111  0
             theRequest.addCookie(this.jsessionCookie);
 112   
         }
 113   
     }
 114   
 
 115   
     /**
 116   
      * @return the {@link WebRequest} that will be used to connect to the
 117   
      * security URL. It can be used to add additional HTTP parameters such
 118   
      * as proprietary ones required by some containers.
 119   
      */
 120  0
     public WebRequest getSecurityRequest()
 121   
     {
 122  0
         return this.securityRequest;
 123   
     }
 124   
     
 125   
     /**
 126   
      * This sets the URL to use when attempting to log in. This method is used
 127   
      * if for whatever reason the default URL is incorrect.
 128   
      *
 129   
      * @param theUrl A URL to use to attempt to login.
 130   
      */
 131  0
     public void setSecurityCheckURL(URL theUrl)
 132   
     {
 133  0
         this.securityCheckURL = theUrl;
 134   
     }
 135   
     
 136   
     /**
 137   
      * This returns the URL to use when attempting to log in. By default, it's
 138   
      * the context URL defined in the Cactus configuration with  
 139   
      * "/j_security_check" appended. 
 140   
      *
 141   
      * @param theConfiguration the Cactus configuration
 142   
      * @return the URL that is being used to attempt to login.
 143   
      */
 144  0
     public URL getSecurityCheckURL(Configuration theConfiguration)
 145   
     {
 146  0
         if (this.securityCheckURL == null)
 147   
         {
 148   
             // Configure default
 149  0
             String stringUrl = 
 150   
                 ((WebConfiguration) theConfiguration).getContextURL()
 151   
                 + "/j_security_check";
 152   
 
 153  0
             try
 154   
             {
 155  0
                 this.securityCheckURL = new URL(stringUrl);
 156   
             }
 157   
             catch (MalformedURLException e)
 158   
             {
 159  0
                 throw new ChainedRuntimeException(
 160   
                     "Unable to create default Security Check URL [" 
 161   
                     + stringUrl + "]");
 162   
             }
 163   
         }
 164   
 
 165  0
         LOGGER.debug("Using security check URL [" + this.securityCheckURL
 166   
             + "]");
 167   
 
 168  0
         return securityCheckURL;
 169   
     }
 170   
 
 171   
 
 172   
     /**
 173   
      * Get the cookie name of the session.
 174   
      * @return the cookie name of the session
 175   
      */
 176  0
     private String getSessionCookieName()
 177   
     {
 178  0
         return this.sessionCookieName;
 179   
     }
 180   
 
 181   
     /**
 182   
      * Set the cookie name of the session to theName.
 183   
      * If theName is null, the change request will be ignored.
 184   
      * The default is &quot;<code>JSESSIONID</code>&quot;.
 185   
      * @param theName the cookie name of the session
 186   
      */
 187  0
     public void setSessionCookieName(String theName)
 188   
     {
 189  0
         if (theName != null)
 190   
         {
 191  0
             this.sessionCookieName = theName;
 192   
         }
 193   
     }
 194   
 
 195   
 
 196   
     /**
 197   
      * Get the expected HTTP response status code for an authentication request
 198   
      * which should be successful.
 199   
      * @return the expected HTTP response status code
 200   
      */
 201  0
     protected int getExpectedAuthResponse()
 202   
     {
 203  0
         return this.expectedAuthResponse;
 204   
     }
 205   
 
 206   
     /**
 207   
      * Set the expected HTTP response status code for an authentication request
 208   
      * which should be successful.
 209   
      * The default is HttpURLConnection.HTTP_MOVED_TEMP.
 210   
      * @param theExpectedCode the expected HTTP response status code value
 211   
      */
 212  0
     public void setExpectedAuthResponse(int theExpectedCode)
 213   
     {
 214  0
         this.expectedAuthResponse = theExpectedCode;
 215   
     }
 216   
 
 217   
 
 218   
     /**
 219   
      * Get a cookie required to be set by set-cookie header field.
 220   
      * @param theConnection a {@link HttpURLConnection}
 221   
      * @param theTarget the target cookie name
 222   
      * @return the {@link Cookie}
 223   
      */
 224  0
     private Cookie getCookie(HttpURLConnection theConnection, String theTarget)
 225   
     {
 226   
         // Check (possible multiple) cookies for a target.
 227  0
         int i = 1;
 228  0
         String key = theConnection.getHeaderFieldKey(i);
 229  0
         while (key != null)
 230   
         {
 231  0
             if (key.equalsIgnoreCase("set-cookie"))
 232   
             {
 233   
                 // Cookie is in the form:
 234   
                 // "NAME=VALUE; expires=DATE; path=PATH;
 235   
                 //  domain=DOMAIN_NAME; secure"
 236   
                 // The only thing we care about is finding a cookie with
 237   
                 // the name "JSESSIONID" and caching the value.
 238  0
                 String cookiestr = theConnection.getHeaderField(i);
 239  0
                 String nameValue = cookiestr.substring(0, 
 240   
                     cookiestr.indexOf(";"));
 241  0
                 int equalsChar = nameValue.indexOf("=");
 242  0
                 String name = nameValue.substring(0, equalsChar);
 243  0
                 String value = nameValue.substring(equalsChar + 1);
 244  0
                 if (name.equalsIgnoreCase(theTarget))
 245   
                 {
 246  0
                     return new Cookie(theConnection.getURL().getHost(),
 247   
                         name, value);
 248   
                 }
 249   
             }
 250  0
             key = theConnection.getHeaderFieldKey(++i);
 251   
         }
 252  0
         return null;
 253   
     }
 254   
 
 255   
 
 256   
     /**
 257   
      * Check if the pre-auth step can be considered as succeeded or not.
 258   
      * As default, the step considered as succeeded
 259   
      * if the response status code of <code>theConnection</code>
 260   
      * is less than 400.
 261   
      *
 262   
      * @param theConnection a <code>HttpURLConnection</code> value
 263   
      * @exception Exception if the pre-auth step should be considered as failed
 264   
      */
 265  0
     protected void checkPreAuthResponse(HttpURLConnection theConnection)
 266   
         throws Exception
 267   
     {
 268  0
         if (theConnection.getResponseCode() >= 400)
 269   
         {
 270  0
             throw new Exception("Received a status code ["
 271   
                 + theConnection.getResponseCode()
 272   
                 + "] and was expecting less than 400");
 273   
         }
 274   
     }
 275   
 
 276   
 
 277   
     /**
 278   
      * Get login session cookie.
 279   
      * This is the first step to start login session:
 280   
      * <dl>
 281   
      *   <dt> C-&gt;S: </dt>
 282   
      *   <dd> try to connect to a restricted resource </dd>
 283   
      *   <dt> S-&gt;C: </dt>
 284   
      *   <dd> redirect or forward to the login page with set-cookie header </dd>
 285   
      * </ol>
 286   
      * @param theRequest a request to connect to a restricted resource
 287   
      * @param theConfiguration a <code>Configuration</code> value
 288   
      * @return the <code>Cookie</code>
 289   
      */
 290  0
     private Cookie getSecureSessionIdCookie(WebRequest theRequest,
 291   
         Configuration theConfiguration)
 292   
     {
 293  0
         HttpURLConnection connection;
 294  0
         String resource = null;
 295   
 
 296  0
         try
 297   
         {
 298   
             // Create a helper that will connect to a restricted resource.
 299  0
             WebConfiguration webConfig = (WebConfiguration) theConfiguration;
 300  0
             resource = webConfig.getRedirectorURL(theRequest);
 301   
 
 302  0
             HttpClientConnectionHelper helper = 
 303   
                 new HttpClientConnectionHelper(resource);
 304   
 
 305  0
             WebRequest request =
 306   
                 new WebRequestImpl((WebConfiguration) theConfiguration);
 307   
 
 308   
             // Make the connection using a default web request.
 309  0
             connection = helper.connect(request, theConfiguration);
 310   
 
 311  0
             checkPreAuthResponse(connection);
 312   
         }
 313   
         catch (Throwable e)
 314   
         {
 315  0
             throw new ChainedRuntimeException(
 316   
                 "Failed to connect to the secured redirector: " + resource, e);
 317   
         }
 318   
 
 319  0
         return getCookie(connection, getSessionCookieName());
 320   
     }
 321   
 
 322   
 
 323   
     /**
 324   
      * Check if the auth step can be considered as succeeded or not.
 325   
      * As default, the step considered as succeeded
 326   
      * if the response status code of <code>theConnection</code>
 327   
      * equals <code>getExpectedAuthResponse()</code>.
 328   
      *
 329   
      * @param theConnection a <code>HttpURLConnection</code> value
 330   
      * @exception Exception if the auth step should be considered as failed
 331   
      */
 332  0
     protected void checkAuthResponse(HttpURLConnection theConnection)
 333   
         throws Exception
 334   
     {
 335  0
         if (theConnection.getResponseCode() != getExpectedAuthResponse())
 336   
         {
 337  0
             throw new Exception("Received a status code ["
 338   
                 + theConnection.getResponseCode()
 339   
                 + "] and was expecting a ["
 340   
                 + getExpectedAuthResponse() + "]");
 341   
         }
 342   
     }
 343   
 
 344   
 
 345   
     /**
 346   
      * Authenticate the principal by calling the security URL.
 347   
      * 
 348   
      * @param theRequest the web request used to connect to the Redirector
 349   
      * @param theConfiguration the Cactus configuration
 350   
      */
 351  0
     public void authenticate(WebRequest theRequest,
 352   
         Configuration theConfiguration)
 353   
     {
 354  0
         this.jsessionCookie = getSecureSessionIdCookie(theRequest,
 355   
             theConfiguration);
 356   
     
 357  0
         try
 358   
         {
 359   
             // Create a helper that will connect to the security check URL.
 360  0
             HttpClientConnectionHelper helper = 
 361   
                 new HttpClientConnectionHelper(
 362   
                     getSecurityCheckURL(theConfiguration).toString());
 363   
 
 364   
             // Configure a web request with the JSESSIONID cookie,
 365   
             // the username and the password.
 366  0
             WebRequest request = getSecurityRequest();
 367  0
             ((WebRequestImpl) request).setConfiguration(theConfiguration);
 368  0
             request.addCookie(this.jsessionCookie);
 369  0
             request.addParameter("j_username", getName(), 
 370   
                 WebRequest.POST_METHOD);
 371  0
             request.addParameter("j_password", getPassword(), 
 372   
                 WebRequest.POST_METHOD);
 373   
 
 374   
             // Make the connection using the configured web request.
 375  0
             HttpURLConnection connection = helper.connect(request,
 376   
                 theConfiguration);
 377   
 
 378  0
             checkAuthResponse(connection);        
 379   
         }
 380   
         catch (Throwable e)
 381   
         {
 382  0
             this.jsessionCookie = null;
 383  0
             throw new ChainedRuntimeException(
 384   
                 "Failed to authenticate the principal", e);
 385   
         }
 386   
     }
 387   
 }
 388