commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jsde...@apache.org
Subject cvs commit: jakarta-commons/httpclient/src/test/org/apache/commons/httpclient TestAuthenticator.java
Date Thu, 18 Jul 2002 17:05:51 GMT
jsdever     2002/07/18 10:05:51

  Modified:    httpclient/src/java/org/apache/commons/httpclient
                        Authenticator.java HttpMethodBase.java
               httpclient/src/test/org/apache/commons/httpclient
                        TestAuthenticator.java
  Log:
  Apply patch for bug: http://nagoya.apache.org/bugzilla/show_bug.cgi?id=10532
  
  Unit Tests: test-nohost
  Sumbitted by: Jeff Dever
  
  Revision  Changes    Path
  1.18      +191 -155  jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/Authenticator.java
  
  Index: Authenticator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/Authenticator.java,v
  retrieving revision 1.17
  retrieving revision 1.18
  diff -u -r1.17 -r1.18
  --- Authenticator.java	16 Jul 2002 13:52:57 -0000	1.17
  +++ Authenticator.java	18 Jul 2002 17:05:51 -0000	1.18
  @@ -69,24 +69,49 @@
   import java.security.MessageDigest;
   
   /**
  - * <p>Utility methods for HTTP authorization and authentication.</p>
  - * <p>
  + * Utility methods for HTTP authorization and authentication.
  + * 
    * This class provides utility methods for generating
    * responses to HTTP www and proxy authentication challenges.
  - * </p>
  + * <p>
  + * Preemptive authentication can be turned on by using the property value of 
  + * #PREEMPTIVE_PROPERTY.  If left unspecified, it has the default value of
  + * #PREEMPTIVE_DEFAULT.  This configurable behaviour conforms to rcf2617:
  + * <blockquote>
  + *  A client SHOULD assume that all paths at or deeper than the depth of
  + *  the last symbolic element in the path field of the Request-URI also
  + *      are within the protection space specified by the Basic realm value of
  + *      the current challenge. A client MAY preemptively send the
  + *      corresponding Authorization header with requests for resources in
  + *      that space without receipt of another challenge from the server.
  + *      Similarly, when a client sends a request to a proxy, it may reuse a
  + *      userid and password in the Proxy-Authorization header field without
  + *      receiving another challenge from the proxy server.
  + * </blockquote>
  + *
    * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
    * @author Rodney Waldhoff
  - * @author <a href="mailto:jsdever@sympatico.ca">Jeff Dever</a>
  + * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
    * @version $Revision$ $Date$
    */
   class Authenticator {
  -    
  +
       /** <tt>org.apache.commons.httpclient.Authenticator</tt> log. */
       private static final Log log = LogSource.getInstance("org.apache.commons.httpclient.Authenticator");
   
       /** Base 64 encoder. */
       private static Base64 base64 = new Base64();
   
  +    /** 
  +     * The boolean property name to turn on preemptive authentication. 
  +     */
  +    static final String PREEMPTIVE_PROPERTY = "httpclient.authentication.preemptive";
  +
  +    /**
  +     * The default property value for #PREEMPTIVE_PROPERTY.
  +     */
  +    static final String PREEMPTIVE_DEFAULT = "false";
  +
       /**
        * The www authenticate challange header
        */
  @@ -107,138 +132,157 @@
        */
       public static final String PROXY_AUTH_RESP = "Proxy-Authorization";
   
  +
       /**
  -     * Add requisite authentication credentials to the given
  -     * {@link HttpMethod}, if possible.
  +     * Add requisite authentication credentials to the given <i>method</i>
  +     * in the given <i>state</i> if possible.
        *
  -     * @see HttpState#setCredentials(String, Credentials) HttpState.setCredentials
  -     * @see #authenticate(HttpMethod,HttpState,Header,String)
  -     *
  -     * @param method a {@link HttpMethod} which requires authentication
  -     * @param state a {@link HttpState} object providing {@link Credentials}
  +     * @param method the HttpMethod which requires authentication
  +     * @param state the HttpState object providing Credentials
        *
        * @throws HttpException when a parsing or other error occurs
  -     * @throws UnsupportedOperationException when the given challenge type is not supported
  -     * @return true if only if a response header was added
  +     * @throws UnsupportedOperationException when the challenge type is not supported
  +     * @return true if the Authenticate response header was added
  +     *
  +     * @see HttpState#setCredentials(String,Credentials)
  +     * @see #authenticate(HttpMethod,HttpState,Header,String)
        */
       static boolean authenticate(HttpMethod method, HttpState state) 
           throws HttpException, UnsupportedOperationException {
   
  -        log.debug("Authenticator.authenticate(HttpMethod, HttpState)");
  +            log.debug("enter Authenticator.authenticate(HttpMethod, HttpState)");
  +            Header challengeHeader = method.getResponseHeader(WWW_AUTH);
   
  -        Header challengeHeader = method.getResponseHeader(WWW_AUTH);
  -        if(null == challengeHeader) { return false; }
  -
  -        return authenticate(method, state, challengeHeader, WWW_AUTH_RESP);
  -    }
  +            return authenticate(method, state, challengeHeader, WWW_AUTH_RESP);
  +        }
   
       /**
  -     * Add requisite proxy authentication credentials to the given
  -     * {@link HttpMethod}, if possible.
  +     * Add requisite proxy authentication credentials to the given <i>method</i>
  +     * in the given <i>state</i> if possible.
        *
  -     * @see HttpState#setProxyCredentials(String, Credentials) HttpState.setProxyCredentials
  -     * @see #authenticate(HttpMethod,HttpState,Header,String)
  -     *
  -     * @param method a {@link HttpMethod} which requires authentication
  -     * @param state a {@link HttpState} object providing {@link Credentials}
  +     * @param method the HttpMethod which requires authentication
  +     * @param state the HttpState object providing Credentials
        *
        * @throws HttpException when a parsing or other error occurs
        * @throws UnsupportedOperationException when the given challenge type is not supported
  -     * @return true if only if a response header was added
  +     * @return true if the Authenticate response header was added
  +     *
  +     * @see HttpState#setProxyCredentials(String,Credentials)
  +     * @see #authenticate(HttpMethod,HttpState,Header,String)
        */
       static boolean authenticateProxy(HttpMethod method, HttpState state) 
           throws HttpException, UnsupportedOperationException {
   
  -        log.debug("Authenticator.authenticateProxy(HttpMethod, HttpState)");
  +            log.debug("enter Authenticator.authenticateProxy(HttpMethod, HttpState)");
  +            Header challengeHeader = method.getResponseHeader(PROXY_AUTH);
  +
  +            return authenticate(method, state, challengeHeader, PROXY_AUTH_RESP);
  +        }
   
  -        Header challengeHeader = method.getResponseHeader(PROXY_AUTH);
  -        if (null == challengeHeader) { return false; }
  -        return authenticate(method, state, challengeHeader, PROXY_AUTH_RESP);
  -    }
   
       /**
        * Add requisite authentication credentials to the given
  -     * {@link HttpMethod}, if possible, using the given response header
  +     * <i>method</i> using the given the <i>challengeHeader</i>.
        *
  -     * Currently only <b>Basic</b> authentication is supported.
  -     *
  -     * @param method the {@link HttpMethod http method} to add the authentication
  -     *      details to
  -     * @param challengeHeader the header the web server created to challenge the
  -     *      credentials
  -     * @param state a {@link HttpState} object providing {@link Credentials}
  +     * Currently <b>Basic</b> and <b>Digest</b> authentication
are supported.
  +     * If the challengeHeader is null, the default authentication credentials
  +     * will be sent.
  +     *
  +     * @param method the http method to add the authentication header to
  +     * @param challengeHeader the header the web server created to challenge the credentials
  +     * @param state the http state object providing {@link Credentials}
        * @param respHeader the response header to add (e.g. proxy or standard)
        *
        * @throws HttpException when an error occurs parsing the challenge
        * @throws UnsupportedOperationException when the given challenge type is not supported
  -     * @return true if only if a response header was added
  -     */
  -    private static boolean authenticate(HttpMethod method, HttpState state, Header challengeHeader,
String respHeader)
  -        throws HttpException, UnsupportedOperationException {
  +     * @return true if a response header was added
  +     *
  +     * @see #basic
  +     * @see #digest
  +     * @see HttpMethod#addRequestHeader
  +     */
  +    private static boolean authenticate(HttpMethod method, HttpState state, Header challengeHeader,
String respHeader) throws HttpException, UnsupportedOperationException {
  +        log.debug("enter Authenticator.authenticate(HttpMethod, HttpState, Header, String)");
  +
  +        //check the preemptive policy
  +        //TODO: this needs to be a service from some configuration class
  +        String preemptive_str = System.getProperties().getProperty(
  +                PREEMPTIVE_PROPERTY, PREEMPTIVE_DEFAULT);
  +        preemptive_str = preemptive_str.trim().toLowerCase();
  +
  +        if (! (preemptive_str.equals("true") || preemptive_str.equals("false")) ){ //property
problem
  +            log.warn("Configuration property " + PREEMPTIVE_PROPERTY + 
  +                    " must be either true or false.  Using default: " + PREEMPTIVE_DEFAULT);
  +            preemptive_str = PREEMPTIVE_DEFAULT;
  +        }
  +        boolean preemptive = ("true".equals(preemptive_str));
  +        log.debug("Using preemptive authorization: " + preemptive);
  +
  +
  +        //set the header preemptively if necessisary
  +        if (challengeHeader == null){
  +            if (preemptive){ 
  +                Header requestHeader = Authenticator.basic(null, state, respHeader);
  +                if(requestHeader != null) {  // default credentials exist, add the header
  +                    log.debug("Preemptively sending default basic credentials");
  +                    method.addRequestHeader(requestHeader);
  +                    return true;
  +                } else {  // no default credentials, don't add the header
  +                    log.debug("No default credentials to preemptively send");
  +                    return false;
  +                } 
  +            } else {
  +                return false;
  +            }
  +        }
  +        log.debug("challenge header is: " + challengeHeader);
   
  +
  +        // Get the challenge from the header
           String challenge = challengeHeader.getValue();
  -        if(null == challenge) { return false; }
   
  +
  +        // Parse the authentication scheme from the challenge
  +        // TODO: Use regular expression pattern matching to parse the challenge
           int space = challenge.indexOf(' ');
           if(space < 0) {
  -            throw new HttpException("Unable to parse authentication challenge \"" + challenge
+ "\", expected space");
  +            throw new HttpException("Authentication challenge \'" + challenge + "\'does
not contain an authentication scheme");
           }
           String authScheme = challenge.substring(0, space);
   
  -        if ("basic".equalsIgnoreCase(authScheme)) {
  -            // FIXME: Note that this won't work if there
  -            //        is more than one realm within
  -            //        the challenge
  -            // FIXME: We could probably make it a bit
  -            //        more flexible in parsing as well.
  -
  -            // parse the realm from the authentication challenge
  -            if(challenge.length() < space + 1) {
  -                throw new HttpException("Unable to parse authentication challenge \"" +
challenge + "\", expected realm");
  -            }
  -            String realmstr = challenge.substring(space+1,challenge.length());
  -            realmstr.trim();
  -            if(realmstr.length()<"realm=\"\"".length()) {
  -                throw new HttpException("Unable to parse authentication challenge \"" +
challenge + "\", expected realm");
  -            }
  -            String realm = realmstr.substring("realm=\"".length(),realmstr.length()-1);
  -            log.debug("Parsed realm \"" + realm + "\" from challenge \"" + challenge +
"\".");
  -           Header header = Authenticator.basic(realm, state, respHeader);
  -            if(null != header) {
  -                method.addRequestHeader(header);
  -                return true;
  -            } else {
  -                return false;
  -            }
  -        } else if ("digest".equalsIgnoreCase(authScheme)) {
  -            // FIXME: Note that this won't work if there
  -            //        is more than one realm within
  -            //        the challenge
  -            // FIXME: We could probably make it a bit
  -            //        more flexible in parsing as well.
  -
  -            // parse the realm from the authentication challenge
  -            if(challenge.length() < space + 1) {
  -                throw new HttpException("Unable to parse authentication challenge \"" +
challenge + "\", expected realm");
  -            }
  -            String realmstr = challenge.substring(space+1,challenge.length());
  -            realmstr.trim();
  -            if(realmstr.length()<"realm=\"\"".length()) {
  -                throw new HttpException("Unable to parse authentication challenge \"" +
challenge + "\", expected realm");
  -            }
  -            String realm = realmstr.substring("realm=\"".length(),realmstr.length()-1);
  -            log.debug("Parsed realm \"" + realm + "\" from challenge \"" + challenge +
"\".");
  -            Header header = Authenticator.digest(realm, method, state, respHeader);
  -            if(null != header) {
  -                method.addRequestHeader(header);
  -                return true;
  -            } else {
  -                return false;
  -            }
  -        } else {
  +        // Parse the realm from the authentication challenge
  +        // FIXME: Note that this won't work if there is more than one realm within the
challenge
  +        if (challenge.length() < space + 1) {
  +            throw new HttpException("Unable to parse authentication challenge \"" + challenge
+ "\", expected realm");
  +        }
  +        String realmstr = challenge.substring(space+1, challenge.length());
  +        realmstr.trim();
  +        if (realmstr.length() < "realm=\"\"".length()) {
  +            throw new HttpException("Unable to parse authentication challenge \"" + challenge
+ "\", expected realm");
  +        }
  +        String realm = realmstr.substring("realm=\"".length(), realmstr.length()-1);
  +        log.debug("Parsed realm \"" + realm + "\" from challenge \"" + challenge + "\".");
  +
  +        // Check for the authentication type, and add header if necessisary
  +        Header requestHeader = null;
  +        if ("basic".equalsIgnoreCase(authScheme)) {  // Basic authentication
  +            requestHeader = Authenticator.basic(realm, state, respHeader);
  +
  +        } else if ("digest".equalsIgnoreCase(authScheme)) {  // Digest authentication
  +            requestHeader = Authenticator.digest(realm, method, state, respHeader);
  +
  +        } else {  // unrecognized authentication
               throw new UnsupportedOperationException("Authentication type \"" + authScheme
+ "\" is not recognized.");
           }
  -    }
  +
  +        if(requestHeader != null) {  // add the header
  +            method.addRequestHeader(requestHeader);
  +            return true;
  +        } else {  // don't add the header
  +            return false;
  +        } 
  +    } 
  +
   
       /**
        * Create a Basic <tt>Authorization</tt> header for the given
  @@ -254,7 +298,8 @@
        * @throws HttpException when no matching credentials are available
        */
       static Header basic(String realm, HttpState state, String respHeader) throws HttpException
{
  -        log.debug("Authenticator.basic(String,HttpState)");
  +
  +        log.debug("enter Authenticator.basic(String, HttpState)");
           boolean proxy = PROXY_AUTH_RESP.equals(respHeader);
           UsernamePasswordCredentials cred = null;
           try {
  @@ -264,20 +309,9 @@
           } catch(ClassCastException e) {
               throw new HttpException("UsernamePasswordCredentials required for Basic authentication.");
           }
  +
           if(null == cred) {
  -            if(log.isInfoEnabled()) {
  -                log.info("No credentials found for realm \"" + realm + "\", attempting
to use default credentials.");
  -            }
  -            try {
  -                cred = (UsernamePasswordCredentials)( proxy ?
  -                        state.getProxyCredentials(null) :
  -                        state.getCredentials(null));
  -            } catch(ClassCastException e) {
  -                throw new HttpException("UsernamePasswordCredentials required for Basic
authentication.");
  -            }
  -        }
  -        if(null == cred) {
  -            throw new HttpException("No credentials available for the Basic authentication
realm \"" + realm + "\"/");
  +            throw new HttpException("No credentials available for the Basic authentication
realm \'" + realm + "\'");
           } else {
               return new Header(respHeader, Authenticator.basic(cred));
           }
  @@ -374,9 +408,9 @@
   
           MessageDigest md5Helper;
           try {
  -          md5Helper = MessageDigest.getInstance(digAlg);
  +            md5Helper = MessageDigest.getInstance(digAlg);
           } catch (Exception e) {
  -            System.out.println("ERROR! Unsupported algorithm in HTTP Digest authentication:
"+digAlg);
  +            log.error("ERROR! Unsupported algorithm in HTTP Digest authentication: "+digAlg);
               HttpException he = new HttpException("Unsupported algorithm in HTTP Digest
authentication: "+digAlg);
               throw he;
           }
  @@ -389,7 +423,7 @@
           String serverDigestValue;
           if (qop==null) serverDigestValue = md5a1 + ":" + nonce + ":" + md5a2;
           else serverDigestValue = md5a1 + ":" + nonce + ":" + nc + ":" +
  -                                   cnonce + ":" + qop + ":" + md5a2;
  +            cnonce + ":" + qop + ":" + md5a2;
           String serverDigest = encode(md5Helper.digest(serverDigestValue.getBytes()));
           return serverDigest;
       }
  @@ -406,9 +440,9 @@
           String digAlg = "MD5";
           MessageDigest md5Helper;
           try {
  -          md5Helper = MessageDigest.getInstance(digAlg);
  +            md5Helper = MessageDigest.getInstance(digAlg);
           } catch (Exception e) {
  -            System.out.println("ERROR! Unsupported algorithm in HTTP Digest authentication:
"+digAlg);
  +            log.error("ERROR! Unsupported algorithm in HTTP Digest authentication: "+digAlg);
               HttpException he = new HttpException("Unsupported algorithm in HTTP Digest
authentication: "+digAlg);
               throw he;
           }
  @@ -442,15 +476,15 @@
           String algorithm = "MD5";       //we only support MD5
   
           sb.append("username=\""+uname+"\"")
  -        .append(", realm=\""+realm+"\"")
  -        .append(", nonce=\""+nonce+"\"")
  -        .append(", uri=\""+uri+"\"")
  -        .append((qop==null?"":", qop=\""+qop+"\""))
  -        .append(", algorithm=\""+algorithm+"\"")
  -        .append((qop==null?"":", nc="+nc))
  -        .append((qop==null?"":", cnonce=\""+cnonce+"\""))
  -        .append(", response=\""+response+"\"")
  -        .append(", opaque=\""+opaque+"\"");
  +            .append(", realm=\""+realm+"\"")
  +            .append(", nonce=\""+nonce+"\"")
  +            .append(", uri=\""+uri+"\"")
  +            .append((qop==null?"":", qop=\""+qop+"\""))
  +            .append(", algorithm=\""+algorithm+"\"")
  +            .append((qop==null?"":", nc="+nc))
  +            .append((qop==null?"":", cnonce=\""+cnonce+"\""))
  +            .append(", response=\""+response+"\"")
  +            .append(", opaque=\""+opaque+"\"");
           return sb.toString();
       }
   
  @@ -467,15 +501,15 @@
        * <CODE>str</CODE>
        */
       private static String removeQuotes(String str) {
  -      if (str == null)
  -        return null;
  +        if (str == null)
  +            return null;
   
  -      int fqpos = str.indexOf("\"")+1;
  -      int lqpos = str.lastIndexOf("\"");
  -      if (fqpos > 0 && lqpos > fqpos)
  -        return str.substring(fqpos,lqpos);
  -      else
  -        return str;
  +        int fqpos = str.indexOf("\"")+1;
  +        int lqpos = str.lastIndexOf("\"");
  +        if (fqpos > 0 && lqpos > fqpos)
  +            return str.substring(fqpos,lqpos);
  +        else
  +            return str;
       }
   
       /**
  @@ -488,19 +522,19 @@
        */
       private static String encode( byte[] binaryData ) {
   
  -      if (binaryData.length != 16)
  -          return null;
  +        if (binaryData.length != 16)
  +            return null;
   
  -      char[] buffer = new char[32];
  +        char[] buffer = new char[32];
   
  -      for (int i=0; i<16; i++) {
  -          int low = (int) (binaryData[i] & 0x0f);
  -          int high = (int) ((binaryData[i] & 0xf0) >> 4);
  -          buffer[i*2] = hexadecimal[high];
  -          buffer[i*2 + 1] = hexadecimal[low];
  -      }
  +        for (int i=0; i<16; i++) {
  +            int low = (int) (binaryData[i] & 0x0f);
  +            int high = (int) ((binaryData[i] & 0xf0) >> 4);
  +            buffer[i*2] = hexadecimal[high];
  +            buffer[i*2 + 1] = hexadecimal[low];
  +        }
   
  -      return new String(buffer);
  +        return new String(buffer);
       }
   
       /**
  @@ -509,9 +543,8 @@
        *
        * @see #encode(byte[])
        */
  -    private static final char[] hexadecimal =
  -            {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  -             'a', 'b', 'c', 'd', 'e', 'f'};
  +    private static final char[] hexadecimal = 
  +    { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
   
       /**
        * Processes the www-authenticate HTTP header received from the server that
  @@ -549,9 +582,12 @@
        *    entry is placed (only if it has <CODE>"xxx=yyy"</CODE> format).
        */
       private static void processDigestToken(String token, Hashtable ht) {
  -      int eqpos = token.indexOf("=");
  +        int eqpos = token.indexOf("=");
   
  -      if (eqpos > 0 && eqpos < token.length()-1)
  -        ht.put(token.substring(0,eqpos).trim(),token.substring(eqpos+1).trim());
  +        if (eqpos > 0 && eqpos < token.length()-1)
  +            ht.put(token.substring(0,eqpos).trim(),token.substring(eqpos+1).trim());
       }
  +
  +
  +
   }
  
  
  
  1.32      +27 -11    jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java
  
  Index: HttpMethodBase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java,v
  retrieving revision 1.31
  retrieving revision 1.32
  diff -u -r1.31 -r1.32
  --- HttpMethodBase.java	13 Jul 2002 09:06:29 -0000	1.31
  +++ HttpMethodBase.java	18 Jul 2002 17:05:51 -0000	1.32
  @@ -112,7 +112,7 @@
    * @author Rodney Waldhoff
    * @author Sean C. Sullivan
    * @author <a href="mailto:dion@apache.org">dIon Gillard</a>
  - * @author <a href="mailto:jsdever@sympatico.ca">Jeff Dever</a>
  + * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
    * @version $Revision$ $Date$
    */
   public abstract class HttpMethodBase implements HttpMethod {
  @@ -233,10 +233,14 @@
       }
   
       /**
  -     * Add the specified request header, NOT overwriting any
  -     * previous value.
  +     * Add the specified request header.
  +     *
  +     * If a header of the same name already exists, the new value will be
  +     * appended onto the the existing value list. 
  +     * A <i>header</i> value of <code>null</code> will be ignored.

        * Note that header-name matching is case insensitive.
  -     * @param header the header
  +     *
  +     * @param header the header to add to the request
        */
       public void addRequestHeader(Header header) {
           // "It must be possible to combine the multiple header fields into
  @@ -244,6 +248,13 @@
           // semantics of the message, by appending each subsequent field-value
           // to the first, each separated by a comma."
           //   - HTTP/1.0 (4.3)
  +        log.debug("HttpMethodBase.addRequestHeader(Header)");
  +
  +        if (header == null){
  +	   log.debug("null header value ignored");
  +	}
  +
  +	// Preserve the original header if it exists
           Header orig = (Header)(requestHeaders.get(header.getName().toLowerCase()));
           if (null == orig) {
               orig = header;
  @@ -252,7 +263,7 @@
                              ", " +
                              (null == header.getValue() ? "" : header.getValue()));
           }
  -        requestHeaders.put(orig.getName().toLowerCase(),orig);
  +        requestHeaders.put(orig.getName().toLowerCase(), orig);
       }
   
       /**
  @@ -431,7 +442,7 @@
        */
       public int execute(HttpState state, HttpConnection connection) throws HttpException,
IOException {
           if (log.isDebugEnabled()) {
  -        	log.debug("HttpMethodBase.execute(HttpState,HttpConnection)");
  +        	log.debug("enter HttpMethodBase.execute(HttpState, HttpConnection)");
           }
   
           if (null == state) {
  @@ -450,6 +461,9 @@
               throw new HttpException("Not valid");
           }
   
  +        //pre-emptively add the authorization header, if required.
  +        Authenticator.authenticate(this, state);
  +
           Set visited = new HashSet();
           Set realms = new HashSet();
           int retryCount = 0;
  @@ -460,6 +474,7 @@
                   log.debug("HttpMethodBase.execute(): looping.");
               }
   
  +
               try{
                   if (!connection.isOpen()) {
                       if (log.isDebugEnabled()) {
  @@ -520,9 +535,10 @@
                           realms.add(pathAndCreds);
                       }
   
  +                    removeRequestHeader(Authenticator.WWW_AUTH_RESP); //remove preemptively
header
                       boolean authenticated = false;
                       try {
  -                        authenticated = Authenticator.authenticate(this,state);
  +                        authenticated = Authenticator.authenticate(this, state);
                       } catch (HttpException httpe) {
                           log.warn(httpe.getMessage());
                       } catch (UnsupportedOperationException uoe) {
  
  
  
  1.10      +43 -18    jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestAuthenticator.java
  
  Index: TestAuthenticator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestAuthenticator.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- TestAuthenticator.java	16 Jul 2002 13:52:57 -0000	1.9
  +++ TestAuthenticator.java	18 Jul 2002 17:05:51 -0000	1.10
  @@ -73,7 +73,7 @@
    * Unit tests for {@link Authenticator}.
    *
    * @author Rodney Waldhoff
  - * @author <a href="mailto:jsdever@sympatico.ca">Jeff Dever</a>
  + * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
    * @version $Id$
    */
   public class TestAuthenticator extends TestCase {
  @@ -158,7 +158,8 @@
       public void testBasicAuthenticationWithNoChallenge() throws Exception {
           HttpState state = new HttpState();
           HttpMethod method = new SimpleHttpMethod(null);
  -        assertTrue(false == Authenticator.authenticate(method,state));
  +
  +        assertEquals(false, Authenticator.authenticate(method,state));
       }
   
       public void testBasicAuthenticationWithNullHttpState() throws Exception {
  @@ -171,18 +172,6 @@
           }
       }
   
  -    public void testDigestAuthenticationScheme() throws Exception {
  -        HttpState state = new HttpState();
  -        state.setCredentials("realm1",new UsernamePasswordCredentials("username","password"));
  -        {
  -            HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate","Basic
realm=\"realm1\""));
  -            assertTrue(Authenticator.authenticate(method,state));
  -            assertTrue(null != method.getRequestHeader("Authorization"));
  -	    //TODO: test for correctness
  -        }
  - 
  -    }
  -
       public void testInvalidAuthenticationScheme() throws Exception {
           HttpState state = new HttpState();
           state.setCredentials(null,new UsernamePasswordCredentials("username","password"));
  @@ -246,6 +235,40 @@
           }
       }
   
  +    public void testPreemptiveAuthorizationDefault() throws Exception {
  +        HttpState state = new HttpState();
  +        HttpMethod method = new SimpleHttpMethod(null);
  +        state.setCredentials(null, new UsernamePasswordCredentials("username","password"));
  +
  +        assertTrue(! Authenticator.authenticate(method,state));
  +        assertTrue(null == method.getRequestHeader("Authorization"));
  +    }
  +
  +    public void testPreemptiveAuthorizationTrue() throws Exception {
  +        HttpState state = new HttpState();
  +        HttpMethod method = new SimpleHttpMethod(null);
  +        state.setCredentials(null, new UsernamePasswordCredentials("username","password"));
  +
  +        System.getProperties().setProperty(Authenticator.PREEMPTIVE_PROPERTY, "true");
  +        assertTrue(Authenticator.authenticate(method,state));
  +        assertTrue(null != method.getRequestHeader("Authorization"));
  +        String expected = "Basic " + new String(Base64.encode("username:password".getBytes()));
  +        assertEquals(expected, method.getRequestHeader("Authorization").getValue());
  +    }
  +
  +    public void testPreemptiveAuthorizationFalse() throws Exception {
  +        HttpState state = new HttpState();
  +        HttpMethod method = new SimpleHttpMethod(null);
  +
  +        System.getProperties().setProperty(Authenticator.PREEMPTIVE_PROPERTY, "false");
  +        state.setCredentials(null, new UsernamePasswordCredentials("username","password"));
  +        assertTrue(! Authenticator.authenticate(method,state));
  +        assertTrue(null == method.getRequestHeader("Authorization"));
  +    }
  +
  +
  +
  +
       // --------------------------------- Test Methods for Digest Authentication
   
       public void testDigestAuthenticationWithNoCreds() {
  @@ -359,4 +382,6 @@
           String digest = Authenticator.createDigest(cred.getUserName(),cred.getPassword(),
table);
           assertEquals(response, digest);
       }
  +
  +
   }
  
  
  

--
To unsubscribe, e-mail:   <mailto:commons-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:commons-dev-help@jakarta.apache.org>


Mime
View raw message