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 |