Index: java/org/apache/commons/httpclient/Authenticator.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/Authenticator.java,v retrieving revision 1.41 diff -u -r1.41 Authenticator.java --- java/org/apache/commons/httpclient/Authenticator.java 28 Mar 2003 16:37:49 -0000 1.41 +++ java/org/apache/commons/httpclient/Authenticator.java 1 Apr 2003 08:58:16 -0000 @@ -199,12 +199,17 @@ * @see HttpMethod#addRequestHeader */ private static boolean authenticate(HttpMethod method, HttpState state, - boolean proxy) + boolean proxy) throws HttpException, UnsupportedOperationException { LOG.trace("enter Authenticator.authenticate(HttpMethod, HttpState, " + "Header, String)"); + return authenticate(method, null, state, proxy); + } + private static boolean authenticate(HttpMethod method, String host, + HttpState state, boolean proxy) + throws HttpException, UnsupportedOperationException { String challengeheader = proxy ? PROXY_AUTH : WWW_AUTH; // I REALLY hate doing this, but I need to avoid multiple autorization @@ -240,9 +245,9 @@ LOG.debug("Using " + authscheme.getSchemeName() + " authentication scheme"); } if (proxy) { - return HttpAuthenticator.authenticateProxy(authscheme, method, state); + return HttpAuthenticator.authenticateProxy(authscheme, method, host, state); } else { - return HttpAuthenticator.authenticate(authscheme, method, state); + return HttpAuthenticator.authenticate(authscheme, method, host, state); } } Index: java/org/apache/commons/httpclient/HttpMethodBase.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java,v retrieving revision 1.127 diff -u -r1.127 HttpMethodBase.java --- java/org/apache/commons/httpclient/HttpMethodBase.java 1 Apr 2003 00:25:24 -0000 1.127 +++ java/org/apache/commons/httpclient/HttpMethodBase.java 1 Apr 2003 08:58:29 -0000 @@ -76,7 +76,6 @@ import org.apache.commons.httpclient.cookie.MalformedCookieException; import org.apache.commons.httpclient.cookie.CookiePolicy; import org.apache.commons.httpclient.cookie.CookieSpec; -import org.apache.commons.httpclient.cookie.MalformedCookieException; import org.apache.commons.httpclient.protocol.Protocol; import org.apache.commons.httpclient.util.URIUtil; import org.apache.commons.logging.Log; @@ -1338,7 +1337,7 @@ if (challenges.length > 0) { try { AuthScheme authscheme = HttpAuthenticator.selectAuthScheme(challenges); - HttpAuthenticator.authenticate(authscheme, this, state); + HttpAuthenticator.authenticate(authscheme, this, conn.getHost(), state); } catch (HttpException e) { // log and move on if (LOG.isErrorEnabled()) { @@ -1485,7 +1484,7 @@ if (challenges.length > 0) { try { AuthScheme authscheme = HttpAuthenticator.selectAuthScheme(challenges); - HttpAuthenticator.authenticateProxy(authscheme, this, state); + HttpAuthenticator.authenticateProxy(authscheme, this, conn.getProxyHost(), state); } catch (HttpException e) { // log and move on if (LOG.isErrorEnabled()) { @@ -2340,11 +2339,11 @@ switch (statusCode) { case HttpStatus.SC_UNAUTHORIZED: removeRequestHeader(HttpAuthenticator.WWW_AUTH_RESP); - authenticated = HttpAuthenticator.authenticate(authscheme, this, state); + authenticated = HttpAuthenticator.authenticate(authscheme, this, conn.getHost(), state); break; case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED: removeRequestHeader(HttpAuthenticator.PROXY_AUTH_RESP); - authenticated = HttpAuthenticator.authenticateProxy(authscheme, this, state); + authenticated = HttpAuthenticator.authenticateProxy(authscheme, this, conn.getProxyHost(), state); break; } } catch (AuthenticationException e) { Index: java/org/apache/commons/httpclient/HttpState.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpState.java,v retrieving revision 1.18 diff -u -r1.18 HttpState.java --- java/org/apache/commons/httpclient/HttpState.java 27 Mar 2003 20:58:27 -0000 1.18 +++ java/org/apache/commons/httpclient/HttpState.java 1 Apr 2003 08:58:33 -0000 @@ -64,7 +64,6 @@ package org.apache.commons.httpclient; import java.util.ArrayList; -import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -378,7 +377,6 @@ this.cookiePolicy = policy; } - /** * Set the Credentials for the given authentication realm. * @@ -390,40 +388,117 @@ *

* Any previous credentials for this realm will be overwritten. * + * @deprecated This method does not distinguish between realms with the + * same name on different hosts. Use + * {@link HttpState#setCredentials(String, Credentials)} instead. + * * @param realm the authentication realm * @param credentials the authentication credentials for the given realm * - * @see #getCredentials(String) - * @see #setProxyCredentials(String, Credentials) + * @see #getCredentials(String, String) + * @see #setProxyCredentials(String, String, Credentials) * */ + public synchronized void setCredentials(String realm, Credentials credentials) { LOG.trace("enter HttpState.setCredentials(String, Credentials)"); - credMap.put(realm, credentials); + setCredentials(realm, null, credentials); + } + + /** Sets the credentials for realm on host. + * with no host. + * + * When realm is null, I'll use the given + * credentials when no other {@link Credentials} have + * been supplied for the given challenging realm. + * (I.e., use a null realm to set the "default" + * credentials.) + *

+ * Any previous credentials for this realm will be overwritten. + * + * @param realm the authentication realm + * @param host the host the realm belongs to + * @param credentials the authentication credentials for the given realm. + * + * @see #getCredentials(String, String) + * @see #setProxyCredentials(String, String, Credentials) + */ + + public synchronized void setCredentials(String realm, String host, Credentials credentials) { + LOG.trace( + "enter HttpState.setCredentials(String realm, String host, Credentials credentials)"); + if (host != null) { + if (realm == null) { + credMap.put(host.toLowerCase(), credentials); + } else { + credMap.put(host.toLowerCase() + realm, credentials); + } + } else { + credMap.put(realm, credentials); + } + } + + /** + * Get the Credentials for the given authentication realm. + * + * If the realm exists on host, return the coresponding credentials. + * If the host exists with a null realm, return the corresponding + * credentials. + * If the realm exists with a null host, return the + * corresponding credentials. If the realm does not exist, return + * the default Credentials. If there are no default credentials, return + * null. + * + * @param realm the authentication realm + * @param host the host the realm is on + * @return the credentials + * + * @see #setCredentials(String, String, Credentials) + * + */ + + public synchronized Credentials getCredentials(String realm, String host) { + LOG.trace("enter HttpState.getCredentials(String, String"); + Credentials creds = null; + if (host != null) { + creds = (Credentials) credMap.get(host.toLowerCase() + realm); + if (creds == null) { + creds = (Credentials) credMap.get(host.toLowerCase()); + } + } + if (creds == null) { + creds = (Credentials) credMap.get(realm); + if (creds == null) { + creds = (Credentials) credMap.get(null); + } + } + return creds; } - /** * Get the Credentials for the given authentication realm. * - * If the realm exists, return the coresponding credentials. If the - * realm does not exist, return the default Credentials. If there is - * no default credentials, return null. + * If the realm exists on host, return the coresponding credentials. + * If the realm exists with a null host, return the + * corresponding credentials. If the realm does not exist, return + * the default Credentials. If there is no default credentials, return + * null. * + * @deprecated This method does not distinguish between realms on different + * servers with the same name. Use {@link #getCredentials(String, String)} + * instead. + * * @param realm the authentication realm * @return the credentials * - * @see #setCredentials(String, Credentials) + * @see #setCredentials(String, String, Credentials) * */ + public synchronized Credentials getCredentials(String realm) { LOG.trace("enter HttpState.getCredentials(String)"); - Credentials creds = (Credentials) credMap.get(realm); - if (creds == null) { - creds = (Credentials) credMap.get(null); - } - return creds; + return getCredentials(realm, null); } /** @@ -438,6 +513,10 @@ *

* Any previous credentials for this realm will be overwritten. * + * @depreciated This method does not differentiate between realms with + * the same name on different servers. Use + * {@link #setProxyCredentials(String, String, Credentials)} instead. + * * @param realm the authentication realm * @param credentials the authentication credentials for the given realm * @@ -445,11 +524,44 @@ * @see #setCredentials(String, Credentials) * */ + public synchronized void setProxyCredentials(String realm, Credentials credentials) { LOG.trace("enter HttpState.setProxyCredentials(String, credentials)"); - proxyCred.put(realm, credentials); + setProxyCredentials(realm, null, credentials); + } + + /** + * Set the for the proxy with the given authentication realm. + * + * When realm and host are null, I'll use the given + * credentials when no other {@link Credentials} have + * been supplied for the given challenging realm. + * (I.e., use a null realm to set the "default" + * credentials.) Realms rarely make much sense with proxies, so + * null is normally a good choice here. + *

+ * Any previous credentials for this realm will be overwritten. + * + * @param realm the authentication realm + * @param credentials the authentication credentials for the given realm + * + * @see #getProxyCredentials(String) + * @see #setCredentials(String, Credentials) + * + */ + + public synchronized void setProxyCredentials(String realm, String proxyHost, Credentials credentials) { + LOG.trace("enter HttpState.setProxyCredentials(String, String, Credentials"); + if (proxyHost != null) { + if (realm == null) { + proxyCred.put(proxyHost.toLowerCase(), credentials); + } else { + proxyCred.put(proxyHost.toLowerCase() + realm, credentials); + } + } else { + proxyCred.put(realm, credentials); + } } - /** * Get the Credentials for the proxy with the given authentication realm. @@ -457,19 +569,58 @@ * If the realm exists, return the coresponding credentials. If the * realm does not exist, return the default Credentials. If there is * no default credentials, return null. + * + * @deprecated This method does not distinguish between realms on different hosts. + * Use {@link #getProxyCredentials(String, String)} instead. * * @param realm the authentication realm * @return the credentials - * @see #setProxyCredentials + * @see #setProxyCredentials(String, String, Credentials) */ + public synchronized Credentials getProxyCredentials(String realm) { LOG.trace("enter HttpState.getProxyCredentials(String)"); - Credentials creds = (Credentials) proxyCred.get(realm); - if (creds == null) { - creds = (Credentials) proxyCred.get(null); - } - return creds; + return getProxyCredentials(realm, null); } + + /** + * Get the Credentials for the proxy with the given authentication realm on the given + * host. + * + * If the realm exists on host, return the coresponding credentials. + * If the host exists with a null realm, return the corresponding + * credentials. + * If the realm exists with a null host, return the + * corresponding credentials. If the realm does not exist, return + * the default Credentials. If there are no default credentials, return + * null. + * + * @deprecated This method does not distinguish between realms on different hosts. + * Use {@link #getProxyCredentials(String, String)} instead. + * + * @param realm the authentication realm + * @param host the host the realm is on + * @return the credentials + * @see #setProxyCredentials(String, String, Credentials) + */ + + public synchronized Credentials getProxyCredentials(String realm, String proxyHost) { + LOG.trace("enter HttpState.getCredentials(String, String"); + Credentials creds = null; + if (proxyHost != null) { + creds = (Credentials) proxyCred.get(proxyHost.toLowerCase() + realm); + if (creds == null) { + creds = (Credentials) proxyCred.get(proxyHost.toLowerCase()); + } + } + if (creds == null) { + creds = (Credentials) proxyCred.get(realm); + if (creds == null) { + creds = (Credentials) proxyCred.get(null); + } + } + return creds; + } /** * Return a string representation of this object. Index: java/org/apache/commons/httpclient/NTLM.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/NTLM.java,v retrieving revision 1.12 diff -u -r1.12 NTLM.java --- java/org/apache/commons/httpclient/NTLM.java 11 Feb 2003 03:41:14 -0000 1.12 +++ java/org/apache/commons/httpclient/NTLM.java 1 Apr 2003 08:58:37 -0000 @@ -280,10 +280,14 @@ } /** - * TODO: Figure out what this method really does. - * @param host The host - * @param domain The domain - * @return String + * Creates the "type 1" response for NTLM authentication. This is the initial + * response to the server which identifies the host and domain of the client. + * + *

User credentials are supplied in the type 3 message.

+ * + * @param host The host name of the client for authentication. + * @param domain The NT domain the authentication is to occur within. + * @return String The response to send back to the server. */ private String getType1Message(String host, String domain) { host = host.toUpperCase(); @@ -373,12 +377,12 @@ /** * Creates the type 3 message using the given server nonce. - * @param user The user. + * @param user The username. * @param password The password. - * @param host The host. - * @param domain The domain. + * @param host The host name of the client for authentication. + * @param domain The NT domain to authenticate within. * @param nonce the 8 byte array the server sent. - * @return The type 3 message. + * @return The type 3 message to return to the server. * @throws HttpException If {@encrypt(byte[],byte[])} fails. */ private String getType3Message(String user, String password, @@ -477,7 +481,7 @@ * given nonce. * @param password the password to create a hash for. * @param nonce the nonce sent by the server. - * @return The response. + * @return The hashed password to include in the type 3 message. * @throws HttpException If {@link #encrypt(byte[],byte[])} fails. */ private byte[] hashPassword(String password, byte[] nonce) @@ -544,9 +548,9 @@ * plaintext is encrypted with each key and the resulting 24 bytes are * stored in the results array. * - * @param keys The keys. + * @param keys The byte array containing the 21 bytes to use as the keys. * @param plaintext The plain text to encrypt. - * @param results Where the results are stored. + * @param results Where the results are stored. This must be at least 24 bytes long. * @throws HttpException If {@link #encrypt(byte[],byte[])} fails. */ private void calcResp(byte[] keys, byte[] plaintext, byte[] results) 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.1 diff -u -r1.1 HttpAuthenticator.java --- java/org/apache/commons/httpclient/auth/HttpAuthenticator.java 27 Mar 2003 20:58:27 -0000 1.1 +++ java/org/apache/commons/httpclient/auth/HttpAuthenticator.java 1 Apr 2003 08:58:39 -0000 @@ -247,8 +247,8 @@ } - private static boolean doAuthenticate(AuthScheme authscheme, HttpMethod method, HttpState state, - boolean proxy) + private static boolean doAuthenticate(AuthScheme authscheme, HttpMethod method, String host, + HttpState state, boolean proxy) throws AuthenticationException { if (authscheme == null) { throw new IllegalArgumentException("Authentication scheme may not be null"); @@ -273,8 +273,9 @@ LOG.debug("Using '" + realm + "' authentication realm"); } } + Credentials credentials = proxy ? - state.getProxyCredentials(realm) : state.getCredentials(realm); + state.getProxyCredentials(realm, host) : state.getCredentials(realm, host); if (credentials == null) { throw new AuthenticationException( "No credentials available for the " + authscheme.getSchemeName() + @@ -308,8 +309,29 @@ */ public static boolean authenticate(AuthScheme authscheme, HttpMethod method, HttpState state) throws AuthenticationException { + return authenticate(authscheme, method, null, state); + } + + /** + * Attempt to provide requisite authentication credentials to the + * given method in the given state using the given + * authentication scheme and host. + * + * @param authscheme The authentication scheme to be used + * @param method The HttpMethod which requires authentication + * @param host The host being connected to. + * @param state The HttpState object providing Credentials + * + * @return true if the Authenticate response header was added + * + * @throws AuthenticationException when a parsing or other error occurs + + * @see HttpState#setCredentials(String,Credentials) + */ + public static boolean authenticate(AuthScheme authscheme, HttpMethod method, String host, + HttpState state) throws AuthenticationException { LOG.trace("enter HttpAuthenticator.authenticate(AuthScheme, HttpMethod, HttpState)"); - return doAuthenticate(authscheme, method, state, false); + return doAuthenticate(authscheme, method, host, state, false); } @@ -329,9 +351,9 @@ * @see HttpState#setCredentials(String,Credentials) */ - public static boolean authenticateProxy(AuthScheme authscheme, HttpMethod method, HttpState state) + public static boolean authenticateProxy(AuthScheme authscheme, HttpMethod method, String host, HttpState state) throws AuthenticationException { LOG.trace("enter HttpAuthenticator.authenticateProxy(AuthScheme, HttpMethod, HttpState)"); - return doAuthenticate(authscheme, method, state, true); + return doAuthenticate(authscheme, method, host, state, true); } } Index: test/org/apache/commons/httpclient/TestAuthenticator.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestAuthenticator.java,v retrieving revision 1.23 diff -u -r1.23 TestAuthenticator.java --- test/org/apache/commons/httpclient/TestAuthenticator.java 28 Mar 2003 16:37:50 -0000 1.23 +++ test/org/apache/commons/httpclient/TestAuthenticator.java 1 Apr 2003 08:58:45 -0000 @@ -666,5 +666,53 @@ } - + // --------------------------------- Test Methods for Selecting Credentials + + public void testDefaultCredentials() throws Exception { + HttpState state = new HttpState(); + Credentials expected = new UsernamePasswordCredentials("name", "pass"); + state.setCredentials(null, expected); + Credentials got = state.getCredentials("realm", "host"); + assertEquals(got, expected); + } + + public void testRealmCredentials() throws Exception { + HttpState state = new HttpState(); + Credentials expected = new UsernamePasswordCredentials("name", "pass"); + state.setCredentials("realm", expected); + Credentials got = state.getCredentials("realm", "host"); + assertEquals(expected, got); + } + + public void testHostCredentials() throws Exception { + HttpState state = new HttpState(); + Credentials expected = new UsernamePasswordCredentials("name", "pass"); + state.setCredentials(null, "host", expected); + Credentials got = state.getCredentials("realm", "host"); + assertEquals(expected, got); + } + + public void testBothCredentials() throws Exception { + HttpState state = new HttpState(); + Credentials expected = new UsernamePasswordCredentials("name", "pass"); + state.setCredentials("realm", "host", expected); + Credentials got = state.getCredentials("realm", "host"); + assertEquals(expected, got); + } + + public void testWrongHostCredentials() throws Exception { + HttpState state = new HttpState(); + Credentials expected = new UsernamePasswordCredentials("name", "pass"); + state.setCredentials(null, "host1", expected); + Credentials got = state.getCredentials("realm", "host2"); + assertNotSame(expected, got); + } + + public void testWrongRealmCredentials() throws Exception { + HttpState state = new HttpState(); + Credentials expected = new UsernamePasswordCredentials("name", "pass"); + state.setCredentials("realm1", "host", expected); + Credentials got = state.getCredentials("realm2", "host"); + assertNotSame(expected, got); + } }