Clover coverage report - Cactus 1.5 for J2EE API 1.3
Coverage timestamp: Wed Feb 18 2004 09:09:13 EST
file stats: LOC: 320   Methods: 8
NCLOC: 132   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
FormAuthentication.java 0% 0% 0% 0%
coverage
 1   
 /*
 2   
  * ====================================================================
 3   
  *
 4   
  * The Apache Software License, Version 1.1
 5   
  *
 6   
  * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
 7   
  * reserved.
 8   
  *
 9   
  * Redistribution and use in source and binary forms, with or without
 10   
  * modification, are permitted provided that the following conditions
 11   
  * are met:
 12   
  *
 13   
  * 1. Redistributions of source code must retain the above copyright
 14   
  *    notice, this list of conditions and the following disclaimer.
 15   
  *
 16   
  * 2. Redistributions in binary form must reproduce the above copyright
 17   
  *    notice, this list of conditions and the following disclaimer in
 18   
  *    the documentation and/or other materials provided with the
 19   
  *    distribution.
 20   
  *
 21   
  * 3. The end-user documentation included with the redistribution, if
 22   
  *    any, must include the following acknowlegement:
 23   
  *       "This product includes software developed by the
 24   
  *        Apache Software Foundation (http://www.apache.org/)."
 25   
  *    Alternately, this acknowlegement may appear in the software itself,
 26   
  *    if and wherever such third-party acknowlegements normally appear.
 27   
  *
 28   
  * 4. The names "The Jakarta Project", "Cactus" and "Apache Software
 29   
  *    Foundation" must not be used to endorse or promote products
 30   
  *    derived from this software without prior written permission. For
 31   
  *    written permission, please contact apache@apache.org.
 32   
  *
 33   
  * 5. Products derived from this software may not be called "Apache"
 34   
  *    nor may "Apache" appear in their names without prior written
 35   
  *    permission of the Apache Group.
 36   
  *
 37   
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 38   
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 39   
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 40   
  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 41   
  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 42   
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 43   
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 44   
  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 45   
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 46   
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 47   
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 48   
  * SUCH DAMAGE.
 49   
  * ====================================================================
 50   
  *
 51   
  * This software consists of voluntary contributions made by many
 52   
  * individuals on behalf of the Apache Software Foundation.  For more
 53   
  * information on the Apache Software Foundation, please see
 54   
  * <http://www.apache.org/>.
 55   
  *
 56   
  */
 57   
 package org.apache.cactus.client.authentication;
 58   
 
 59   
 import java.net.HttpURLConnection;
 60   
 import java.net.MalformedURLException;
 61   
 import java.net.URL;
 62   
 
 63   
 import org.apache.cactus.WebRequest;
 64   
 import org.apache.cactus.client.connector.http.ConnectionHelper;
 65   
 import org.apache.cactus.client.connector.http.ConnectionHelperFactory;
 66   
 import org.apache.cactus.configuration.Configuration;
 67   
 import org.apache.cactus.configuration.WebConfiguration;
 68   
 import org.apache.cactus.util.ChainedRuntimeException;
 69   
 import org.apache.commons.logging.Log;
 70   
 import org.apache.commons.logging.LogFactory;
 71   
 
 72   
 /**
 73   
  * Form-based authentication implementation. An instance of this class
 74   
  * can be reused across several tests as it caches the session cookie.
 75   
  * Thus the first time it is used to authenticate the user, it calls
 76   
  * the security URL (which is by default the context URL prepended by
 77   
  * "j_security_check"), caches the returned session cookie and adds the
 78   
  * cookie for the next request. The second time it is called, it simply
 79   
  * addes the session cookie for the next request.
 80   
  * 
 81   
  * @author <a href="mailto:Jason.Robertson@acs-inc.com">Jason Robertson</a>
 82   
  * @author <a href="mailto:vmassol@apache.org">Vincent Massol</a>
 83   
  *
 84   
  * @since 1.5
 85   
  *
 86   
  * @version $Id: $
 87   
  */
 88   
 public class FormAuthentication extends AbstractAuthentication
 89   
 {
 90   
     /**
 91   
      * The logger.
 92   
      */
 93   
     private static final Log LOGGER = 
 94   
         LogFactory.getLog(FormAuthentication.class);
 95   
 
 96   
     /**
 97   
      * The URL to use when attempting to log in, if for whatever reason 
 98   
      * the default URL is incorrect.
 99   
      */
 100   
     private URL securityCheckURL = null;
 101   
 
 102   
     /**
 103   
      * We store the session cookie name because of case issues. We need
 104   
      * to be able to send exactly the same one as was sent back by the
 105   
      * server.
 106   
      */
 107   
     private String sessionIdCookieName = null;
 108   
 
 109   
     /**
 110   
      * We store the session id cookie so that this instance can
 111   
      * be reused for another test.
 112   
      */
 113   
     private String sessionId = null;
 114   
 
 115   
     /**
 116   
      * {@link WebRequest} object that will be used to connect to the
 117   
      * security URL. 
 118   
      */
 119   
     private WebRequest securityRequest = new WebRequest();
 120   
       
 121   
     /**
 122   
      * @param theName user name of the Credential
 123   
      * @param thePassword user password of the Credential
 124   
      */
 125  0
     public FormAuthentication(String theName, String thePassword)
 126   
     {
 127  0
         super(theName, thePassword);
 128   
     }
 129   
     
 130   
     /**
 131   
      * @see AbstractAuthentication#validateName(String)
 132   
      */
 133  0
     protected void validateName(String theName)
 134   
     {
 135   
         // Nothing to do here...
 136   
     }
 137   
     
 138   
     /**
 139   
      * @see AbstractAuthentication#validatePassword(String)
 140   
      */
 141  0
     protected void validatePassword(String thePassword)
 142   
     {
 143   
         // Nothing to do here...
 144   
     }
 145   
 
 146   
     /**
 147   
      * @see AbstractAuthentication#configure(WebRequest, Configuration)
 148   
      */
 149  0
     public void configure(WebRequest theRequest,
 150   
         Configuration theConfiguration)
 151   
     {
 152   
         // Only authenticate the first time this instance is used.
 153  0
         if (this.sessionId == null)
 154   
         {
 155  0
            authenticate(theRequest, theConfiguration);
 156   
         }
 157   
 
 158   
         // Sets the session id cookie for the next request.
 159  0
         if (this.sessionId != null)
 160   
         {
 161  0
             theRequest.addCookie(this.sessionIdCookieName, this.sessionId);
 162   
         }
 163   
     }
 164   
 
 165   
     /**
 166   
      * @return the {@link WebRequest} that will be used to connect to the
 167   
      * security URL. It can be used to add additional HTTP parameters such
 168   
      * as proprietary ones required by some containers.
 169   
      */
 170  0
     public WebRequest getSecurityRequest()
 171   
     {
 172  0
         return this.securityRequest;
 173   
     }
 174   
     
 175   
     /**
 176   
      * This sets the URL to use when attempting to log in. This method is used
 177   
      * if for whatever reason the default URL is incorrect.
 178   
      *
 179   
      * @param theUrl A URL to use to attempt to login.
 180   
      */
 181  0
     public void setSecurityCheckURL(URL theUrl)
 182   
     {
 183  0
        this.securityCheckURL = theUrl;
 184   
     }
 185   
     
 186   
     /**
 187   
      * This returns the URL to use when attempting to log in. By default, it's
 188   
      * the context URL defined in the Cactus configuration with  
 189   
      * "/j_security_check" appended. 
 190   
      *
 191   
      * @param theConfiguration the Cactus configuration
 192   
      * @return the URL that is being used to attempt to login.
 193   
      */
 194  0
     public URL getSecurityCheckURL(Configuration theConfiguration)
 195   
     {
 196  0
         if (this.securityCheckURL == null)
 197   
         {
 198   
             // Configure default
 199  0
             String stringUrl = 
 200   
                 ((WebConfiguration) theConfiguration).getContextURL()
 201   
                 + "/j_security_check";
 202   
 
 203  0
             try
 204   
             {
 205  0
                 this.securityCheckURL = new URL(stringUrl);
 206   
             }
 207   
             catch (MalformedURLException e)
 208   
             {
 209  0
                 throw new ChainedRuntimeException(
 210   
                     "Unable to create default Security Check URL [" 
 211   
                     + stringUrl + "]");
 212   
             }
 213   
         }
 214   
 
 215  0
         LOGGER.debug("Using security check URL [" + this.securityCheckURL
 216   
             + "]");
 217   
 
 218  0
         return securityCheckURL;
 219   
     }
 220   
 
 221   
     /**
 222   
      * Authenticate the principal by calling the security URL.
 223   
      * 
 224   
      * @param theRequest the web request used to connect to the Redirector
 225   
      * @param theConfiguration the Cactus configuration
 226   
      */    
 227  0
     public void authenticate(WebRequest theRequest, 
 228   
         Configuration theConfiguration)
 229   
     {
 230   
         //Note: This method needs refactoring. It is too complex.
 231   
         
 232  0
         try
 233   
         {
 234   
             // Create a helper that will connect to a restricted resource.
 235   
 
 236  0
             String resource = ((WebConfiguration) theConfiguration).
 237   
                 getRedirectorURL(theRequest);
 238   
     
 239  0
             ConnectionHelper helper = 
 240   
                 ConnectionHelperFactory.getConnectionHelper(resource, 
 241   
                 theConfiguration);
 242   
 
 243   
             // Make the connection using a default web request.
 244  0
             HttpURLConnection connection = helper.connect(
 245   
                 new WebRequest((WebConfiguration) theConfiguration), 
 246   
                 theConfiguration);
 247   
 
 248   
             // Clean any existing session ID.
 249  0
             sessionId = null;
 250   
             
 251   
             // Check (possible multiple) cookies for a JSESSIONID.
 252  0
             int i = 1;
 253  0
             String key = connection.getHeaderFieldKey(i);
 254  0
             while (key != null)
 255   
             {
 256  0
                 if (key.equalsIgnoreCase("set-cookie"))
 257   
                 {
 258   
                     // Cookie is in the form:
 259   
                     // "NAME=VALUE; expires=DATE; path=PATH;
 260   
                     //  domain=DOMAIN_NAME; secure"
 261   
                     // The only thing we care about is finding a cookie with 
 262   
                     // the name "JSESSIONID" and caching the value.
 263   
                     
 264  0
                     String cookiestr = connection.getHeaderField(i);
 265  0
                     String nameValue = cookiestr.substring(0, 
 266   
                         cookiestr.indexOf(";"));
 267  0
                     int equalsChar = nameValue.indexOf("=");
 268  0
                     String name = nameValue.substring(0, equalsChar);
 269   
 
 270  0
                     if (name.equalsIgnoreCase("JSESSIONID"))
 271   
                     {
 272   
                         // We must set a cookie with the exact same name as the
 273   
                         // one given to us, so to preserve any capitalization
 274   
                         // issues, cache the exact cookie name.
 275  0
                         sessionIdCookieName = name;
 276  0
                         sessionId = nameValue.substring(equalsChar + 1);
 277  0
                         break;
 278   
                     }
 279   
                 }
 280  0
                 key = connection.getHeaderFieldKey(++i);
 281   
             }
 282   
 
 283   
             // Create a helper that will connect to the security check URL.
 284  0
             helper = ConnectionHelperFactory.getConnectionHelper(
 285   
                 getSecurityCheckURL(theConfiguration).toString(), 
 286   
                 (WebConfiguration) theConfiguration);
 287   
                 
 288   
             // Configure a web request with the JSESSIONID cookie, 
 289   
             // the username and the password.          
 290  0
             WebRequest request = getSecurityRequest();
 291  0
             request.setConfiguration(theConfiguration);
 292  0
             request.addCookie(sessionIdCookieName, sessionId);
 293  0
             request.addParameter("j_username", getName(), 
 294   
                 WebRequest.POST_METHOD);
 295  0
             request.addParameter("j_password", getPassword(), 
 296   
                 WebRequest.POST_METHOD);
 297   
             
 298   
             // Make the connection using the configured web request.
 299  0
             connection = helper.connect(request, theConfiguration);
 300   
         
 301   
             // If we get back a response code of 302, it means we were 
 302   
             // redirected to the context root after successfully logging in.
 303   
             // If we receive anything else, we didn't log in correctly.
 304  0
             if (connection.getResponseCode() != 302)
 305   
             {
 306  0
                 throw new ChainedRuntimeException("Unable to login, "
 307   
                     + "probably due to bad username/password. Received a ["
 308   
                     + connection.getResponseCode() + "] response code and "
 309   
                     + "was expecting a [302]");
 310   
             }
 311   
         }
 312   
         catch (Throwable e)
 313   
         {
 314  0
             throw new ChainedRuntimeException("Failed to authenticate "
 315   
                 + "the principal", e);
 316   
         }
 317   
     }
 318   
     
 319   
 }
 320