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

Save This Page
Home » cactus-1.8.0-src » org.apache.cactus.client.authentication » [javadoc | source]