Index: java/org/apache/commons/httpclient/ConnectMethod.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ConnectMethod.java,v
retrieving revision 1.24
diff -u -r1.24 ConnectMethod.java
--- java/org/apache/commons/httpclient/ConnectMethod.java 11 Dec 2003 01:19:32 -0000 1.24
+++ java/org/apache/commons/httpclient/ConnectMethod.java 15 Dec 2003 11:12:25 -0000
@@ -113,24 +113,6 @@
/**
* This method does nothing. CONNECT request is not supposed
- * to contain Authorization request header.
- *
- * @param state current state of http requests
- * @param conn the connection to use for I/O
- *
- * @throws IOException when errors occur reading or writing to/from the
- * connection
- * @throws HttpException when a recoverable error occurs
- *
- * @see HttpMethodBase#addAuthorizationRequestHeader(HttpState, HttpConnection)
- */
- protected void addAuthorizationRequestHeader(HttpState state, HttpConnection conn)
- throws IOException, HttpException {
- // Do nothing. Not applicable to CONNECT method
- }
-
- /**
- * This method does nothing. CONNECT request is not supposed
* to contain Cookie request header.
*
* @param state current state of http requests
Index: java/org/apache/commons/httpclient/HttpClient.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpClient.java,v
retrieving revision 1.89
diff -u -r1.89 HttpClient.java
--- java/org/apache/commons/httpclient/HttpClient.java 10 Nov 2003 23:19:49 -0000 1.89
+++ java/org/apache/commons/httpclient/HttpClient.java 15 Dec 2003 11:12:26 -0000
@@ -1,5 +1,5 @@
/*
- * $Header: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpClient.java,v 1.89 2003/11/10 23:19:49 olegk Exp $
+ * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpClient.java,v 1.89 2003/11/10 23:19:49 olegk Exp $
* $Revision: 1.89 $
* $Date: 2003/11/10 23:19:49 $
*
@@ -67,6 +67,7 @@
import java.security.Security;
import java.security.Provider;
+import org.apache.commons.httpclient.auth.AuthScheme;
import org.apache.commons.httpclient.params.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
Index: java/org/apache/commons/httpclient/HttpMethodDirector.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodDirector.java,v
retrieving revision 1.11
diff -u -r1.11 HttpMethodDirector.java
--- java/org/apache/commons/httpclient/HttpMethodDirector.java 10 Dec 2003 21:04:13 -0000 1.11
+++ java/org/apache/commons/httpclient/HttpMethodDirector.java 15 Dec 2003 11:12:27 -0000
@@ -1,5 +1,5 @@
/*
- * $Header: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodDirector.java,v 1.11 2003/12/10 21:04:13 olegk Exp $
+ * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodDirector.java,v 1.11 2003/12/10 21:04:13 olegk Exp $
* $Revision: 1.11 $
* $Date: 2003/12/10 21:04:13 $
*
@@ -65,18 +65,14 @@
import java.io.IOException;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import org.apache.commons.httpclient.auth.AuthChallengeParser;
import org.apache.commons.httpclient.auth.AuthPolicy;
import org.apache.commons.httpclient.auth.AuthScheme;
import org.apache.commons.httpclient.auth.AuthenticationException;
-import org.apache.commons.httpclient.auth.CredentialsNotAvailableException;
-import org.apache.commons.httpclient.auth.HttpAuthenticator;
import org.apache.commons.httpclient.auth.MalformedChallengeException;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.params.HttpParams;
@@ -88,6 +84,18 @@
*/
class HttpMethodDirector {
+ /** The www authenticate challange header. */
+ public static final String WWW_AUTH_CHALLENGE = "WWW-Authenticate";
+
+ /** The www authenticate response header. */
+ public static final String WWW_AUTH_RESP = "Authorization";
+
+ /** The proxy authenticate challange header. */
+ public static final String PROXY_AUTH_CHALLENGE = "Proxy-Authenticate";
+
+ /** The proxy authenticate response header. */
+ public static final String PROXY_AUTH_RESP = "Proxy-Authorization";
+
/** Maximum number of redirects and authentications that will be followed */
private static final int MAX_FORWARDS = 100;
@@ -108,18 +116,27 @@
/** A flag to indicate if the connection should be released after the method is executed. */
private boolean releaseConnection = false;
- /** Realms that we tried to authenticate to */
- private Set realms = null;
-
- /** Proxy Realms that we tried to authenticate to */
- private Set proxyRealms = null;
+ private static final int AUTH_UNINITIATED = 0;
+ private static final int AUTH_PREEMPTIVE = 1;
+ private static final int AUTH_WWW_REQUIRED = 2;
+ private static final int AUTH_PROXY_REQUIRED = 3;
+ private static final int AUTH_NOT_REQUIRED = Integer.MAX_VALUE;
+ /** Actual state of authentication process */
+ private int authState = AUTH_UNINITIATED;
+
/** Actual authentication scheme */
private AuthScheme authScheme = null;
+ /** Whether preemtive authentication is attempted */
+ private boolean authPreemptive = false;
+
/** Actual proxy authentication scheme */
private AuthScheme proxyAuthScheme = null;
+ /** Whether preemtive proxy authentication is attempted */
+ private boolean proxyAuthPreemptive = false;
+
//TODO: to be parameterized
private static final List AUTH_PREFERENCES = new ArrayList(3);
static {
@@ -178,34 +195,41 @@
this.params.getConnectionManagerTimeout()
);
this.conn.setLocked(true);
+ if (this.params.isAuthenticationPreemptive()) {
- realms = new HashSet();
- proxyRealms = new HashSet();
-
- addPreemtiveAuthenticationHeaders(method);
+ LOG.debug("Preemptively sending default basic credentials");
+ this.authState = AUTH_PREEMPTIVE;
+ this.authScheme = AuthPolicy.getAuthScheme("basic");
+ this.authPreemptive = true;
+ if (this.conn.isProxied()) {
+ this.proxyAuthPreemptive = true;
+ this.proxyAuthScheme = AuthPolicy.getAuthScheme("basic");
+ }
+ }
}
+ authenticate(method);
executeWithRetry(method);
if (this.connectMethod != null) {
- //CONNECT method failed. Bow out.
fakeResponse(method);
break;
- } else if (isRedirectNeeded(method)) {
- //if the redirect is unsuccessful, return the statusCode
- //otherwise, drop through the switch and try again.
- if (!processRedirectResponse(method)) {
- break;
+ }
+
+ boolean retry = false;
+ if (isRedirectNeeded(method)) {
+ if (processRedirectResponse(method)) {
+ retry = true;
}
- } else if (isAuthenticationNeeded(method)) {
- //if the authentication is unsuccessful, return the statusCode
- //otherwise, drop through the switch and try again.
- if (!processAuthenticationResponse(method)) {
- break;
+ }
+ if (isAuthenticationNeeded(method)) {
+ if (processAuthenticationResponse(method)) {
+ retry = true;
}
} else {
- // nope, no retry needed, exit loop.
+ this.authState = AUTH_NOT_REQUIRED;
+ }
+ if (!retry) {
break;
}
-
// retry - close previous stream. Caution - this causes
// responseBodyConsumed to be called, which may also close the
// connection.
@@ -239,47 +263,93 @@
}
}
+
- private void applyDefaultCredentials(final HttpMethod method) {
+ private void authenticate(final HttpMethod method) {
try {
- if (HttpAuthenticator.authenticateDefault(method, this.conn, state)) {
- LOG.debug("Default basic credentials applied");
- }
+ authenticateProxy(method);
+ authenticateHost(method);
} catch (AuthenticationException e) {
- // Log error and move on
LOG.error(e.getMessage(), e);
}
}
- private void applyDefaultProxyCredentials(final HttpMethod method) {
- try {
- if (HttpAuthenticator.authenticateProxyDefault(method, this.conn, state)) {
- LOG.debug("Default basic proxy credentials applied");
+
+ private void authenticateHost(final HttpMethod method) throws AuthenticationException {
+ // Clean up existing authentication headers
+ method.removeRequestHeader(WWW_AUTH_RESP);
+ if ((this.authScheme != null)
+ && ((this.authState == AUTH_WWW_REQUIRED)
+ || (!this.authScheme.isConnectionBased())))
+ {
+ String host = conn.getVirtualHost();
+ if (host == null) {
+ host = conn.getHost();
+ }
+ String realm = this.authScheme.getRealm();
+ if (LOG.isDebugEnabled()) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("Authenticating with ");
+ if (realm == null) {
+ buffer.append("default");
+ } else {
+ buffer.append('\'');
+ buffer.append(realm);
+ buffer.append('\'');
+ }
+ buffer.append(" authentication realm at ");
+ buffer.append(host);
+ LOG.info(buffer.toString());
+ }
+ Credentials credentials = this.state.getCredentials(realm, host);
+ if (credentials != null) {
+ String authstring = this.authScheme.authenticate(credentials, method);
+ if (authstring != null) {
+ method.addRequestHeader(new Header(WWW_AUTH_RESP, authstring, true));
+ }
+ } else {
+ LOG.warn("Required credentials not available");
}
- } catch (AuthenticationException e) {
- // Log error and move on
- LOG.error(e.getMessage(), e);
}
}
-
- /**
- * Adds authentication headers if authenticationPreemtive has been set.
- *
- * @see HttpClientParams#isAuthenticationPreemptive()
- */
- private void addPreemtiveAuthenticationHeaders(final HttpMethod method) {
- //pre-emptively add the authorization header, if required.
- if (this.params.isAuthenticationPreemptive()) {
- LOG.debug("Preemptively sending default basic credentials");
- applyDefaultCredentials(method);
- if (this.conn.isProxied()) {
- applyDefaultProxyCredentials(method);
+ private void authenticateProxy(final HttpMethod method) throws AuthenticationException {
+ // Clean up existing authentication headers
+ method.removeRequestHeader(PROXY_AUTH_RESP);
+ if ((this.proxyAuthScheme != null)
+ && ((this.authState == AUTH_PROXY_REQUIRED)
+ || (!this.proxyAuthScheme.isConnectionBased())))
+ {
+ String host = conn.getProxyHost();
+ String realm = this.proxyAuthScheme.getRealm();
+ if (LOG.isDebugEnabled()) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("Authenticating with ");
+ if (realm == null) {
+ buffer.append("default");
+ } else {
+ buffer.append('\'');
+ buffer.append(realm);
+ buffer.append('\'');
+ }
+ buffer.append(" proxy authentication realm at ");
+ buffer.append(host);
+ LOG.info(buffer.toString());
+ }
+ Credentials credentials = this.state.getProxyCredentials(realm, host);
+ if (credentials != null) {
+ String authstring = this.proxyAuthScheme.authenticate(credentials, method);
+ if (authstring != null) {
+ method.addRequestHeader(new Header(PROXY_AUTH_RESP, authstring, true));
+ }
+ } else {
+ LOG.warn("Required credentials not available");
}
}
}
+
/**
* Executes a method with the current hostConfiguration.
*
@@ -379,17 +449,23 @@
this.connectMethod.getParams().setDefaults(this.params);
int code;
- if (this.params.isAuthenticationPreemptive()) {
- applyDefaultProxyCredentials(this.connectMethod);
- }
for (;;) {
+ try {
+ authenticateProxy(this.connectMethod);
+ } catch (AuthenticationException e) {
+ LOG.error(e.getMessage(), e);
+ }
executeWithRetry(this.connectMethod);
code = this.connectMethod.getStatusCode();
+ boolean retry = false;
if (code == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED) {
- if (!processAuthenticationResponse(this.connectMethod)) {
- break;
+ if (processAuthenticationResponse(this.connectMethod)) {
+ retry = true;
}
} else {
+ this.authState = AUTH_NOT_REQUIRED;
+ }
+ if (!retry) {
break;
}
if (this.connectMethod.getResponseBodyAsStream() != null) {
@@ -495,16 +571,6 @@
LOG.warn("Redirected location '" + location + "' is malformed");
return false;
}
-
- //invalidate the list of authentication attempts
- this.realms.clear();
- //remove exisitng authentication headers
- if ((this.proxyAuthScheme != null) && (this.proxyAuthScheme.isConnectionBased())) {
- method.removeRequestHeader(HttpAuthenticator.PROXY_AUTH);
- }
- method.removeRequestHeader(HttpAuthenticator.WWW_AUTH_RESP);
- //Invalidate present authentication scheme
- this.authScheme = null;
//update the current location with the redirect location.
//avoiding use of URL.getPath() and URL.getQuery() to keep
//jdk1.2 comliance.
@@ -517,14 +583,15 @@
+ "' to '" + redirectUri.getEscapedURI());
}
+ //And finally invalidate the actual authentication scheme
+ this.authScheme = null;
return true;
}
/**
* Processes a response that requires authentication
*
- * @param state the current state
- * @param conn The connection
+ * @param method the current {@link HttpMethod HTTP method}
*
* @return true if the authentication challenge can be responsed to,
* (that is, at least one of the requested authentication scheme is supported,
@@ -534,92 +601,149 @@
LOG.trace("enter HttpMethodBase.processAuthenticationResponse("
+ "HttpState, HttpConnection)");
- if ((this.proxyAuthScheme != null) && (this.proxyAuthScheme.isConnectionBased())) {
- method.removeRequestHeader(HttpAuthenticator.PROXY_AUTH);
- }
- if ((this.authScheme != null) && (this.authScheme.isConnectionBased())) {
- method.removeRequestHeader(HttpAuthenticator.WWW_AUTH);
- }
- boolean authenticated = false;
try {
switch (method.getStatusCode()) {
case HttpStatus.SC_UNAUTHORIZED:
- Map challenges = AuthChallengeParser.parseChallenges(
- method.getResponseHeaders(HttpAuthenticator.WWW_AUTH));
- if (challenges.isEmpty()) {
- return false;
- }
- if (this.authScheme != null) {
- processChallenge(this.authScheme, challenges);
- } else {
- this.authScheme = processChallenge(challenges);
- if (this.authScheme == null) {
- return false;
- }
- }
- String host = this.conn.getVirtualHost();
- if (host == null) {
- host = this.conn.getHost();
- }
- if (previousAttemptFailed(this.realms, host,
- this.authScheme)) {
- return false;
- }
- method.removeRequestHeader(HttpAuthenticator.WWW_AUTH_RESP);
- authenticated = HttpAuthenticator.authenticate(
- this.authScheme, method, this.conn, this.state);
- break;
+ return processWWWAuthChallenge(method);
case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED:
- Map proxyChallenges = AuthChallengeParser.parseChallenges(
- method.getResponseHeaders(HttpAuthenticator.PROXY_AUTH));
- if (proxyChallenges.isEmpty()) {
- return false;
- }
- if (this.proxyAuthScheme != null) {
- processChallenge(this.proxyAuthScheme, proxyChallenges);
- } else {
- this.proxyAuthScheme = processChallenge(proxyChallenges);
- if (this.proxyAuthScheme == null) {
- return false;
- }
- }
- if (previousAttemptFailed(this.proxyRealms, this.conn.getProxyHost(),
- this.proxyAuthScheme)) {
- return false;
- }
- method.removeRequestHeader(HttpAuthenticator.PROXY_AUTH_RESP);
- authenticated = HttpAuthenticator.authenticateProxy(
- proxyAuthScheme, method, this.conn, this.state);
- break;
+ return processProxyAuthChallenge(method);
+ default:
+ return false;
}
- } catch (MalformedChallengeException e) {
+ } catch (Exception e) {
if (LOG.isErrorEnabled()) {
LOG.error(e.getMessage(), e);
}
return false;
- } catch (CredentialsNotAvailableException e) {
- if (LOG.isWarnEnabled()) {
- LOG.warn(e.getMessage());
+ }
+ }
+
+ private boolean processWWWAuthChallenge(final HttpMethod method)
+ throws MalformedChallengeException, AuthenticationException
+ {
+ if (this.authPreemptive) {
+ this.authScheme = null;
+ this.authPreemptive = false;
+ }
+ Map challenges = AuthChallengeParser.parseChallenges(
+ method.getResponseHeaders(WWW_AUTH_CHALLENGE));
+ if (challenges.isEmpty()) {
+ return false;
+ }
+ if (this.authScheme != null) {
+ processChallenge(this.authScheme, challenges);
+ } else {
+ this.authScheme = processChallenge(challenges);
+ }
+ if (this.authScheme == null) {
+ return false;
+ }
+ if ((this.authState == AUTH_WWW_REQUIRED)
+ && (this.authScheme.isComplete())) {
+ // Already tried and failed
+ if (LOG.isInfoEnabled()) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("Attempt to authenticate with '");
+ buffer.append(this.authScheme.getRealm());
+ buffer.append("' authentication realm at ");
+ String host = this.conn.getVirtualHost();
+ if (host == null) {
+ host = this.conn.getHost();
+ }
+ buffer.append(host);
+ buffer.append(" failed");
+ LOG.info(buffer.toString());
}
return false;
- } catch (AuthenticationException e) {
- if (LOG.isErrorEnabled()) {
- LOG.error(e.getMessage(), e);
+ } else {
+ this.authState = AUTH_WWW_REQUIRED;
+
+ String host = conn.getVirtualHost();
+ if (host == null) {
+ host = conn.getHost();
+ }
+ String realm = this.authScheme.getRealm();
+ Credentials credentials = this.state.getCredentials(realm, host);
+ if (credentials == null) {
+ if (LOG.isInfoEnabled()) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("No credentials available for the ");
+ if (realm == null) {
+ buffer.append("default");
+ } else {
+ buffer.append('\'');
+ buffer.append(realm);
+ buffer.append('\'');
+ }
+ buffer.append(" authentication realm at ");
+ buffer.append(host);
+ }
+ return false;
+ } else {
+ return true;
}
+ }
+ }
+
+ private boolean processProxyAuthChallenge(final HttpMethod method)
+ throws MalformedChallengeException, AuthenticationException
+ {
+ if (this.proxyAuthPreemptive) {
+ this.proxyAuthScheme = null;
+ this.proxyAuthPreemptive = false;
+ }
+ Map proxyChallenges = AuthChallengeParser.parseChallenges(
+ method.getResponseHeaders(PROXY_AUTH_CHALLENGE));
+ if (proxyChallenges.isEmpty()) {
+ return false;
+ }
+ if (this.proxyAuthScheme != null) {
+ processChallenge(this.proxyAuthScheme, proxyChallenges);
+ } else {
+ this.proxyAuthScheme = processChallenge(proxyChallenges);
+ }
+ if (this.proxyAuthScheme == null) {
return false;
- }
- if (!authenticated) {
- // won't be able to authenticate to this challenge
- // without additional information
- LOG.debug("Credentials required to respond to authorization" +
- " challenge are not available");
- } else {
- LOG.debug("Credentials required to respond to authorization" +
- " challenge have been provided");
- // let's try it again, using the credentials
- }
- return authenticated;
- }
+ }
+ if ((this.authState == AUTH_PROXY_REQUIRED)
+ && (this.proxyAuthScheme.isComplete())) {
+ // Already tried and failed
+ if (LOG.isInfoEnabled()) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("Attempt to authenticate with '");
+ buffer.append(this.authScheme.getRealm());
+ buffer.append("' proxy authentication realm at ");
+ buffer.append(this.conn.getProxyHost());
+ buffer.append(" failed");
+ LOG.info(buffer.toString());
+ }
+ return false;
+ } else {
+ this.authState = AUTH_PROXY_REQUIRED;
+
+ String host = conn.getProxyHost();
+ String realm = this.proxyAuthScheme.getRealm();
+ Credentials credentials = this.state.getProxyCredentials(realm, host);
+ if (credentials == null) {
+ if (LOG.isInfoEnabled()) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("No credentials available for the ");
+ if (realm == null) {
+ buffer.append("default");
+ } else {
+ buffer.append('\'');
+ buffer.append(realm);
+ buffer.append('\'');
+ }
+ buffer.append(" proxy authentication realm at ");
+ buffer.append(host);
+ }
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
private void processChallenge(final AuthScheme authscheme, final Map challenges)
throws MalformedChallengeException, AuthenticationException
@@ -679,34 +803,6 @@
return authscheme;
}
-
- private boolean previousAttemptFailed(final Set realms, final String host, final AuthScheme authscheme) {
- // See if authentication against the given realm & host has
- // already been attempted
- StringBuffer buffer = new StringBuffer();
- buffer.append(host);
- buffer.append('#');
- buffer.append(authscheme.getID());
- String realm = buffer.toString();
-
- if (realms.contains(realm)) {
- // Already tried. Give up
- if (LOG.isInfoEnabled()) {
- buffer = new StringBuffer();
- buffer.append("Attempt to authenticate with '");
- buffer.append(authscheme.getRealm());
- buffer.append("' authentication realm at ");
- buffer.append(host);
- buffer.append(" failed");
- LOG.info(buffer.toString());
- }
- return true;
- } else {
- realms.add(realm);
- return false;
- }
-
- }
/**
* Tests if the {@link HttpMethod method} requires a redirect to another location.
*
@@ -748,7 +844,7 @@
if (method.getDoAuthentication()) { //process authentication response
return true;
} else { //let the client handle the authenticaiton
- LOG.info("Redirect requested but doAuthentication is "
+ LOG.info("Authentication requested but doAuthentication is "
+ "disabled");
return false;
}
@@ -785,4 +881,31 @@
return this.params;
}
+ /**
+ * Returns the authentication scheme used to authenticate with the
+ * target host.
+ *
+ * @return the authentication scheme used to authenticate with the
+ * target host. Null is returned if target host authentication
+ * was not required.
+ *
+ * @since 2.1
+ */
+ public AuthScheme getAuthScheme() {
+ return authScheme;
+ }
+
+ /**
+ * Returns the authentication scheme used to authenticate with the
+ * proxy host.
+ *
+ * @return the authentication scheme used to authenticate with the
+ * proxy host. Null is returned if proxy authentication was not
+ * required.
+ *
+ * @since 2.1
+ */
+ public AuthScheme getProxyAuthScheme() {
+ return proxyAuthScheme;
+ }
}
Index: java/org/apache/commons/httpclient/MultiThreadedHttpConnectionManager.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/MultiThreadedHttpConnectionManager.java,v
retrieving revision 1.29
diff -u -r1.29 MultiThreadedHttpConnectionManager.java
--- java/org/apache/commons/httpclient/MultiThreadedHttpConnectionManager.java 11 Dec 2003 01:19:32 -0000 1.29
+++ java/org/apache/commons/httpclient/MultiThreadedHttpConnectionManager.java 15 Dec 2003 11:12:29 -0000
@@ -1114,6 +1114,9 @@
}
}
+ /**
+ * @deprecated
+ */
public void print(String data)
throws IOException, IllegalStateException, HttpRecoverableException {
if (hasConnection()) {
@@ -1132,6 +1135,9 @@
}
}
+ /**
+ * @deprecated
+ */
public void printLine(String data)
throws IOException, IllegalStateException, HttpRecoverableException {
if (hasConnection()) {
Index: java/org/apache/commons/httpclient/auth/AuthScheme.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/AuthScheme.java,v
retrieving revision 1.6
diff -u -r1.6 AuthScheme.java
--- java/org/apache/commons/httpclient/auth/AuthScheme.java 11 Dec 2003 01:19:32 -0000 1.6
+++ java/org/apache/commons/httpclient/auth/AuthScheme.java 15 Dec 2003 11:12:29 -0000
@@ -152,6 +152,8 @@
*
* @return String a String identifying the authentication challenge. The
* returned value may be null.
+ *
+ * @deprecated no longer used
*/
String getID();
@@ -165,7 +167,18 @@
boolean isConnectionBased();
/**
- * @deprecated Use {@link #authenticate(Credentials, String, String, HttpMethodParams)}
+ * Authentication process may involve a series of challenge-response exchanges.
+ * This method tests if the authorization process has been completed, either
+ * successfully or unsuccessfully, that is, all the required authorization
+ * challenges have been processed in their entirety.
+ *
+ * @return true if the authentication process has been completed,
+ * false otherwise.
+ */
+ boolean isComplete();
+
+ /**
+ * @deprecated Use {@link #authenticate(Credentials, HttpMethod)}
*
* Produces an authorization string for the given set of {@link Credentials},
* method name and URI using the given authentication scheme in response to
Index: java/org/apache/commons/httpclient/auth/BasicScheme.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/BasicScheme.java,v
retrieving revision 1.9
diff -u -r1.9 BasicScheme.java
--- java/org/apache/commons/httpclient/auth/BasicScheme.java 11 Dec 2003 01:19:32 -0000 1.9
+++ java/org/apache/commons/httpclient/auth/BasicScheme.java 15 Dec 2003 11:12:30 -0000
@@ -92,12 +92,16 @@
/** Log object for this class. */
private static final Log LOG = LogFactory.getLog(BasicScheme.class);
+ /** Whether the basic authentication process is complete */
+ private boolean complete;
+
/**
* Default constructor for the basic authetication scheme.
*
*/
public BasicScheme() {
super();
+ this.complete = false;
}
/**
@@ -113,9 +117,9 @@
*/
public BasicScheme(final String challenge) throws MalformedChallengeException {
super(challenge);
+ this.complete = true;
}
-
/**
* Returns textual designation of the basic authentication scheme.
*
@@ -126,6 +130,31 @@
}
/**
+ * Processes the Basic challenge.
+ *
+ * @param the challenge string
+ *
+ * @throws MalformedChallengeException is thrown if the authentication challenge
+ * is malformed
+ */
+ public void processChallenge(String challenge)
+ throws MalformedChallengeException
+ {
+ super.processChallenge(challenge);
+ this.complete = true;
+ }
+
+ /**
+ * Tests if the Basic authentication process has been completed.
+ *
+ * @return true if Basic authorization has been processed,
+ * false otherwise.
+ */
+ public boolean isComplete() {
+ return this.complete;
+ }
+
+ /**
* Produces basic authorization string for the given set of
* {@link Credentials}.
*
@@ -138,6 +167,8 @@
* be generated due to an authentication failure
*
* @return a basic authorization string
+ *
+ * @deprecated Use {@link #authenticate(Credentials, HttpMethod)}
*/
public String authenticate(Credentials credentials, String method, String uri)
throws AuthenticationException {
@@ -235,5 +266,4 @@
return "Basic " + HttpConstants.getAsciiString(
Base64.encode(EncodingUtil.getBytes(buffer.toString(), charset)));
}
-
}
Index: java/org/apache/commons/httpclient/auth/DigestScheme.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/DigestScheme.java,v
retrieving revision 1.13
diff -u -r1.13 DigestScheme.java
--- java/org/apache/commons/httpclient/auth/DigestScheme.java 11 Dec 2003 01:19:32 -0000 1.13
+++ java/org/apache/commons/httpclient/auth/DigestScheme.java 15 Dec 2003 11:12:30 -0000
@@ -120,6 +120,9 @@
'e', 'f'
};
+ /** Whether the digest authentication process is complete */
+ private boolean complete;
+
//TODO: supply a real nonce-count, currently a server will interprete a repeated request as a replay
private static final String NC = "00000001"; //nonce-count is always 1
private static final int QOP_MISSING = 0;
@@ -135,12 +138,15 @@
*/
public DigestScheme() {
super();
+ this.complete = false;
}
/**
* Gets an ID based upon the realm and the nonce value. This ensures that requests
* to the same realm with different nonce values will succeed. This differentiation
* allows servers to request re-authentication using a fresh nonce value.
+ *
+ * @deprecated no longer used
*/
public String getID() {
@@ -167,35 +173,7 @@
public DigestScheme(final String challenge)
throws MalformedChallengeException {
super(challenge);
-
- if (getParameter("nonce") == null) {
- throw new MalformedChallengeException("missing nonce in challange");
- }
-
- boolean unsupportedQop = false;
- // qop parsing
- String qop = getParameter("qop");
- if (qop != null) {
- StringTokenizer tok = new StringTokenizer(qop,",");
- while (tok.hasMoreTokens()) {
- String variant = tok.nextToken().trim();
- if (variant.equals("auth")) {
- qopVariant = QOP_AUTH;
- break; //that's our favourite, because auth-int is unsupported
- } else if (variant.equals("auth-int")) {
- qopVariant = QOP_AUTH_INT;
- } else {
- unsupportedQop = true;
- LOG.warn("Unsupported qop detected: "+ variant);
- }
- }
- }
-
- if (unsupportedQop && (qopVariant == QOP_MISSING)) {
- throw new MalformedChallengeException("None of the qop methods is supported");
- }
-
- cnonce = createCnonce();
+ this.complete = true;
}
/**
@@ -238,8 +216,23 @@
}
cnonce = createCnonce();
+ this.complete = true;
}
+ /**
+ * Tests if the Digest authentication process has been completed.
+ *
+ * @return true if Digest authorization has been processed,
+ * false otherwise.
+ */
+ public boolean isComplete() {
+ String s = getParameter("stale");
+ if ("true".equalsIgnoreCase(s)) {
+ return false;
+ } else {
+ return this.complete;
+ }
+ }
/**
* Returns textual designation of the digest authentication scheme.
@@ -276,6 +269,8 @@
*
* @see org.apache.commons.httpclient.HttpMethod#getName()
* @see org.apache.commons.httpclient.HttpMethod#getPath()
+ *
+ * @deprecated Use {@link #authenticate(Credentials, HttpMethod)}
*/
public String authenticate(Credentials credentials, String method, String uri)
throws AuthenticationException {
Index: java/org/apache/commons/httpclient/auth/HttpAuthenticator.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/HttpAuthenticator.java,v
retrieving revision 1.15
diff -u -r1.15 HttpAuthenticator.java
--- java/org/apache/commons/httpclient/auth/HttpAuthenticator.java 11 Dec 2003 01:19:32 -0000 1.15
+++ java/org/apache/commons/httpclient/auth/HttpAuthenticator.java 15 Dec 2003 11:12:31 -0000
@@ -100,6 +100,8 @@
* @author Adrian Sutton
* @author Mike Bowler
* @author Oleg Kalnichevski
+ *
+ * @deprecated no longer used
*/
public final class HttpAuthenticator {
@@ -238,6 +240,8 @@
* @throws AuthenticationException when a parsing or other error occurs
*
* @see HttpState#setCredentials(String,String,Credentials)
+ *
+ * @deprecated use AuthScheme
*/
public static boolean authenticateDefault(
HttpMethod method,
@@ -269,6 +273,8 @@
* @throws AuthenticationException when a parsing or other error occurs
* @see HttpState#setCredentials(String,String,Credentials)
+ *
+ * @deprecated use AuthScheme
*/
public static boolean authenticateProxyDefault(
HttpMethod method,
@@ -310,7 +316,7 @@
String realm = authscheme.getRealm();
if (LOG.isDebugEnabled()) {
StringBuffer buffer = new StringBuffer();
- buffer.append("Authenticating with the ");
+ buffer.append("Using credentials for ");
if (realm == null) {
buffer.append("default");
} else {
@@ -326,9 +332,18 @@
? state.getProxyCredentials(realm, host)
: state.getCredentials(realm, host);
if (credentials == null) {
- throw new CredentialsNotAvailableException(
- "No credentials available for the '" + realm
- + "' authentication realm at " + host);
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("No credentials available for the ");
+ if (realm == null) {
+ buffer.append("default");
+ } else {
+ buffer.append('\'');
+ buffer.append(realm);
+ buffer.append('\'');
+ }
+ buffer.append(" authentication realm at ");
+ buffer.append(host);
+ throw new CredentialsNotAvailableException(buffer.toString());
}
String auth = authscheme.authenticate(credentials, method);
if (auth != null) {
@@ -360,6 +375,8 @@
* @throws AuthenticationException when a parsing or other error occurs
* @see HttpState#setCredentials(String,String,Credentials)
+ *
+ * @deprecated use AuthScheme
*/
public static boolean authenticate(
AuthScheme authscheme,
@@ -394,6 +411,8 @@
* @throws AuthenticationException when a parsing or other error occurs
* @see HttpState#setCredentials(String,String,Credentials)
+ *
+ * @deprecated use AuthScheme
*/
public static boolean authenticateProxy(
AuthScheme authscheme,
Index: java/org/apache/commons/httpclient/auth/NTLM.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/NTLM.java,v
retrieving revision 1.5
diff -u -r1.5 NTLM.java
--- java/org/apache/commons/httpclient/auth/NTLM.java 11 Dec 2003 01:19:32 -0000 1.5
+++ java/org/apache/commons/httpclient/auth/NTLM.java 15 Dec 2003 11:12:32 -0000
@@ -263,7 +263,7 @@
* @param domain The domain to authenticate with.
* @return String the message to add to the HTTP request header.
*/
- private String getType1Message(String host, String domain) {
+ public String getType1Message(String host, String domain) {
host = host.toUpperCase();
domain = domain.toUpperCase();
byte[] hostBytes = EncodingUtil.getBytes(host, DEFAULT_CHARSET);
@@ -338,7 +338,7 @@
* @return an array of 8 bytes that the server sent to be used when
* hashing the password.
*/
- private byte[] parseType2Message(String message) {
+ public byte[] parseType2Message(String message) {
// Decode the message first.
byte[] msg = Base64.decode(EncodingUtil.getBytes(message, DEFAULT_CHARSET));
byte[] nonce = new byte[8];
@@ -362,7 +362,7 @@
* @return The type 3 message.
* @throws AuthenticationException If {@encrypt(byte[],byte[])} fails.
*/
- private String getType3Message(String user, String password,
+ public String getType3Message(String user, String password,
String host, String domain, byte[] nonce)
throws AuthenticationException {
Index: java/org/apache/commons/httpclient/auth/NTLMScheme.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/NTLMScheme.java,v
retrieving revision 1.13
diff -u -r1.13 NTLMScheme.java
--- java/org/apache/commons/httpclient/auth/NTLMScheme.java 11 Dec 2003 01:19:32 -0000 1.13
+++ java/org/apache/commons/httpclient/auth/NTLMScheme.java 15 Dec 2003 11:12:32 -0000
@@ -90,12 +90,21 @@
/** NTLM challenge string. */
private String ntlmchallenge = null;
+ private static final int UNINITIATED = 0;
+ private static final int INITIATED = 1;
+ private static final int TYPE1_MSG_GENERATED = 2;
+ private static final int TYPE2_MSG_RECEIVED = 3;
+ private static final int TYPE3_MSG_GENERATED = 4;
+
+ /** Authentication process state */
+ private int state;
/**
* Default constructor for the NTLM authentication scheme.
*
*/
public NTLMScheme() {
super();
+ this.state = UNINITIATED;
}
/**
@@ -128,12 +137,24 @@
if (i != -1) {
s = challenge.substring(i, challenge.length());
this.ntlmchallenge = s.trim();
+ this.state = TYPE2_MSG_RECEIVED;
} else {
this.ntlmchallenge = "";
+ this.state = INITIATED;
}
}
/**
+ * Tests if the NTLM authentication process has been completed.
+ *
+ * @return true if Basic authorization has been processed,
+ * false otherwise.
+ */
+ public boolean isComplete() {
+ return this.state == TYPE3_MSG_GENERATED;
+ }
+
+ /**
* Returns textual designation of the NTLM authentication scheme.
*
* @return ntlm
@@ -167,12 +188,13 @@
*
* @return String a String identifying the authentication challenge. The
* returned value may be null.
+ *
+ * @deprecated no longer used
*/
public String getID() {
return ntlmchallenge;
}
-
/**
* Returns the authentication parameter with the given name, if available.
*
@@ -208,6 +230,8 @@
*
* @return a ntlm authorization string
* @throws AuthenticationException is thrown if authentication fails
+ *
+ * @deprecated Use non-static {@link #authenticate(Credentials, HttpMethod)}
*/
public static String authenticate(
final NTCredentials credentials, final String challenge)
@@ -236,6 +260,8 @@
*
* @return a ntlm authorization string
* @throws AuthenticationException is thrown if authentication fails
+ *
+ * @deprecated Use non-static {@link #authenticate(Credentials, HttpMethod)}
*/
public static String authenticate(
final NTCredentials credentials,
@@ -273,6 +299,8 @@
* be generated due to an authentication failure
*
* @return an NTLM authorization string
+ *
+ * @deprecated Use {@link #authenticate(Credentials, HttpMethod)}
*/
public String authenticate(Credentials credentials, String method, String uri)
throws AuthenticationException {
@@ -309,6 +337,10 @@
) throws AuthenticationException {
LOG.trace("enter NTLMScheme.authenticate(Credentials, HttpMethod)");
+ if (this.state == UNINITIATED) {
+ throw new IllegalStateException("NTLM authentication process has not been initiated");
+ }
+
NTCredentials ntcredentials = null;
try {
ntcredentials = (NTCredentials) credentials;
@@ -317,9 +349,22 @@
"Credentials cannot be used for NTLM authentication: "
+ credentials.getClass().getName());
}
- return NTLMScheme.authenticate(
- ntcredentials,
- this.ntlmchallenge,
- method.getParams().getCredentialCharset());
+ NTLM ntlm = new NTLM();
+ String response = null;
+ if (this.state == INITIATED) {
+ response = ntlm.getType1Message(
+ ntcredentials.getHost(),
+ ntcredentials.getDomain());
+ this.state = TYPE1_MSG_GENERATED;
+ } else {
+ response = ntlm.getType3Message(
+ ntcredentials.getUserName(),
+ ntcredentials.getPassword(),
+ ntcredentials.getHost(),
+ ntcredentials.getDomain(),
+ ntlm.parseType2Message(this.ntlmchallenge));
+ this.state = TYPE3_MSG_GENERATED;
+ }
+ return "NTLM " + response;
}
}
Index: java/org/apache/commons/httpclient/auth/RFC2617Scheme.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/RFC2617Scheme.java,v
retrieving revision 1.5
diff -u -r1.5 RFC2617Scheme.java
--- java/org/apache/commons/httpclient/auth/RFC2617Scheme.java 10 Dec 2003 21:04:13 -0000 1.5
+++ java/org/apache/commons/httpclient/auth/RFC2617Scheme.java 15 Dec 2003 11:12:33 -0000
@@ -1,5 +1,5 @@
/*
- * $Header: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/RFC2617Scheme.java,v 1.5 2003/12/10 21:04:13 olegk Exp $
+ * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/RFC2617Scheme.java,v 1.5 2003/12/10 21:04:13 olegk Exp $
* $Revision: 1.5 $
* $Date: 2003/12/10 21:04:13 $
*
@@ -144,6 +144,9 @@
if (name == null) {
throw new IllegalArgumentException("Parameter name may not be null");
}
+ if (this.params == null) {
+ return null;
+ }
return (String) this.params.get(name.toLowerCase());
}
@@ -173,6 +176,8 @@
*
* @return String a String identifying the authentication challenge. The
* returned value may be null.
+ *
+ * @deprecated no longer used
*/
public String getID() {
return getRealm();
Index: test/org/apache/commons/httpclient/NoncompliantPostMethod.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/NoncompliantPostMethod.java,v
retrieving revision 1.1
diff -u -r1.1 NoncompliantPostMethod.java
--- test/org/apache/commons/httpclient/NoncompliantPostMethod.java 1 Feb 2003 16:10:48 -0000 1.1
+++ test/org/apache/commons/httpclient/NoncompliantPostMethod.java 15 Dec 2003 11:12:33 -0000
@@ -99,7 +99,8 @@
Header header = headers[i];
// Write all the headers but "Expect"
if (!header.getName().equalsIgnoreCase("Expect") ) {
- conn.print(header.toExternalForm());
+ conn.print(header.toExternalForm(),
+ HttpConstants.HTTP_ELEMENT_CHARSET);
}
}
}
Index: test/org/apache/commons/httpclient/TestBadContentLength.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestBadContentLength.java,v
retrieving revision 1.2
diff -u -r1.2 TestBadContentLength.java
--- test/org/apache/commons/httpclient/TestBadContentLength.java 11 Dec 2003 22:54:19 -0000 1.2
+++ test/org/apache/commons/httpclient/TestBadContentLength.java 15 Dec 2003 11:12:33 -0000
@@ -63,7 +63,6 @@
import java.io.IOException;
import java.io.InputStream;
-import java.net.ProtocolException;
import junit.framework.Test;
import junit.framework.TestSuite;