You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cactus-dev@jakarta.apache.org by vm...@apache.org on 2004/02/27 10:10:59 UTC

cvs commit: jakarta-cactus/framework/src/java/share/org/apache/cactus/client/authentication FormAuthentication.java

vmassol     2004/02/27 01:10:59

  Modified:    documentation/docs/xdocs changes.xml
               framework/src/java/share/org/apache/cactus/client/authentication
                        FormAuthentication.java
  Log:
  - Added new <code>FormAuthentication.setExpectedAuthResponse(int)</code> that allows to set the expected HTTP response code for an authentication request which should be successful. If not specified, it defaults to <code>HttpURLConnection.HTTP_MOVED_TEMP</code>.
  - Added new <code>FormAuthentication.setExpectedPreAuthResponse(int)</code> that allows to set the expected HTTP response code for a request to a restricted resource without authenticated principal. If not specified, it defaults to <code>HttpURLConnection.HTTP_MOVED_TEMP</code>.
  - Added new <code>FormAuthentication.setSessionCookieName(String)</code> that allows to set the security cookie name to a name different than <code>JSESSIONID</code> (the default).
  - <code>FormAuthentication</code> no longer assumes "localhost" when adding cookies.
  
  Revision  Changes    Path
  1.163     +25 -0     jakarta-cactus/documentation/docs/xdocs/changes.xml
  
  Index: changes.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-cactus/documentation/docs/xdocs/changes.xml,v
  retrieving revision 1.162
  retrieving revision 1.163
  diff -u -r1.162 -r1.163
  --- changes.xml	25 Feb 2004 20:45:40 -0000	1.162
  +++ changes.xml	27 Feb 2004 09:10:59 -0000	1.163
  @@ -68,6 +68,31 @@
         </devs>
   
         <release version="1.6dev" date="in CVS">
  +        <action dev="VMA" type="add" due-to="Kazuhito Suguri" due-to-email="suguri.kazuhito@lab.ntt.co.jp">
  +          Added new 
  +          <code>FormAuthentication.setExpectedAuthResponse(int)</code>
  +          that allows to set the expected HTTP response code for an
  +          authentication request which should be successful. If not 
  +          specified, it defaults to 
  +          <code>HttpURLConnection.HTTP_MOVED_TEMP</code>.
  +        </action>
  +        <action dev="VMA" type="add" due-to="Kazuhito Suguri" due-to-email="suguri.kazuhito@lab.ntt.co.jp">
  +          Added new 
  +          <code>FormAuthentication.setExpectedPreAuthResponse(int)</code>
  +          that allows to set the expected HTTP response code for a request to 
  +          a restricted resource without authenticated principal. If not 
  +          specified, it defaults to 
  +          <code>HttpURLConnection.HTTP_MOVED_TEMP</code>.
  +        </action>
  +        <action dev="VMA" type="add" due-to="Kazuhito Suguri" due-to-email="suguri.kazuhito@lab.ntt.co.jp">
  +          Added new <code>FormAuthentication.setSessionCookieName(String)</code>
  +          that allows to set the security cookie name to a name different than
  +          <code>JSESSIONID</code> (the default).
  +        </action>
  +        <action dev="VMA" type="fix" fixes-bug="17933" due-to="Kazuhito Suguri" due-to-email="suguri.kazuhito@lab.ntt.co.jp">
  +          <code>FormAuthentication</code> no longer assumes "localhost" when 
  +          adding cookies.
  +        </action>
           <action dev="VMA" type="fix" due-to="Paul Green" due-to-email="Paul.Green@ons.gsi.gov.uk">
             Fixed bug in Cactus wrapper implementation of
             <code>request.getPathTranslated()</code> which was failing when there
  
  
  
  1.18      +207 -88   jakarta-cactus/framework/src/java/share/org/apache/cactus/client/authentication/FormAuthentication.java
  
  Index: FormAuthentication.java
  ===================================================================
  RCS file: /home/cvs/jakarta-cactus/framework/src/java/share/org/apache/cactus/client/authentication/FormAuthentication.java,v
  retrieving revision 1.17
  retrieving revision 1.18
  diff -u -r1.17 -r1.18
  --- FormAuthentication.java	14 Feb 2004 11:49:45 -0000	1.17
  +++ FormAuthentication.java	27 Feb 2004 09:10:59 -0000	1.18
  @@ -1,7 +1,7 @@
   /* 
    * ========================================================================
    * 
  - * Copyright 2001-2003 The Apache Software Foundation.
  + * Copyright 2001-2004 The Apache Software Foundation.
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
  @@ -23,6 +23,7 @@
   import java.net.MalformedURLException;
   import java.net.URL;
   
  +import org.apache.cactus.Cookie;
   import org.apache.cactus.WebRequest;
   import org.apache.cactus.client.connector.http.ConnectionHelper;
   import org.apache.cactus.client.connector.http.ConnectionHelperFactory;
  @@ -44,6 +45,7 @@
    * 
    * @author <a href="mailto:Jason.Robertson@acs-inc.com">Jason Robertson</a>
    * @author <a href="mailto:vmassol@apache.org">Vincent Massol</a>
  + * @author <a href="mailto:suguri.kazuhito@lab.ntt.co.jp">Kazuhito SUGURI</a>
    *
    * @since 1.5
    *
  @@ -58,21 +60,31 @@
           LogFactory.getLog(FormAuthentication.class);
   
       /**
  +     * The expected HTTP response code for the request to a restricted
  +     * resource without authenticated principal.
  +     */
  +    private int expectedPreAuthResponse = HttpURLConnection.HTTP_MOVED_TEMP;
  +
  +    /**
  +     * The expected HTTP response code when the authentication is succeeded.
  +     */
  +    private int expectedAuthResponse = HttpURLConnection.HTTP_MOVED_TEMP;
  +
  +    /**
        * The URL to use when attempting to log in, if for whatever reason 
        * the default URL is incorrect.
        */
  -    private URL securityCheckURL = null;
  +    private URL securityCheckURL;
   
       /**
  -     * We store the session cookie name because of case issues. We need
  -     * to be able to send exactly the same one as was sent back by the
  -     * server.
     */
  -    private String sessionIdCookieName = null;
  +     * The cookie name of the session.
  +     */
  +    private String sessionCookieName = "JSESSIONID";
   
       /**
  -     * We store the session id cookie so that this instance can
  -     * be reused for another test.
     */
  -    private String sessionId = null;
  +     * We store the session cookie.
  +     */
  +    private Cookie jsessionCookie;
   
       /**
        * {@link WebRequest} object that will be used to connect to the
  @@ -112,15 +124,15 @@
           Configuration theConfiguration)
       {
           // Only authenticate the first time this instance is used.
  -        if (this.sessionId == null)
  +        if (this.jsessionCookie == null)
           {
              authenticate(theRequest, theConfiguration);
           }
   
           // Sets the session id cookie for the next request.
  -        if (this.sessionId != null)
  +        if (this.jsessionCookie != null)
           {
  -            theRequest.addCookie(this.sessionIdCookieName, this.sessionId);
  +            theRequest.addCookie(this.jsessionCookie);
           }
       }
   
  @@ -142,7 +154,7 @@
        */
       public void setSecurityCheckURL(URL theUrl)
       {
  -       this.securityCheckURL = theUrl;
  +        this.securityCheckURL = theUrl;
       }
       
       /**
  @@ -180,104 +192,211 @@
           return securityCheckURL;
       }
   
  +
       /**
  -     * Authenticate the principal by calling the security URL.
  -     * 
  -     * @param theRequest the web request used to connect to the Redirector
     * @param theConfiguration the Cactus configuration
  -     */    
  -    public void authenticate(WebRequest theRequest, 
  -        Configuration theConfiguration)
  +     * Get the cookie name of the session.
  +     * @return the cookie name of the session
  +     */
  +    private String getSessionCookieName()
       {
  -        //Note: This method needs refactoring. It is too complex.
  -        
  -        try
  +        return this.sessionCookieName;
  +    }
  +
  +    /**
  +     * Set the cookie name of the session to theName.
  +     * If theName is null, the change request will be ignored.
  +     * The default is &quot;<code>JSESSIONID</code>&quot;.
  +     * @param theName the cookie name of the session
  +     */
  +    public void setSessionCookieName(String theName)
  +    {
  +        if (theName != null)
           {
  -            // Create a helper that will connect to a restricted resource.
  +            this.sessionCookieName = theName;
  +        }
  +    }
   
  -            String resource = ((WebConfiguration) theConfiguration).
  -                getRedirectorURL(theRequest);
  -    
  -            ConnectionHelper helper = 
  -                ConnectionHelperFactory.getConnectionHelper(resource, 
  -                theConfiguration);
  +    /**
  +     * Get the expected HTTP response code for a request to a restricted
  +     * resource without authenticated principal.
  +     * @return the expected HTTP response code value
  +     */
  +    private int getExpectedPreAuthResponse()
  +    {
  +        return this.expectedPreAuthResponse;
  +    }
   
  -            // Make the connection using a default web request.
  -            HttpURLConnection connection = helper.connect(
  -                new WebRequestImpl((WebConfiguration) theConfiguration), 
  -                theConfiguration);
  +    /**
  +     * Set the expected HTTP response code for a request to a restricted
  +     * resource without authenticated principal.
  +     * The default is HttpURLConnection.HTTP_MOVED_TEMP.
  +     * @param theExpectedCode the expected HTTP response code value
  +     */
  +    public void setExpectedPreAuthResponse(int theExpectedCode)
  +    {
  +        this.expectedPreAuthResponse = theExpectedCode;
  +    }
  +
  +    /**
  +     * Get the expected HTTP response code for an authentication request
  +     * which should be successful.
  +     * @return the expected HTTP response code
  +     */
  +    private int getExpectedAuthResponse()
  +    {
  +        return this.expectedAuthResponse;
  +    }
  +
  +    /**
  +     * Set the expected HTTP response code for an authentication request
  +     * which should be successful.
  +     * The default is HttpURLConnection.HTTP_MOVED_TEMP.
  +     * @param theExpectedCode the expected HTTP response code value
  +     */
  +    public void setExpectedAuthResponse(int theExpectedCode)
  +    {
  +        this.expectedAuthResponse = theExpectedCode;
  +    }
  +
  +    /**
  +     * Check if the actual response code is that of the expected.
  +     * @param theExpected the expected response code
  +     * @param theActual the actural response code
  +     * @exception Exception the actual response code is not that of the expected
  +     */
  +    private void checkResponseCodeEquals(int theExpected, int theActual)
  +        throws Exception
  +    {
  +        if (theActual != theExpected)
  +        {
  +            throw new Exception("Received a [" + theActual + "] response code"
  +                + " and was expecting a [" + theExpected + "]");
  +        }
  +    }
   
  -            // Clean any existing session ID.
  -            sessionId = null;
  -            
  -            // Check (possible multiple) cookies for a JSESSIONID.
  -            int i = 1;
  -            String key = connection.getHeaderFieldKey(i);
  -            while (key != null)
  +    /**
  +     * Get a cookie required to be set by set-cookie header field.
  +     * @param theConnection a {@link HttpURLConnection}
  +     * @param theTarget the target cookie name
  +     * @return the {@link Cookie}
  +     */
  +    private Cookie getCookie(HttpURLConnection theConnection, String theTarget)
  +    {
  +        // Check (possible multiple) cookies for a target.
  +        int i = 1;
  +        String key = theConnection.getHeaderFieldKey(i);
  +        while (key != null)
  +        {
  +            if (key.equalsIgnoreCase("set-cookie"))
               {
  -                if (key.equalsIgnoreCase("set-cookie"))
  +                // Cookie is in the form:
  +                // "NAME=VALUE; expires=DATE; path=PATH;
  +                //  domain=DOMAIN_NAME; secure"
  +                // The only thing we care about is finding a cookie with
  +                // the name "JSESSIONID" and caching the value.
  +                String cookiestr = theConnection.getHeaderField(i);
  +                String nameValue = cookiestr.substring(0, 
  +                    cookiestr.indexOf(";"));
  +                int equalsChar = nameValue.indexOf("=");
  +                String name = nameValue.substring(0, equalsChar);
  +                String value = nameValue.substring(equalsChar + 1);
  +                if (name.equalsIgnoreCase(theTarget))
                   {
  -                    // Cookie is in the form:
  -                    // "NAME=VALUE; expires=DATE; path=PATH;
  -                    //  domain=DOMAIN_NAME; secure"
  -                    // The only thing we care about is finding a cookie with 
  -                    // the name "JSESSIONID" and caching the value.
  -                    
  -                    String cookiestr = connection.getHeaderField(i);
  -                    String nameValue = cookiestr.substring(0, 
  -                        cookiestr.indexOf(";"));
  -                    int equalsChar = nameValue.indexOf("=");
  -                    String name = nameValue.substring(0, equalsChar);
  -
  -                    if (name.equalsIgnoreCase("JSESSIONID"))
  -                    {
  -                        // We must set a cookie with the exact same name as the
  -                        // one given to us, so to preserve any capitalization
  -                        // issues, cache the exact cookie name.
  -                        sessionIdCookieName = name;
  -                        sessionId = nameValue.substring(equalsChar + 1);
  -                        break;
  -                    }
  +                    return new Cookie(theConnection.getURL().getHost(),
  +                        name, value);
                   }
  -                key = connection.getHeaderFieldKey(++i);
               }
  +            key = theConnection.getHeaderFieldKey(++i);
  +        }
  +        return null;
  +    }
  +
  +    /**
  +     * Get login session cookie.
  +     * This is the first step to start login session:
  +     * <dl>
  +     *   <dt> C-&gt;S: </dt>
  +     *   <dd> try to connect to a restricted resource </dd>
  +     *   <dt> S-&gt;C: </dt>
  +     *   <dd> redirect or forward to the login page with set-cookie header </dd>
  +     * </ol>
  +     * @param theRequest a request to connect to a restricted resource
  +     * @param theConfiguration a <code>Configuration</code> value
  +     * @return the <code>Cookie</code>
  +     */
  +    private Cookie getSecureSessionIdCookie(WebRequest theRequest,
  +        Configuration theConfiguration)
  +    {
  +        HttpURLConnection connection;
  +        String resource = null;
  +
  +        try
  +        {
  +            // Create a helper that will connect to a restricted resource.
  +            WebConfiguration webConfig = (WebConfiguration) theConfiguration;
  +            resource = webConfig.getRedirectorURL(theRequest);
  +            ConnectionHelper helper =
  +                ConnectionHelperFactory.getConnectionHelper(resource,
  +                theConfiguration);
  +            WebRequest request =
  +                new WebRequestImpl((WebConfiguration) theConfiguration);
  +
  +            // Make the connection using a default web request.
  +            connection = helper.connect(request, theConfiguration);
  +            checkResponseCodeEquals(getExpectedPreAuthResponse(),
  +                connection.getResponseCode());
  +        }
  +        catch (Throwable e)
  +        {
  +            throw new ChainedRuntimeException(
  +                "Failed to connect to the secured redirector: " + resource, e);
  +        }
   
  +        return getCookie(connection, getSessionCookieName());
  +    }
  +
  +    /**
  +     * Authenticate the principal by calling the security URL.
  +     * 
  +     * @param theRequest the web request used to connect to the Redirector
  +     * @param theConfiguration the Cactus configuration
  +     */
  +    public void authenticate(WebRequest theRequest,
  +        Configuration theConfiguration)
  +    {
  +        this.jsessionCookie = getSecureSessionIdCookie(theRequest,
  +            theConfiguration);
  +    
  +        try
  +        {
               // Create a helper that will connect to the security check URL.
  -            helper = ConnectionHelperFactory.getConnectionHelper(
  -                getSecurityCheckURL(theConfiguration).toString(), 
  -                (WebConfiguration) theConfiguration);
  -                
  -            // Configure a web request with the JSESSIONID cookie, 
  -            // the username and the password.          
  -            WebRequest request = getSecurityRequest();
  +            ConnectionHelper helper =
  +                ConnectionHelperFactory.getConnectionHelper(
  +                getSecurityCheckURL(theConfiguration).toString(),
  +               (WebConfiguration) theConfiguration);
   
  -            // TODO: Change design so that we cannot get a ClassCastException
  +            // Configure a web request with the JSESSIONID cookie,
  +            // the username and the password.
  +            WebRequest request = getSecurityRequest();
               ((WebRequestImpl) request).setConfiguration(theConfiguration);
  -
  -            request.addCookie(sessionIdCookieName, sessionId);
  +            request.addCookie(this.jsessionCookie);
               request.addParameter("j_username", getName(), 
                   WebRequest.POST_METHOD);
               request.addParameter("j_password", getPassword(), 
                   WebRequest.POST_METHOD);
  -            
  +
               // Make the connection using the configured web request.
  -            connection = helper.connect(request, theConfiguration);
  +            HttpURLConnection connection = helper.connect(request,
  +                theConfiguration);
           
  -            // If we get back a response code of 302, it means we were 
  -            // redirected to the context root after successfully logging in.
  -            // If we receive anything else, we didn't log in correctly.
  -            if (connection.getResponseCode() != 302)
  -            {
  -                throw new ChainedRuntimeException("Unable to login, "
  -                    + "probably due to bad username/password. Received a ["
  -                    + connection.getResponseCode() + "] response code and "
  -                    + "was expecting a [302]");
  -            }
  +            checkResponseCodeEquals(getExpectedAuthResponse(),
  +                connection.getResponseCode());
           }
           catch (Throwable e)
           {
  -            throw new ChainedRuntimeException("Failed to authenticate "
  -                + "the principal", e);
  +            this.jsessionCookie = null;
  +            throw new ChainedRuntimeException(
  +                "Failed to authenticate the principal", e);
           }
       }
  -    
   }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: cactus-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: cactus-dev-help@jakarta.apache.org