DigestScheme can use an arbitrary digest algorithm requested by the target server (such SHA) as long as this algorithm is supported by the Java runtime

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@708595 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2008-10-28 15:11:25 +00:00
parent c3b6c426ca
commit e434f1367a
3 changed files with 48 additions and 22 deletions

View File

@ -1,6 +1,11 @@
Changes since 4.0 beta 1 Changes since 4.0 beta 1
------------------- -------------------
* DigestScheme can use an arbitrary digest algorithm requested by the
target server (such SHA) as long as this algorithm is supported by
the Java runtime.
Contributed by Oleg Kalnichevski <olegk at apache.org>
* Fixed parsing and validation of RFC2109 compliant Set-Cookie headers * Fixed parsing and validation of RFC2109 compliant Set-Cookie headers
by the Best-Match cookie spec. by the Best-Match cookie spec.
Contributed by Oleg Kalnichevski <olegk at apache.org> Contributed by Oleg Kalnichevski <olegk at apache.org>

View File

@ -288,7 +288,11 @@ public class DigestScheme extends RFC2617Scheme {
"Unsupported qop in HTTP Digest authentication"); "Unsupported qop in HTTP Digest authentication");
} }
MessageDigest md5Helper = createMessageDigest("MD5"); String digAlg = algorithm;
if (digAlg.equalsIgnoreCase("MD5-sess")) {
digAlg = "MD5";
}
MessageDigest digester = createMessageDigest(digAlg);
String uname = credentials.getUserPrincipal().getName(); String uname = credentials.getUserPrincipal().getName();
String pwd = credentials.getPassword(); String pwd = credentials.getPassword();
@ -304,25 +308,25 @@ public class DigestScheme extends RFC2617Scheme {
String a1 = tmp.toString(); String a1 = tmp.toString();
//a1 is suitable for MD5 algorithm //a1 is suitable for MD5 algorithm
if(algorithm.equals("MD5-sess")) { if (algorithm.equalsIgnoreCase("MD5-sess")) {
// H( unq(username-value) ":" unq(realm-value) ":" passwd ) // H( unq(username-value) ":" unq(realm-value) ":" passwd )
// ":" unq(nonce-value) // ":" unq(nonce-value)
// ":" unq(cnonce-value) // ":" unq(cnonce-value)
algorithm = "MD5";
String cnonce = getCnonce(); String cnonce = getCnonce();
String tmp2=encode(md5Helper.digest(EncodingUtils.getBytes(a1, charset))); String tmp2 = encode(digester.digest(EncodingUtils.getBytes(a1, charset)));
StringBuilder tmp3 = new StringBuilder(tmp2.length() + nonce.length() + cnonce.length() + 2); StringBuilder tmp3 = new StringBuilder(
tmp2.length() + nonce.length() + cnonce.length() + 2);
tmp3.append(tmp2); tmp3.append(tmp2);
tmp3.append(':'); tmp3.append(':');
tmp3.append(nonce); tmp3.append(nonce);
tmp3.append(':'); tmp3.append(':');
tmp3.append(cnonce); tmp3.append(cnonce);
a1 = tmp3.toString(); a1 = tmp3.toString();
} else if (!algorithm.equals("MD5")) {
throw new AuthenticationException("Unhandled algorithm " + algorithm + " requested");
} }
String md5a1 = encode(md5Helper.digest(EncodingUtils.getBytes(a1, charset))); String hasha1 = encode(digester.digest(EncodingUtils.getBytes(a1, charset)));
String a2 = null; String a2 = null;
if (qopVariant == QOP_AUTH_INT) { if (qopVariant == QOP_AUTH_INT) {
@ -332,25 +336,26 @@ public class DigestScheme extends RFC2617Scheme {
} else { } else {
a2 = method + ':' + uri; a2 = method + ':' + uri;
} }
String md5a2 = encode(md5Helper.digest(EncodingUtils.getAsciiBytes(a2))); String hasha2 = encode(digester.digest(EncodingUtils.getAsciiBytes(a2)));
// 3.2.2.1 // 3.2.2.1
String serverDigestValue; String serverDigestValue;
if (qopVariant == QOP_MISSING) { if (qopVariant == QOP_MISSING) {
StringBuilder tmp2 = new StringBuilder(md5a1.length() + nonce.length() + md5a2.length()); StringBuilder tmp2 = new StringBuilder(
tmp2.append(md5a1); hasha1.length() + nonce.length() + hasha1.length());
tmp2.append(hasha1);
tmp2.append(':'); tmp2.append(':');
tmp2.append(nonce); tmp2.append(nonce);
tmp2.append(':'); tmp2.append(':');
tmp2.append(md5a2); tmp2.append(hasha2);
serverDigestValue = tmp2.toString(); serverDigestValue = tmp2.toString();
} else { } else {
String qopOption = getQopVariantString(); String qopOption = getQopVariantString();
String cnonce = getCnonce(); String cnonce = getCnonce();
StringBuilder tmp2 = new StringBuilder(md5a1.length() + nonce.length() StringBuilder tmp2 = new StringBuilder(hasha1.length() + nonce.length()
+ NC.length() + cnonce.length() + qopOption.length() + md5a2.length() + 5); + NC.length() + cnonce.length() + qopOption.length() + hasha2.length() + 5);
tmp2.append(md5a1); tmp2.append(hasha1);
tmp2.append(':'); tmp2.append(':');
tmp2.append(nonce); tmp2.append(nonce);
tmp2.append(':'); tmp2.append(':');
@ -360,12 +365,12 @@ public class DigestScheme extends RFC2617Scheme {
tmp2.append(':'); tmp2.append(':');
tmp2.append(qopOption); tmp2.append(qopOption);
tmp2.append(':'); tmp2.append(':');
tmp2.append(md5a2); tmp2.append(hasha2);
serverDigestValue = tmp2.toString(); serverDigestValue = tmp2.toString();
} }
String serverDigest = String serverDigest =
encode(md5Helper.digest(EncodingUtils.getAsciiBytes(serverDigestValue))); encode(digester.digest(EncodingUtils.getAsciiBytes(serverDigestValue)));
return serverDigest; return serverDigest;
} }
@ -449,12 +454,9 @@ public class DigestScheme extends RFC2617Scheme {
* @return encoded MD5, or <CODE>null</CODE> if encoding failed * @return encoded MD5, or <CODE>null</CODE> if encoding failed
*/ */
private static String encode(byte[] binaryData) { private static String encode(byte[] binaryData) {
if (binaryData.length != 16) { int n = binaryData.length;
return null; char[] buffer = new char[n * 2];
} for (int i = 0; i < n; i++) {
char[] buffer = new char[32];
for (int i = 0; i < 16; i++) {
int low = (binaryData[i] & 0x0f); int low = (binaryData[i] & 0x0f);
int high = ((binaryData[i] & 0xf0) >> 4); int high = ((binaryData[i] & 0xf0) >> 4);
buffer[i * 2] = HEXADECIMAL[high]; buffer[i * 2] = HEXADECIMAL[high];

View File

@ -130,6 +130,25 @@ public class TestDigestScheme extends TestCase {
assertEquals("e95a7ddf37c2eab009568b1ed134f89a", table.get("response")); assertEquals("e95a7ddf37c2eab009568b1ed134f89a", table.get("response"));
} }
public void testDigestAuthenticationWithSHA() throws Exception {
String challenge = "Digest realm=\"realm1\", " +
"nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
"algorithm=SHA";
Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
HttpRequest request = new BasicHttpRequest("Simple", "/");
Credentials cred = new UsernamePasswordCredentials("username","password");
AuthScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
Header authResponse = authscheme.authenticate(cred, request);
Map<String, String> table = parseAuthResponse(authResponse);
assertEquals("username", table.get("username"));
assertEquals("realm1", table.get("realm"));
assertEquals("/", table.get("uri"));
assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
assertEquals("8769e82e4e28ecc040b969562b9050580c6d186d", table.get("response"));
}
public void testDigestAuthenticationWithQueryStringInDigestURI() throws Exception { public void testDigestAuthenticationWithQueryStringInDigestURI() throws Exception {
String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\""; String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge); Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);