Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(584)

Unified Diff: sdk/lib/io/http_impl.dart

Issue 14740015: Implementation of HTTP digest authentication (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sdk/lib/io/http_impl.dart
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index ee855ec8661e76acc5bd920272ab9938bce258f8..8ee2458208dc720ce0e79171e764abeab90cdcec 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -274,8 +274,7 @@ class _HttpClientResponse
Future<HttpClientResponse> _authenticate() {
Future<HttpClientResponse> retryWithCredentials(_Credentials cr) {
if (cr != null) {
- // TODO(sgjesse): Support digest.
- if (cr.scheme == _AuthenticationScheme.BASIC) {
+ if (cr.scheme != _AuthenticationScheme.UNKNOWN) {
Anders Johnsen 2013/05/02 19:10:19 Merge ifs.
Søren Gjesse 2013/05/03 08:10:36 Done.
// Drain body and retry.
return fold(null, (x, y) {}).then((_) {
return _httpClient._openUrlFromRequest(_httpRequest.method,
@@ -299,12 +298,28 @@ class _HttpClientResponse
new _AuthenticationScheme.fromString(header.value);
String realm = header.parameters["realm"];
- // See if any credentials are available.
+ // See if any matching credentials are available.
_Credentials cr = _httpClient._findCredentials(_httpRequest.uri, scheme);
+ if (cr != null) {
+ if (cr.scheme == _AuthenticationScheme.BASIC && !cr.used) {
+ // If credentials found prepare for retrying the request.
+ return retryWithCredentials(cr);
+ }
- if (cr != null && !cr.used) {
- // If credentials found prepare for retrying the request.
- return retryWithCredentials(cr);
+ // Digest authentication only supports the MD5 algorithm.
+ if (cr.scheme == _AuthenticationScheme.DIGEST &&
Anders Johnsen 2013/05/02 19:10:19 No used check? If missing, maybe move it to line 3
Søren Gjesse 2013/05/03 08:10:36 The checking for whether the nonce is set works li
+ (header.parameters["algorithm"] == null ||
Anders Johnsen 2013/05/02 19:10:19 != String, or do we always know it's either null o
Søren Gjesse 2013/05/03 08:10:36 Done.
Søren Gjesse 2013/05/03 08:10:36 The HeaderValue only adds Strings to the map.
+ header.parameters["algorithm"].toLowerCase() == "md5")) {
+ if (cr.nonce == null) {
+ // Set up authentication state.
+ cr.nonce = header.parameters["nonce"];
+ cr.algorithm = "MD5";
+ cr.qop = header.parameters["qop"];
+ cr.nonceCount = 0;
+ }
+ // If credentials found prepare for retrying the request.
+ return retryWithCredentials(cr);
+ }
}
// Ask for more credentials if none found or the one found has
@@ -1948,7 +1963,16 @@ class _AuthenticationScheme {
class _Credentials {
- _Credentials(this.uri, this.realm, this.credentials);
+ _Credentials(this.uri, this.realm, this.credentials) {
+ // Calculate the H(A1) value once.
+ var hasher = new MD5();
+ hasher.add(credentials.username.codeUnits);
Anders Johnsen 2013/05/02 19:10:19 Should we do any String encoding here, and below?
Søren Gjesse 2013/05/03 08:10:36 Added UTF-8 encoding and moved the coment from lin
+ hasher.add([_CharCode.COLON]);
+ hasher.add(realm.codeUnits);
+ hasher.add([_CharCode.COLON]);
+ hasher.add(credentials.password.codeUnits);
+ ha1 = CryptoUtils.bytesToHex(hasher.close());
+ }
_AuthenticationScheme get scheme => credentials.scheme;
@@ -1963,6 +1987,12 @@ class _Credentials {
}
void authorize(HttpClientRequest request) {
+ // Digest credentials cannot be used without a nonce from the
+ // server.
+ if (credentials.scheme == _AuthenticationScheme.DIGEST &&
+ nonce == null) {
+ return;
+ }
credentials.authorize(this, request);
used = true;
}
@@ -1973,9 +2003,11 @@ class _Credentials {
_HttpClientCredentials credentials;
// Digest specific fields.
+ String ha1;
String nonce;
String algorithm;
String qop;
+ int nonceCount;
}
@@ -2047,9 +2079,65 @@ class _HttpClientDigestCredentials
_AuthenticationScheme get scheme => _AuthenticationScheme.DIGEST;
+ String authorization(_Credentials credentials, HttpClientRequest request) {
+ // There is no mentioning of username/password encoding in RFC
+ // 2617. However there is an open draft for adding an additional
+ // accept-charset parameter to the WWW-Authenticate and
+ // Proxy-Authenticate headers, see
+ // http://tools.ietf.org/html/draft-reschke-basicauth-enc-06. For
+ // now always use UTF-8 encoding.
+ MD5 hasher = new MD5();
+ hasher.add(request.method.codeUnits);
+ hasher.add([_CharCode.COLON]);
+ hasher.add(request.uri.path.codeUnits);
+ var ha2 = CryptoUtils.bytesToHex(hasher.close());
+
+ String qop;
+ String cnonce;
+ String nc;
+ var x;
+ hasher = new MD5();
+ hasher.add(credentials.ha1.codeUnits);
+ hasher.add([_CharCode.COLON]);
+ if (credentials.qop == "auth") {
+ qop = credentials.qop;
+ cnonce = CryptoUtils.bytesToHex(_IOCrypto.getRandomBytes(4));
+ nc = (++credentials.nonceCount).toRadixString(16);
+ nc = "00000000".substring(0, 8 - nc.length + 1) + nc;
+ hasher.add(credentials.nonce.codeUnits);
+ hasher.add([_CharCode.COLON]);
+ hasher.add(nc.codeUnits);
+ hasher.add([_CharCode.COLON]);
+ hasher.add(cnonce.codeUnits);
+ hasher.add([_CharCode.COLON]);
+ hasher.add(credentials.qop.codeUnits);
+ hasher.add([_CharCode.COLON]);
+ hasher.add(ha2.codeUnits);
+ } else {
+ hasher.add(credentials.nonce.codeUnits);
+ hasher.add([_CharCode.COLON]);
+ hasher.add(ha2.codeUnits);
+ }
+ var response = CryptoUtils.bytesToHex(hasher.close());
+
+ StringBuffer buffer = new StringBuffer();
+ buffer.write('Digest ');
+ buffer.write('username="$username"');
+ buffer.write(', realm="${credentials.realm}"');
+ buffer.write(', nonce="${credentials.nonce}"');
+ buffer.write(', uri="${request.uri.path}"');
+ buffer.write(', algorithm="${credentials.algorithm}"');
+ if (qop == "auth") {
+ buffer.write(', qop="$qop"');
+ buffer.write(', cnonce="$cnonce"');
+ buffer.write(', nc="$nc"');
+ }
+ buffer.write(', response="$response"');
+ return buffer.toString();
+ }
+
void authorize(_Credentials credentials, HttpClientRequest request) {
- // TODO(sgjesse): Implement!!!
- throw new UnsupportedError("Digest authentication not yet supported");
+ request.headers.set(HttpHeaders.AUTHORIZATION, authorization(credentials, request));
}
void authorizeProxy(_ProxyCredentials credentials,

Powered by Google App Engine
This is Rietveld 408576698