Browse Source

Fix HTTP digest authentication

JGit's internal implementation of the HTTP digest authentication
method wasn't conforming to RFC 2617 (HTTP Authentication: Basic
and Digest Access Authentication), resulting in authentication
failures when connecting to a digest protected site.

The code now more accurately matches section 3.2.2 (The Authorization
Request Header) from the standards document.

Change-Id: If41b5c2cbdd59ddd6b2dea143f325e42cd58c395
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
stable-0.10
Shawn O. Pearce 14 years ago
parent
commit
2bc13104a8
  1. 70
      org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java

70
org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java

@ -49,10 +49,12 @@ import static org.eclipse.jgit.util.HttpSupport.HDR_WWW_AUTHENTICATE;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
@ -216,35 +218,50 @@ abstract class HttpAuthMethod {
@SuppressWarnings("boxing") @SuppressWarnings("boxing")
@Override @Override
void configureRequest(final HttpURLConnection conn) throws IOException { void configureRequest(final HttpURLConnection conn) throws IOException {
final Map<String, String> p = new HashMap<String, String>(params); final Map<String, String> r = new LinkedHashMap<String, String>();
p.put("username", user);
final String realm = p.get("realm"); final String realm = params.get("realm");
final String nonce = p.get("nonce"); final String nonce = params.get("nonce");
final String uri = p.get("uri"); final String cnonce = params.get("cnonce");
final String qop = p.get("qop"); final String uri = uri(conn.getURL());
final String qop = params.get("qop");
final String method = conn.getRequestMethod(); final String method = conn.getRequestMethod();
final String A1 = user + ":" + realm + ":" + pass; final String A1 = user + ":" + realm + ":" + pass;
final String A2 = method + ":" + uri; final String A2 = method + ":" + uri;
final String expect; r.put("username", user);
r.put("realm", realm);
r.put("nonce", nonce);
r.put("uri", uri);
final String response, nc;
if ("auth".equals(qop)) { if ("auth".equals(qop)) {
final String c = p.get("cnonce"); nc = String.format("%08x", ++requestCount);
final String nc = String.format("%08x", ++requestCount); response = KD(H(A1), nonce + ":" + nc + ":" + cnonce + ":"
p.put("nc", nc); + qop
expect = KD(H(A1), nonce + ":" + nc + ":" + c + ":" + qop + ":" + ":"
+ H(A2)); + H(A2));
} else { } else {
expect = KD(H(A1), nonce + ":" + H(A2)); nc = null;
} response = KD(H(A1), nonce + ":" + H(A2));
p.put("response", expect); }
r.put("response", response);
if (params.containsKey("algorithm"))
r.put("algorithm", "MD5");
if (cnonce != null && qop != null)
r.put("cnonce", cnonce);
if (params.containsKey("opaque"))
r.put("opaque", params.get("opaque"));
if (qop != null)
r.put("qop", qop);
if (nc != null)
r.put("nc", nc);
StringBuilder v = new StringBuilder(); StringBuilder v = new StringBuilder();
for (Map.Entry<String, String> e : p.entrySet()) { for (Map.Entry<String, String> e : r.entrySet()) {
if (v.length() > 0) { if (v.length() > 0)
v.append(", "); v.append(", ");
}
v.append(e.getKey()); v.append(e.getKey());
v.append('='); v.append('=');
v.append('"'); v.append('"');
@ -254,6 +271,25 @@ abstract class HttpAuthMethod {
conn.setRequestProperty(HDR_AUTHORIZATION, NAME + " " + v); conn.setRequestProperty(HDR_AUTHORIZATION, NAME + " " + v);
} }
private static String uri(URL u) {
StringBuilder r = new StringBuilder();
r.append(u.getProtocol());
r.append("://");
r.append(u.getHost());
if (0 < u.getPort()) {
if (u.getPort() == 80 && "http".equals(u.getProtocol()))
/* nothing */;
else if (u.getPort() == 443 && "https".equals(u.getProtocol()))
/* nothing */;
else
r.append(':').append(u.getPort());
}
r.append(u.getPath());
if (u.getQuery() != null)
r.append('?').append(u.getQuery());
return r.toString();
}
private static String H(String data) { private static String H(String data) {
try { try {
MessageDigest md = newMD5(); MessageDigest md = newMD5();

Loading…
Cancel
Save