Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/http/http_auth_handler_digest.h" | 5 #include "net/http/http_auth_handler_digest.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/md5.h" | 10 #include "base/md5.h" |
| 11 #include "base/rand_util.h" | 11 #include "base/rand_util.h" |
| 12 #include "base/string_util.h" | 12 #include "base/string_util.h" |
| 13 #include "base/stringprintf.h" | 13 #include "base/stringprintf.h" |
| 14 #include "base/utf_string_conversions.h" | 14 #include "base/utf_string_conversions.h" |
| 15 #include "net/base/net_errors.h" | 15 #include "net/base/net_errors.h" |
| 16 #include "net/base/net_util.h" | 16 #include "net/base/net_util.h" |
| 17 #include "net/http/http_auth.h" | 17 #include "net/http/http_auth.h" |
| 18 #include "net/http/http_request_info.h" | 18 #include "net/http/http_request_info.h" |
| 19 #include "net/http/http_util.h" | 19 #include "net/http/http_util.h" |
| 20 | 20 |
| 21 // TODO(eroman): support qop=auth-int | |
| 22 | |
| 23 namespace net { | 21 namespace net { |
| 24 | 22 |
| 25 // Digest authentication is specified in RFC 2617. | 23 // Digest authentication is specified in RFC 2617. |
| 26 // The expanded derivations are listed in the tables below. | 24 // The expanded derivations are listed in the tables below. |
| 27 | 25 |
| 28 //==========+==========+==========================================+ | 26 //==========+==========+==========================================+ |
| 29 // qop |algorithm | response | | 27 // qop |algorithm | response | |
| 30 //==========+==========+==========================================+ | 28 //==========+==========+==========================================+ |
| 31 // ? | ?, md5, | MD5(MD5(A1):nonce:MD5(A2)) | | 29 // ? | ?, md5, | MD5(MD5(A1):nonce:MD5(A2)) | |
| 32 // | md5-sess | | | 30 // | md5-sess | | |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 58 if (fixed_cnonce_) | 56 if (fixed_cnonce_) |
| 59 return std::string(domain); | 57 return std::string(domain); |
| 60 std::string cnonce; | 58 std::string cnonce; |
| 61 cnonce.reserve(16); | 59 cnonce.reserve(16); |
| 62 for (int i = 0; i < 16; ++i) | 60 for (int i = 0; i < 16; ++i) |
| 63 cnonce.push_back(domain[base::RandInt(0, 15)]); | 61 cnonce.push_back(domain[base::RandInt(0, 15)]); |
| 64 return cnonce; | 62 return cnonce; |
| 65 } | 63 } |
| 66 | 64 |
| 67 // static | 65 // static |
| 68 std::string HttpAuthHandlerDigest::QopToString(int qop) { | 66 std::string HttpAuthHandlerDigest::QopToString(int qop) { |
|
eroman
2010/11/11 23:02:58
I think this function should be changed to either
| |
| 69 switch (qop) { | 67 // qop is a bitmask, so report highest priority one first. |
| 70 case QOP_AUTH: | 68 if (qop & QOP_AUTH_INT) { |
| 71 return "auth"; | 69 return "auth-int"; |
| 72 case QOP_AUTH_INT: | 70 } else if (qop & QOP_AUTH) { |
|
eroman
2010/11/11 23:02:58
style: we avoid "else" when using returns.
As in:
| |
| 73 return "auth-int"; | 71 return "auth"; |
| 74 default: | 72 } else { |
| 75 return ""; | 73 return ""; |
| 76 } | 74 } |
| 77 } | 75 } |
| 78 | 76 |
| 79 // static | 77 // static |
| 80 std::string HttpAuthHandlerDigest::AlgorithmToString(int algorithm) { | 78 std::string HttpAuthHandlerDigest::AlgorithmToString(int algorithm) { |
| 81 switch (algorithm) { | 79 switch (algorithm) { |
| 82 case ALGORITHM_MD5: | 80 case ALGORITHM_MD5: |
| 83 return "MD5"; | 81 return "MD5"; |
| 84 case ALGORITHM_MD5_SESS: | 82 case ALGORITHM_MD5_SESS: |
| 85 return "MD5-sess"; | 83 return "MD5-sess"; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 145 const std::string& cnonce, | 143 const std::string& cnonce, |
| 146 const std::string& nc) const { | 144 const std::string& nc) const { |
| 147 // ha1 = MD5(A1) | 145 // ha1 = MD5(A1) |
| 148 // TODO(eroman): is this the right encoding? | 146 // TODO(eroman): is this the right encoding? |
| 149 std::string ha1 = MD5String(UTF16ToUTF8(username) + ":" + realm_ + ":" + | 147 std::string ha1 = MD5String(UTF16ToUTF8(username) + ":" + realm_ + ":" + |
| 150 UTF16ToUTF8(password)); | 148 UTF16ToUTF8(password)); |
| 151 if (algorithm_ == HttpAuthHandlerDigest::ALGORITHM_MD5_SESS) | 149 if (algorithm_ == HttpAuthHandlerDigest::ALGORITHM_MD5_SESS) |
| 152 ha1 = MD5String(ha1 + ":" + nonce_ + ":" + cnonce); | 150 ha1 = MD5String(ha1 + ":" + nonce_ + ":" + cnonce); |
| 153 | 151 |
| 154 // ha2 = MD5(A2) | 152 // ha2 = MD5(A2) |
| 155 // TODO(eroman): need to add MD5(req-entity-body) for qop=auth-int. | 153 // TODO(eroman): need to add MD5(req-entity-body) for qop=auth-int. |
|
eroman
2010/11/11 23:02:58
Can you add an assertion here that qop is not auth
| |
| 156 std::string ha2 = MD5String(method + ":" + path); | 154 std::string ha2 = MD5String(method + ":" + path); |
| 157 | 155 |
| 158 std::string nc_part; | 156 std::string nc_part; |
| 159 if (qop_ != HttpAuthHandlerDigest::QOP_UNSPECIFIED) { | 157 if (qop_ != HttpAuthHandlerDigest::QOP_UNSPECIFIED) { |
| 160 nc_part = nc + ":" + cnonce + ":" + QopToString(qop_) + ":"; | 158 nc_part = nc + ":" + cnonce + ":" + QopToString(qop_) + ":"; |
| 161 } | 159 } |
| 162 | 160 |
| 163 return MD5String(ha1 + ":" + nonce_ + ":" + nc_part + ha2); | 161 return MD5String(ha1 + ":" + nonce_ + ":" + nc_part + ha2); |
| 164 } | 162 } |
| 165 | 163 |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 302 algorithm_ = ALGORITHM_MD5; | 300 algorithm_ = ALGORITHM_MD5; |
| 303 } else if (LowerCaseEqualsASCII(value, "md5-sess")) { | 301 } else if (LowerCaseEqualsASCII(value, "md5-sess")) { |
| 304 algorithm_ = ALGORITHM_MD5_SESS; | 302 algorithm_ = ALGORITHM_MD5_SESS; |
| 305 } else { | 303 } else { |
| 306 DVLOG(1) << "Unknown value of algorithm"; | 304 DVLOG(1) << "Unknown value of algorithm"; |
| 307 return false; // FAIL -- unsupported value of algorithm. | 305 return false; // FAIL -- unsupported value of algorithm. |
| 308 } | 306 } |
| 309 } else if (LowerCaseEqualsASCII(name, "qop")) { | 307 } else if (LowerCaseEqualsASCII(name, "qop")) { |
| 310 // Parse the comma separated list of qops. | 308 // Parse the comma separated list of qops. |
| 311 HttpUtil::ValuesIterator qop_values(value.begin(), value.end(), ','); | 309 HttpUtil::ValuesIterator qop_values(value.begin(), value.end(), ','); |
| 310 int qop = QOP_UNSPECIFIED; | |
| 312 while (qop_values.GetNext()) { | 311 while (qop_values.GetNext()) { |
| 313 if (LowerCaseEqualsASCII(qop_values.value(), "auth")) { | 312 if (LowerCaseEqualsASCII(qop_values.value(), "auth")) { |
| 314 qop_ |= QOP_AUTH; | 313 qop |= QOP_AUTH; |
| 315 } else if (LowerCaseEqualsASCII(qop_values.value(), "auth-int")) { | 314 } else if (LowerCaseEqualsASCII(qop_values.value(), "auth-int")) { |
| 316 qop_ |= QOP_AUTH_INT; | 315 qop |= QOP_AUTH_INT; |
| 317 } | 316 } |
| 318 } | 317 } |
| 318 // TODO(cbentzel): Since auth-int isn't currently supported, fail | |
| 319 // parsing if it is the only qop option available. | |
| 320 // http://crbug.com/45194 | |
| 321 if (qop == QOP_AUTH_INT) | |
| 322 return false; | |
|
eroman
2010/11/11 23:02:58
I suggest outputting some sort of warning or log m
| |
| 323 qop_ = (qop & ~QOP_AUTH_INT); | |
| 319 } else { | 324 } else { |
| 320 DVLOG(1) << "Skipping unrecognized digest property"; | 325 DVLOG(1) << "Skipping unrecognized digest property"; |
| 321 // TODO(eroman): perhaps we should fail instead of silently skipping? | 326 // TODO(eroman): perhaps we should fail instead of silently skipping? |
| 322 } | 327 } |
| 323 return true; | 328 return true; |
| 324 } | 329 } |
| 325 | 330 |
| 326 HttpAuthHandlerDigest::Factory::Factory() { | 331 HttpAuthHandlerDigest::Factory::Factory() { |
| 327 } | 332 } |
| 328 | 333 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 341 // method and only constructing when valid. | 346 // method and only constructing when valid. |
| 342 scoped_ptr<HttpAuthHandler> tmp_handler( | 347 scoped_ptr<HttpAuthHandler> tmp_handler( |
| 343 new HttpAuthHandlerDigest(digest_nonce_count)); | 348 new HttpAuthHandlerDigest(digest_nonce_count)); |
| 344 if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log)) | 349 if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log)) |
| 345 return ERR_INVALID_RESPONSE; | 350 return ERR_INVALID_RESPONSE; |
| 346 handler->swap(tmp_handler); | 351 handler->swap(tmp_handler); |
| 347 return OK; | 352 return OK; |
| 348 } | 353 } |
| 349 | 354 |
| 350 } // namespace net | 355 } // namespace net |
| OLD | NEW |