You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by ol...@apache.org on 2004/06/23 08:50:25 UTC
cvs commit: jakarta-commons/httpclient/src/test/org/apache/commons/httpclient TestHttpState.java
olegk 2004/06/22 23:50:25
Modified: httpclient/src/java/org/apache/commons/httpclient
HttpState.java
httpclient/src/java/org/apache/commons/httpclient/auth
AuthScope.java
httpclient/src/test/org/apache/commons/httpclient
TestHttpState.java
Log:
PR #29540 (HttpState#matchCredentials is broken)
Changelog:
* Fixes credentials scope matching algorithm
Contributed by Oleg Kalnichevski
Reviewed by Michael Becke
Revision Changes Path
1.35 +32 -30 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpState.java
Index: HttpState.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpState.java,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -r1.34 -r1.35
--- HttpState.java 12 Jun 2004 22:47:23 -0000 1.34
+++ HttpState.java 23 Jun 2004 06:50:25 -0000 1.35
@@ -310,7 +310,7 @@
* have been explictly supplied for the challenging host. Any previous
* credentials for the given realm on the given host will be overwritten.
*
- * @param scope the authentication scope
+ * @param realm the authentication realm
* @param host the host the realm belongs to
* @param credentials the authentication {@link Credentials credentials}
* for the given realm.
@@ -330,7 +330,7 @@
* Sets the {@link Credentials credentials} for the given authentication
* scope. Any previous credentials for the given scope will be overwritten.
*
- * @param scope the {@link AuthScope authentication scope}
+ * @param authscope the {@link AuthScope authentication scope}
* @param credentials the authentication {@link Credentials credentials}
* for the given scope.
*
@@ -355,24 +355,26 @@
* @return the credentials
*
*/
- private static Credentials matchCredentials(HashMap map, AuthScope authscope) {
- AuthScope key = authscope;
- Credentials creds = (Credentials) map.get(key);
- if (creds == null && authscope.getScheme() != null) {
- key = new AuthScope(authscope.getHost(), authscope.getPort(), authscope.getRealm());
- creds = (Credentials) map.get(key);
- }
- if (creds == null && authscope.getRealm() != null) {
- key = new AuthScope(authscope.getHost(), authscope.getPort());
- creds = (Credentials) map.get(key);
- }
- if (creds == null && authscope.getPort() >= 0) {
- key = new AuthScope(authscope.getHost(), -1);
- creds = (Credentials) map.get(key);
- }
- if (creds == null && authscope.getHost() != null) {
- key = AuthScope.ANY;
- creds = (Credentials) map.get(key);
+ private static Credentials matchCredentials(final HashMap map, final AuthScope authscope) {
+ // see if we get a direct hit
+ Credentials creds = (Credentials)map.get(authscope);
+ if (creds == null) {
+ // Nope.
+ // Do a full scan
+ int bestMatchFactor = -1;
+ AuthScope bestMatch = null;
+ Iterator items = map.keySet().iterator();
+ while (items.hasNext()) {
+ AuthScope current = (AuthScope)items.next();
+ int factor = authscope.match(current);
+ if (factor > bestMatchFactor) {
+ bestMatchFactor = factor;
+ bestMatch = current;
+ }
+ }
+ if (bestMatch != null) {
+ creds = (Credentials)map.get(bestMatch);
+ }
}
return creds;
}
@@ -389,7 +391,7 @@
* the default Credentials. If there are no default credentials, return
* <code>null</code>.
*
- * @param scope the authentication scope
+ * @param realm the authentication realm
* @param host the host the realm is on
* @return the credentials
*
@@ -407,7 +409,7 @@
/**
* Get the {@link Credentials credentials} for the given authentication scope.
*
- * @param scope the {@link AuthScope authentication scope}
+ * @param authscope the {@link AuthScope authentication scope}
* @return the credentials
*
* @see #setCredentials(AuthScope, Credentials)
@@ -433,7 +435,7 @@
* credentials for the given proxy realm on the given proxy host will be
* overwritten.
*
- * @param scope the authentication scope
+ * @param realm the authentication realm
* @param proxyHost the proxy host
* @param credentials the authentication credentials for the given realm
*
@@ -455,7 +457,7 @@
* Sets the {@link Credentials proxy credentials} for the given authentication
* realm. Any previous credentials for the given realm will be overwritten.
*
- * @param scope the {@link AuthScope authentication scope}
+ * @param authscope the {@link AuthScope authentication scope}
* @param credentials the authentication {@link Credentials credentials}
* for the given realm.
*
@@ -486,7 +488,7 @@
* the default Credentials. If there are no default credentials, return
* <code>null</code>.
*
- * @param scope the authentication scope
+ * @param realm the authentication realm
* @param proxyHost the proxy host the realm is on
* @return the credentials
* @see #setProxyCredentials(String, String, Credentials)
@@ -502,7 +504,7 @@
/**
* Get the {@link Credentials proxy credentials} for the given authentication scope.
*
- * @param scope the {@link AuthScope authentication scope}
+ * @param authscope the {@link AuthScope authentication scope}
* @return the credentials
*
* @see #setProxyCredentials(AuthScope, Credentials)
1.2 +63 -29 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/AuthScope.java
Index: AuthScope.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/AuthScope.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- AuthScope.java 12 Jun 2004 22:47:23 -0000 1.1
+++ AuthScope.java 23 Jun 2004 06:50:25 -0000 1.2
@@ -32,7 +32,7 @@
/**
* The class represents an authentication scope consisting of a host name,
* a port number, a realm name and an authentication scheme name which
- * {@link Credentials} apply to.
+ * {@link org.apache.commons.httpclient.Credentials} apply to.
*
* @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
* @author <a href="mailto:adrian@intencha.com">Adrian Sutton</a>
@@ -103,10 +103,10 @@
public AuthScope(final String host, int port,
final String realm, final String scheme)
{
- this.host = host;
- this.port = port;
- this.realm = realm;
- this.scheme = scheme;
+ this.host = (host == null) ? ANY_HOST: host.toLowerCase();
+ this.port = (port < 0) ? ANY_PORT: port;
+ this.realm = (realm == null) ? ANY_REALM: realm;
+ this.scheme = (scheme == null) ? ANY_SCHEME: scheme.toUpperCase();;
}
/** Creates a new credentials scope for the given
@@ -198,37 +198,70 @@
return this.scheme;
}
- /** Determines if the given parameters match. Note that <tt>null</tt> acts as a
- * wildcard so if either of the parameters are <tt>null</tt>, it is considered a match.
+ /** Determines if the given parameters are equal.
*
* @param p1 the parameter
* @param p2 the other parameter
- * @return boolean true if the parameters match, otherwise false.
+ * @return boolean true if the parameters are equal, otherwise false.
*/
- private static boolean paramsMatchIgnoreCase(final String p1, final String p2) {
- return p1 == null || p2 == null || p1.equalsIgnoreCase(p2);
+ private static boolean paramsEqual(final String p1, final String p2) {
+ if (p1 == null) {
+ return p1 == p2;
+ } else {
+ return p1.equals(p2);
+ }
}
- /** Determines if the given parameters match. Note that <tt>null</tt> acts as a
- * wildcard so if either of the parameters are <tt>null</tt>, it is considered a match.
+ /** Determines if the given parameters are equal.
*
* @param p1 the parameter
* @param p2 the other parameter
- * @return boolean true if the parameters match, otherwise false.
+ * @return boolean true if the parameters are equal, otherwise false.
*/
- private static boolean paramsMatch(final String p1, final String p2) {
- return p1 == null || p2 == null || p1.equals(p2);
+ private static boolean paramsEqual(int p1, int p2) {
+ return p1 == p2;
}
- /** Determines if the given parameters match. Note that negative value acts as a
- * wildcard so if either of the parameters are negative, it is considered a match.
+ /**
+ * Tests if the authentication scopes match.
*
- * @param p1 the parameter
- * @param p2 the other parameter
- * @return boolean true if the parameters match, otherwise false.
+ * @return the match factor. Negative value signifies no match.
+ * Non-negative signifies a match. The greater the returned value
+ * the closer the match.
+ *
+ * @since 3.0
*/
- private static boolean paramsMatch(int p1, int p2) {
- return p1 < 0 || p2 < 0 || p1 == p2;
+ public int match(final AuthScope that) {
+ int factor = 0;
+ if (paramsEqual(this.scheme, that.scheme)) {
+ factor += 1;
+ } else {
+ if (this.scheme != ANY_SCHEME && that.scheme != ANY_SCHEME) {
+ return -1;
+ }
+ }
+ if (paramsEqual(this.realm, that.realm)) {
+ factor += 2;
+ } else {
+ if (this.realm != ANY_REALM && that.realm != ANY_REALM) {
+ return -1;
+ }
+ }
+ if (paramsEqual(this.port, that.port)) {
+ factor += 4;
+ } else {
+ if (this.port != ANY_PORT && that.port != ANY_PORT) {
+ return -1;
+ }
+ }
+ if (paramsEqual(this.host, that.host)) {
+ factor += 8;
+ } else {
+ if (this.host != ANY_HOST && that.host != ANY_HOST) {
+ return -1;
+ }
+ }
+ return factor;
}
/**
@@ -246,10 +279,10 @@
}
AuthScope that = (AuthScope) o;
return
- paramsMatchIgnoreCase(this.host, that.host)
- && paramsMatch(this.port, that.port)
- && paramsMatch(this.realm, that.realm)
- && paramsMatchIgnoreCase(this.scheme, that.scheme);
+ paramsEqual(this.host, that.host)
+ && paramsEqual(this.port, that.port)
+ && paramsEqual(this.realm, that.realm)
+ && paramsEqual(this.scheme, that.scheme);
}
/**
@@ -278,6 +311,7 @@
}
return buffer.toString();
}
+
/**
* @see java.lang.Object#hashCode()
*/
1.7 +117 -60 jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHttpState.java
Index: TestHttpState.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHttpState.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- TestHttpState.java 13 Jun 2004 12:13:08 -0000 1.6
+++ TestHttpState.java 23 Jun 2004 06:50:25 -0000 1.7
@@ -30,6 +30,8 @@
package org.apache.commons.httpclient;
+import org.apache.commons.httpclient.auth.AuthScope;
+
import junit.framework.*;
/**
@@ -39,17 +41,26 @@
* @author Rodney Waldhoff
* @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
* @author Sean C. Sullivan
+ * @author Oleg Kalnichevski
*
* @version $Id$
*
*/
public class TestHttpState extends TestCase {
- public final Credentials creds1 = new UsernamePasswordCredentials("user1", "pass1");
- public final Credentials creds2 = new UsernamePasswordCredentials("user2", "pass2");
-
- public final String realm1 = "realm1";
- public final String realm2 = "realm2";
+ public final static Credentials CREDS1 =
+ new UsernamePasswordCredentials("user1", "pass1");
+ public final static Credentials CREDS2 =
+ new UsernamePasswordCredentials("user2", "pass2");
+
+ public final static AuthScope SCOPE1 =
+ new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, "realm1");
+ public final static AuthScope SCOPE2 =
+ new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, "realm2");
+ public final static AuthScope BOGUS =
+ new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, "bogus");
+ public final static AuthScope DEFSCOPE =
+ new AuthScope("host", AuthScope.ANY_PORT, "realm");
// ------------------------------------------------------------ Constructor
@@ -74,10 +85,10 @@
public void testHttpStateCredentials() {
HttpState state = new HttpState();
- state.setCredentials(realm1, null, creds1);
- state.setCredentials(realm2, null, creds2);
- assertEquals(creds1, state.getCredentials(realm1, null));
- assertEquals(creds2, state.getCredentials(realm2, null));
+ state.setCredentials(SCOPE1, CREDS1);
+ state.setCredentials(SCOPE2, CREDS2);
+ assertEquals(CREDS1, state.getCredentials(SCOPE1));
+ assertEquals(CREDS2, state.getCredentials(SCOPE2));
}
public void testToString()
@@ -91,44 +102,43 @@
state.addCookie(new Cookie("flub", "duck", "yuck"));
assertNotNull(state.toString());
- state.setCredentials(realm1, null, creds1);
+ state.setCredentials(SCOPE1, CREDS1);
assertNotNull(state.toString());
- state.setProxyCredentials(realm2, null, creds2);
+ state.setProxyCredentials(SCOPE2, CREDS2);
assertNotNull(state.toString());
}
public void testHttpStateNoCredentials() {
HttpState state = new HttpState();
- assertEquals(null, state.getCredentials("bogus", null));
+ assertEquals(null, state.getCredentials(BOGUS));
}
public void testHttpStateDefaultCredentials() {
HttpState state = new HttpState();
- state.setCredentials(null, null, creds1);
- state.setCredentials(realm2, null, creds2);
- assertEquals(creds1, state.getCredentials("bogus", null));
+ state.setCredentials(AuthScope.ANY, CREDS1);
+ state.setCredentials(SCOPE2, CREDS2);
+ assertEquals(CREDS1, state.getCredentials(BOGUS));
}
-
public void testHttpStateProxyCredentials() {
HttpState state = new HttpState();
- state.setProxyCredentials(realm1, null, creds1);
- state.setProxyCredentials(realm2, null, creds2);
- assertEquals(creds1, state.getProxyCredentials(realm1, null));
- assertEquals(creds2, state.getProxyCredentials(realm2, null));
+ state.setProxyCredentials(SCOPE1, CREDS1);
+ state.setProxyCredentials(SCOPE2, CREDS2);
+ assertEquals(CREDS1, state.getProxyCredentials(SCOPE1));
+ assertEquals(CREDS2, state.getProxyCredentials(SCOPE2));
}
public void testHttpStateProxyNoCredentials() {
HttpState state = new HttpState();
- assertEquals(null, state.getProxyCredentials("bogus", null));
+ assertEquals(null, state.getProxyCredentials(BOGUS));
}
public void testHttpStateProxyDefaultCredentials() {
HttpState state = new HttpState();
- state.setProxyCredentials(null, null, creds1);
- state.setProxyCredentials(realm2, null, creds2);
- assertEquals(creds1, state.getProxyCredentials("bogus", null));
+ state.setProxyCredentials(AuthScope.ANY, CREDS1);
+ state.setProxyCredentials(SCOPE2, CREDS2);
+ assertEquals(CREDS1, state.getProxyCredentials(BOGUS));
}
// --------------------------------- Test Methods for Selecting Credentials
@@ -136,65 +146,112 @@
public void testDefaultCredentials() throws Exception {
HttpState state = new HttpState();
Credentials expected = new UsernamePasswordCredentials("name", "pass");
- state.setCredentials(null, null, expected);
- Credentials got = state.getCredentials("realm", "host");
+ state.setCredentials(AuthScope.ANY, expected);
+ Credentials got = state.getCredentials(DEFSCOPE);
assertEquals(got, expected);
}
public void testRealmCredentials() throws Exception {
HttpState state = new HttpState();
Credentials expected = new UsernamePasswordCredentials("name", "pass");
- state.setCredentials("realm", "host", expected);
- Credentials got = state.getCredentials("realm", "host");
+ state.setCredentials(DEFSCOPE, expected);
+ Credentials got = state.getCredentials(DEFSCOPE);
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");
+ state.setCredentials(
+ new AuthScope("host", AuthScope.ANY_PORT, AuthScope.ANY_REALM), expected);
+ Credentials got = state.getCredentials(DEFSCOPE);
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");
+ state.setCredentials(
+ new AuthScope("host1", AuthScope.ANY_PORT, "realm"), expected);
+ Credentials got = state.getCredentials(
+ new AuthScope("host2", AuthScope.ANY_PORT, "realm"));
assertNotSame(expected, got);
}
public void testWrongRealmCredentials() throws Exception {
HttpState state = new HttpState();
Credentials cred = new UsernamePasswordCredentials("name", "pass");
- state.setCredentials("realm1", "host", cred);
- Credentials got = state.getCredentials("realm2", "host");
- assertNotSame(cred, got);
- }
-
- public void testRealmSpoof() throws Exception {
- HttpState state = new HttpState();
- Credentials cred = new UsernamePasswordCredentials("name", "pass");
- state.setCredentials(null, "admin.apache.org", cred);
- Credentials got = state.getCredentials("admin.apache.org", "myhost");
+ state.setCredentials(
+ new AuthScope("host", AuthScope.ANY_PORT, "realm1"), cred);
+ Credentials got = state.getCredentials(
+ new AuthScope("host", AuthScope.ANY_PORT, "realm2"));
assertNotSame(cred, got);
}
+
+ // ------------------------------- Test Methods for matching Credentials
- public void testRealmSpoof2() throws Exception {
+ public void testScopeMatching() {
+ AuthScope authscope1 = new AuthScope("somehost", 80, "somerealm", "somescheme");
+ AuthScope authscope2 = new AuthScope("someotherhost", 80, "somerealm", "somescheme");
+ assertTrue(authscope1.match(authscope2) < 0);
+
+ int m1 = authscope1.match(
+ new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, "somescheme"));
+ int m2 = authscope1.match(
+ new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, "somerealm", AuthScope.ANY_SCHEME));
+ assertTrue(m2 > m1);
+
+ m1 = authscope1.match(
+ new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, "somescheme"));
+ m2 = authscope1.match(
+ new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, "somerealm", AuthScope.ANY_SCHEME));
+ assertTrue(m2 > m1);
+
+ m1 = authscope1.match(
+ new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, "somerealm", "somescheme"));
+ m2 = authscope1.match(
+ new AuthScope(AuthScope.ANY_HOST, 80, AuthScope.ANY_REALM, AuthScope.ANY_SCHEME));
+ assertTrue(m2 > m1);
+
+ m1 = authscope1.match(
+ new AuthScope(AuthScope.ANY_HOST, 80, "somerealm", "somescheme"));
+ m2 = authscope1.match(
+ new AuthScope("somehost", AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthScope.ANY_SCHEME));
+ assertTrue(m2 > m1);
+
+ m1 = authscope1.match(AuthScope.ANY);
+ m2 = authscope1.match(
+ new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, "somescheme"));
+ assertTrue(m2 > m1);
+ }
+
+ public void testCredentialsMatching() {
+ Credentials creds1 = new UsernamePasswordCredentials("name1", "pass1");
+ Credentials creds2 = new UsernamePasswordCredentials("name2", "pass2");
+ Credentials creds3 = new UsernamePasswordCredentials("name3", "pass3");
+
+ AuthScope scope1 = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM);
+ AuthScope scope2 = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, "somerealm");
+ AuthScope scope3 = new AuthScope("somehost", AuthScope.ANY_PORT, AuthScope.ANY_REALM);
+
HttpState state = new HttpState();
- Credentials cred = new UsernamePasswordCredentials("name", "pass");
- state.setCredentials(null, "whatever", cred);
- Credentials got = state.getCredentials("nullwhatever", null);
- assertNotSame(cred, got);
- }
+ state.setCredentials(scope1, creds1);
+ state.setCredentials(scope2, creds2);
+ state.setCredentials(scope3, creds3);
+
+ Credentials got = state.getCredentials(
+ new AuthScope("someotherhost", 80, "someotherrealm", "basic"));
+ Credentials expected = creds1;
+ assertEquals(expected, got);
+
+ got = state.getCredentials(
+ new AuthScope("someotherhost", 80, "somerealm", "basic"));
+ expected = creds2;
+ assertEquals(expected, got);
+ got = state.getCredentials(
+ new AuthScope("somehost", 80, "someotherrealm", "basic"));
+ expected = creds3;
+ assertEquals(expected, got);
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org