Chromium Code Reviews| 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, |