| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
| 13 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
| 14 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
| 15 #include "net/base/net_errors.h" | 15 #include "net/base/net_errors.h" |
| 16 #include "net/base/net_string_util.h" | 16 #include "net/base/net_string_util.h" |
| 17 #include "net/base/net_util.h" | 17 #include "net/base/net_util.h" |
| 18 #include "net/http/http_auth.h" | 18 #include "net/http/http_auth.h" |
| 19 #include "net/http/http_auth_challenge_tokenizer.h" | 19 #include "net/http/http_auth_challenge_tokenizer.h" |
| 20 #include "net/http/http_request_info.h" | 20 #include "net/http/http_request_info.h" |
| 21 #include "net/http/http_util.h" | 21 #include "net/http/http_util.h" |
| 22 #include "url/gurl.h" | 22 #include "url/gurl.h" |
| 23 | 23 |
| 24 namespace net { | 24 namespace net { |
| 25 | 25 |
| 26 static const char* const kDigestSchemeName = "digest"; | 26 static const char kDigestSchemeName[] = "digest"; |
| 27 | 27 |
| 28 // Digest authentication is specified in RFC 2617. | 28 // Digest authentication is specified in RFC 2617. |
| 29 // The expanded derivations are listed in the tables below. | 29 // The expanded derivations are listed in the tables below. |
| 30 | 30 |
| 31 //==========+==========+==========================================+ | 31 //==========+==========+==========================================+ |
| 32 // qop |algorithm | response | | 32 // qop |algorithm | response | |
| 33 //==========+==========+==========================================+ | 33 //==========+==========+==========================================+ |
| 34 // ? | ?, md5, | MD5(MD5(A1):nonce:MD5(A2)) | | 34 // ? | ?, md5, | MD5(MD5(A1):nonce:MD5(A2)) | |
| 35 // | md5-sess | | | 35 // | md5-sess | | |
| 36 //--------- +----------+------------------------------------------+ | 36 //--------- +----------+------------------------------------------+ |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 | 72 |
| 73 HttpAuthHandlerDigest::FixedNonceGenerator::FixedNonceGenerator( | 73 HttpAuthHandlerDigest::FixedNonceGenerator::FixedNonceGenerator( |
| 74 const std::string& nonce) | 74 const std::string& nonce) |
| 75 : nonce_(nonce) { | 75 : nonce_(nonce) { |
| 76 } | 76 } |
| 77 | 77 |
| 78 std::string HttpAuthHandlerDigest::FixedNonceGenerator::GenerateNonce() const { | 78 std::string HttpAuthHandlerDigest::FixedNonceGenerator::GenerateNonce() const { |
| 79 return nonce_; | 79 return nonce_; |
| 80 } | 80 } |
| 81 | 81 |
| 82 HttpAuthHandlerDigest::Factory::Factory() | |
| 83 : nonce_generator_(new DynamicNonceGenerator()) { | |
| 84 } | |
| 85 | |
| 86 HttpAuthHandlerDigest::Factory::~Factory() { | |
| 87 } | |
| 88 | |
| 89 void HttpAuthHandlerDigest::Factory::set_nonce_generator( | |
| 90 const NonceGenerator* nonce_generator) { | |
| 91 nonce_generator_.reset(nonce_generator); | |
| 92 } | |
| 93 | |
| 94 int HttpAuthHandlerDigest::Factory::CreateAuthHandler( | |
| 95 const HttpAuthChallengeTokenizer& challenge, | |
| 96 HttpAuth::Target target, | |
| 97 const GURL& origin, | |
| 98 CreateReason reason, | |
| 99 int digest_nonce_count, | |
| 100 const BoundNetLog& net_log, | |
| 101 scoped_ptr<HttpAuthHandler>* handler) { | |
| 102 // TODO(cbentzel): Move towards model of parsing in the factory | |
| 103 // method and only constructing when valid. | |
| 104 scoped_ptr<HttpAuthHandler> tmp_handler( | |
| 105 new HttpAuthHandlerDigest(digest_nonce_count, nonce_generator_.get())); | |
| 106 int result = | |
| 107 tmp_handler->HandleInitialChallenge(challenge, target, origin, net_log); | |
| 108 if (result == OK) | |
| 109 handler->swap(tmp_handler); | |
| 110 return result; | |
| 111 } | |
| 112 | |
| 113 HttpAuth::AuthorizationResult HttpAuthHandlerDigest::HandleAnotherChallenge( | 82 HttpAuth::AuthorizationResult HttpAuthHandlerDigest::HandleAnotherChallenge( |
| 114 const HttpAuthChallengeTokenizer& challenge) { | 83 const HttpAuthChallengeTokenizer& challenge) { |
| 115 // Even though Digest is not connection based, a "second round" is parsed | 84 // Even though Digest is not connection based, a "second round" is parsed |
| 116 // to differentiate between stale and rejected responses. | 85 // to differentiate between stale and rejected responses. |
| 117 // Note that the state of the current handler is not mutated - this way if | 86 // Note that the state of the current handler is not mutated - this way if |
| 118 // there is a rejection the realm hasn't changed. | 87 // there is a rejection the realm hasn't changed. |
| 119 if (!challenge.SchemeIs(kDigestSchemeName)) | 88 if (!challenge.SchemeIs(kDigestSchemeName)) |
| 120 return HttpAuth::AUTHORIZATION_RESULT_INVALID; | 89 return HttpAuth::AUTHORIZATION_RESULT_INVALID; |
| 121 | 90 |
| 122 HttpUtil::NameValuePairsIterator parameters = challenge.param_pairs(); | 91 HttpUtil::NameValuePairsIterator parameters = challenge.param_pairs(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 std::string method; | 123 std::string method; |
| 155 std::string path; | 124 std::string path; |
| 156 GetRequestMethodAndPath(request, &method, &path); | 125 GetRequestMethodAndPath(request, &method, &path); |
| 157 | 126 |
| 158 *auth_token = AssembleCredentials(method, path, *credentials, | 127 *auth_token = AssembleCredentials(method, path, *credentials, |
| 159 cnonce, nonce_count_); | 128 cnonce, nonce_count_); |
| 160 return OK; | 129 return OK; |
| 161 } | 130 } |
| 162 | 131 |
| 163 HttpAuthHandlerDigest::HttpAuthHandlerDigest( | 132 HttpAuthHandlerDigest::HttpAuthHandlerDigest( |
| 164 int nonce_count, const NonceGenerator* nonce_generator) | 133 int nonce_count, |
| 165 : stale_(false), | 134 const NonceGenerator* nonce_generator) |
| 135 : HttpAuthHandler(kDigestSchemeName), |
| 136 stale_(false), |
| 166 algorithm_(ALGORITHM_UNSPECIFIED), | 137 algorithm_(ALGORITHM_UNSPECIFIED), |
| 167 qop_(QOP_UNSPECIFIED), | 138 qop_(QOP_UNSPECIFIED), |
| 168 nonce_count_(nonce_count), | 139 nonce_count_(nonce_count), |
| 169 nonce_generator_(nonce_generator) { | 140 nonce_generator_(nonce_generator) { |
| 170 DCHECK(nonce_generator_); | 141 DCHECK(nonce_generator_); |
| 171 } | 142 } |
| 172 | 143 |
| 173 HttpAuthHandlerDigest::~HttpAuthHandlerDigest() { | 144 HttpAuthHandlerDigest::~HttpAuthHandlerDigest() { |
| 174 } | 145 } |
| 175 | 146 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 186 // | 157 // |
| 187 // Note that according to RFC 2617 (section 1.2) the realm is required. | 158 // Note that according to RFC 2617 (section 1.2) the realm is required. |
| 188 // However we allow it to be omitted, in which case it will default to the | 159 // However we allow it to be omitted, in which case it will default to the |
| 189 // empty string. | 160 // empty string. |
| 190 // | 161 // |
| 191 // This allowance is for better compatibility with webservers that fail to | 162 // This allowance is for better compatibility with webservers that fail to |
| 192 // send the realm (See http://crbug.com/20984 for an instance where a | 163 // send the realm (See http://crbug.com/20984 for an instance where a |
| 193 // webserver was not sending the realm with a BASIC challenge). | 164 // webserver was not sending the realm with a BASIC challenge). |
| 194 bool HttpAuthHandlerDigest::ParseChallenge( | 165 bool HttpAuthHandlerDigest::ParseChallenge( |
| 195 const HttpAuthChallengeTokenizer& challenge) { | 166 const HttpAuthChallengeTokenizer& challenge) { |
| 196 auth_scheme_ = kDigestSchemeName; | 167 // FAIL -- Couldn't match auth-scheme. |
| 168 if (!challenge.SchemeIs(kDigestSchemeName)) |
| 169 return false; |
| 197 | 170 |
| 198 // Initialize to defaults. | 171 // Initialize to defaults. |
| 199 stale_ = false; | 172 stale_ = false; |
| 200 algorithm_ = ALGORITHM_UNSPECIFIED; | 173 algorithm_ = ALGORITHM_UNSPECIFIED; |
| 201 qop_ = QOP_UNSPECIFIED; | 174 qop_ = QOP_UNSPECIFIED; |
| 202 realm_ = original_realm_ = nonce_ = domain_ = opaque_ = std::string(); | 175 realm_ = original_realm_ = nonce_ = domain_ = opaque_ = std::string(); |
| 203 | 176 |
| 204 // FAIL -- Couldn't match auth-scheme. | |
| 205 if (!challenge.SchemeIs(kDigestSchemeName)) | |
| 206 return false; | |
| 207 | |
| 208 HttpUtil::NameValuePairsIterator parameters = challenge.param_pairs(); | 177 HttpUtil::NameValuePairsIterator parameters = challenge.param_pairs(); |
| 209 | 178 |
| 210 // Loop through all the properties. | 179 // Loop through all the properties. |
| 211 while (parameters.GetNext()) { | 180 while (parameters.GetNext()) { |
| 212 // FAIL -- couldn't parse a property. | 181 // FAIL -- couldn't parse a property. |
| 213 if (!ParseChallengeProperty(parameters.name(), | 182 if (!ParseChallengeProperty(parameters.name(), |
| 214 parameters.value())) | 183 parameters.value())) |
| 215 return false; | 184 return false; |
| 216 } | 185 } |
| 217 | 186 |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 374 if (qop_ != QOP_UNSPECIFIED) { | 343 if (qop_ != QOP_UNSPECIFIED) { |
| 375 // TODO(eroman): Supposedly IIS server requires quotes surrounding qop. | 344 // TODO(eroman): Supposedly IIS server requires quotes surrounding qop. |
| 376 authorization += ", qop=" + QopToString(qop_); | 345 authorization += ", qop=" + QopToString(qop_); |
| 377 authorization += ", nc=" + nc; | 346 authorization += ", nc=" + nc; |
| 378 authorization += ", cnonce=" + HttpUtil::Quote(cnonce); | 347 authorization += ", cnonce=" + HttpUtil::Quote(cnonce); |
| 379 } | 348 } |
| 380 | 349 |
| 381 return authorization; | 350 return authorization; |
| 382 } | 351 } |
| 383 | 352 |
| 353 HttpAuthHandlerDigest::Factory::Factory() |
| 354 : nonce_generator_(new DynamicNonceGenerator()) {} |
| 355 |
| 356 HttpAuthHandlerDigest::Factory::~Factory() {} |
| 357 |
| 358 void HttpAuthHandlerDigest::Factory::set_nonce_generator( |
| 359 const NonceGenerator* nonce_generator) { |
| 360 nonce_generator_.reset(nonce_generator); |
| 361 } |
| 362 |
| 363 scoped_ptr<HttpAuthHandler> |
| 364 HttpAuthHandlerDigest::Factory::CreateAuthHandlerForScheme( |
| 365 const std::string& scheme) { |
| 366 DCHECK(HttpAuth::IsValidNormalizedScheme(scheme)); |
| 367 if (scheme != kDigestSchemeName) |
| 368 return scoped_ptr<HttpAuthHandler>(); |
| 369 return make_scoped_ptr(new HttpAuthHandlerDigest(1, nonce_generator_.get())); |
| 370 } |
| 371 |
| 372 scoped_ptr<HttpAuthHandler> |
| 373 HttpAuthHandlerDigest::Factory::CreateAndInitPreemptiveAuthHandler( |
| 374 HttpAuthCache::Entry* cache_entry, |
| 375 const HttpAuthChallengeTokenizer& tokenizer, |
| 376 HttpAuth::Target target, |
| 377 const BoundNetLog& net_log) { |
| 378 if (cache_entry->scheme() != kDigestSchemeName) |
| 379 return scoped_ptr<HttpAuthHandler>(); |
| 380 scoped_ptr<HttpAuthHandler> handler(new HttpAuthHandlerDigest( |
| 381 cache_entry->IncrementNonceCount(), nonce_generator_.get())); |
| 382 int rv = handler->HandleInitialChallenge(tokenizer, target, |
| 383 cache_entry->origin(), net_log); |
| 384 if (rv == OK) |
| 385 return handler; |
| 386 return scoped_ptr<HttpAuthHandler>(); |
| 387 } |
| 388 |
| 384 } // namespace net | 389 } // namespace net |
| OLD | NEW |