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

Side by Side Diff: net/http/http_auth_handler_digest.cc

Issue 6339012: More net/ method ordering. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: More done while waiting for previous patch to clear Created 9 years, 11 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/http/http_auth_handler_digest.h ('k') | net/http/http_auth_handler_mock.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 67
68 HttpAuthHandlerDigest::FixedNonceGenerator::FixedNonceGenerator( 68 HttpAuthHandlerDigest::FixedNonceGenerator::FixedNonceGenerator(
69 const std::string& nonce) 69 const std::string& nonce)
70 : nonce_(nonce) { 70 : nonce_(nonce) {
71 } 71 }
72 72
73 std::string HttpAuthHandlerDigest::FixedNonceGenerator::GenerateNonce() const { 73 std::string HttpAuthHandlerDigest::FixedNonceGenerator::GenerateNonce() const {
74 return nonce_; 74 return nonce_;
75 } 75 }
76 76
77 // static 77 HttpAuthHandlerDigest::Factory::Factory()
78 std::string HttpAuthHandlerDigest::QopToString(QualityOfProtection qop) { 78 : nonce_generator_(new DynamicNonceGenerator()) {
79 switch (qop) {
80 case QOP_UNSPECIFIED:
81 return "";
82 case QOP_AUTH:
83 return "auth";
84 default:
85 NOTREACHED();
86 return "";
87 }
88 } 79 }
89 80
90 // static 81 HttpAuthHandlerDigest::Factory::~Factory() {
91 std::string HttpAuthHandlerDigest::AlgorithmToString(
92 DigestAlgorithm algorithm) {
93 switch (algorithm) {
94 case ALGORITHM_UNSPECIFIED:
95 return "";
96 case ALGORITHM_MD5:
97 return "MD5";
98 case ALGORITHM_MD5_SESS:
99 return "MD5-sess";
100 default:
101 NOTREACHED();
102 return "";
103 }
104 } 82 }
105 83
106 HttpAuthHandlerDigest::HttpAuthHandlerDigest( 84 void HttpAuthHandlerDigest::Factory::set_nonce_generator(
107 int nonce_count, const NonceGenerator* nonce_generator) 85 const NonceGenerator* nonce_generator) {
108 : stale_(false), 86 nonce_generator_.reset(nonce_generator);
109 algorithm_(ALGORITHM_UNSPECIFIED),
110 qop_(QOP_UNSPECIFIED),
111 nonce_count_(nonce_count),
112 nonce_generator_(nonce_generator) {
113 DCHECK(nonce_generator_);
114 } 87 }
115 88
116 HttpAuthHandlerDigest::~HttpAuthHandlerDigest() { 89 int HttpAuthHandlerDigest::Factory::CreateAuthHandler(
90 HttpAuth::ChallengeTokenizer* challenge,
91 HttpAuth::Target target,
92 const GURL& origin,
93 CreateReason reason,
94 int digest_nonce_count,
95 const BoundNetLog& net_log,
96 scoped_ptr<HttpAuthHandler>* handler) {
97 // TODO(cbentzel): Move towards model of parsing in the factory
98 // method and only constructing when valid.
99 scoped_ptr<HttpAuthHandler> tmp_handler(
100 new HttpAuthHandlerDigest(digest_nonce_count, nonce_generator_.get()));
101 if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log))
102 return ERR_INVALID_RESPONSE;
103 handler->swap(tmp_handler);
104 return OK;
105 }
106
107 HttpAuth::AuthorizationResult HttpAuthHandlerDigest::HandleAnotherChallenge(
108 HttpAuth::ChallengeTokenizer* challenge) {
109 // Even though Digest is not connection based, a "second round" is parsed
110 // to differentiate between stale and rejected responses.
111 // Note that the state of the current handler is not mutated - this way if
112 // there is a rejection the realm hasn't changed.
113 if (!LowerCaseEqualsASCII(challenge->scheme(), "digest"))
114 return HttpAuth::AUTHORIZATION_RESULT_INVALID;
115
116 HttpUtil::NameValuePairsIterator parameters = challenge->param_pairs();
117
118 // Try to find the "stale" value.
119 while (parameters.GetNext()) {
120 if (!LowerCaseEqualsASCII(parameters.name(), "stale"))
121 continue;
122 if (LowerCaseEqualsASCII(parameters.value(), "true"))
123 return HttpAuth::AUTHORIZATION_RESULT_STALE;
124 }
125
126 return HttpAuth::AUTHORIZATION_RESULT_REJECT;
127 }
128
129 bool HttpAuthHandlerDigest::Init(HttpAuth::ChallengeTokenizer* challenge) {
130 return ParseChallenge(challenge);
117 } 131 }
118 132
119 int HttpAuthHandlerDigest::GenerateAuthTokenImpl( 133 int HttpAuthHandlerDigest::GenerateAuthTokenImpl(
120 const string16* username, 134 const string16* username,
121 const string16* password, 135 const string16* password,
122 const HttpRequestInfo* request, 136 const HttpRequestInfo* request,
123 CompletionCallback* callback, 137 CompletionCallback* callback,
124 std::string* auth_token) { 138 std::string* auth_token) {
125 // Generate a random client nonce. 139 // Generate a random client nonce.
126 std::string cnonce = nonce_generator_->GenerateNonce(); 140 std::string cnonce = nonce_generator_->GenerateNonce();
127 141
128 // Extract the request method and path -- the meaning of 'path' is overloaded 142 // Extract the request method and path -- the meaning of 'path' is overloaded
129 // in certain cases, to be a hostname. 143 // in certain cases, to be a hostname.
130 std::string method; 144 std::string method;
131 std::string path; 145 std::string path;
132 GetRequestMethodAndPath(request, &method, &path); 146 GetRequestMethodAndPath(request, &method, &path);
133 147
134 *auth_token = AssembleCredentials(method, path, 148 *auth_token = AssembleCredentials(method, path,
135 *username, 149 *username,
136 *password, 150 *password,
137 cnonce, nonce_count_); 151 cnonce, nonce_count_);
138 return OK; 152 return OK;
139 } 153 }
140 154
141 void HttpAuthHandlerDigest::GetRequestMethodAndPath( 155 HttpAuthHandlerDigest::HttpAuthHandlerDigest(
142 const HttpRequestInfo* request, 156 int nonce_count, const NonceGenerator* nonce_generator)
143 std::string* method, 157 : stale_(false),
144 std::string* path) const { 158 algorithm_(ALGORITHM_UNSPECIFIED),
145 DCHECK(request); 159 qop_(QOP_UNSPECIFIED),
146 160 nonce_count_(nonce_count),
147 const GURL& url = request->url; 161 nonce_generator_(nonce_generator) {
148 162 DCHECK(nonce_generator_);
149 if (target_ == HttpAuth::AUTH_PROXY && url.SchemeIs("https")) {
150 *method = "CONNECT";
151 *path = GetHostAndPort(url);
152 } else {
153 *method = request->method;
154 *path = HttpUtil::PathForRequest(url);
155 }
156 } 163 }
157 164
158 std::string HttpAuthHandlerDigest::AssembleResponseDigest( 165 HttpAuthHandlerDigest::~HttpAuthHandlerDigest() {
159 const std::string& method,
160 const std::string& path,
161 const string16& username,
162 const string16& password,
163 const std::string& cnonce,
164 const std::string& nc) const {
165 // ha1 = MD5(A1)
166 // TODO(eroman): is this the right encoding?
167 std::string ha1 = MD5String(UTF16ToUTF8(username) + ":" + realm_ + ":" +
168 UTF16ToUTF8(password));
169 if (algorithm_ == HttpAuthHandlerDigest::ALGORITHM_MD5_SESS)
170 ha1 = MD5String(ha1 + ":" + nonce_ + ":" + cnonce);
171
172 // ha2 = MD5(A2)
173 // TODO(eroman): need to add MD5(req-entity-body) for qop=auth-int.
174 std::string ha2 = MD5String(method + ":" + path);
175
176 std::string nc_part;
177 if (qop_ != HttpAuthHandlerDigest::QOP_UNSPECIFIED) {
178 nc_part = nc + ":" + cnonce + ":" + QopToString(qop_) + ":";
179 }
180
181 return MD5String(ha1 + ":" + nonce_ + ":" + nc_part + ha2);
182 }
183
184 std::string HttpAuthHandlerDigest::AssembleCredentials(
185 const std::string& method,
186 const std::string& path,
187 const string16& username,
188 const string16& password,
189 const std::string& cnonce,
190 int nonce_count) const {
191 // the nonce-count is an 8 digit hex string.
192 std::string nc = base::StringPrintf("%08x", nonce_count);
193
194 // TODO(eroman): is this the right encoding?
195 std::string authorization = (std::string("Digest username=") +
196 HttpUtil::Quote(UTF16ToUTF8(username)));
197 authorization += ", realm=" + HttpUtil::Quote(realm_);
198 authorization += ", nonce=" + HttpUtil::Quote(nonce_);
199 authorization += ", uri=" + HttpUtil::Quote(path);
200
201 if (algorithm_ != ALGORITHM_UNSPECIFIED) {
202 authorization += ", algorithm=" + AlgorithmToString(algorithm_);
203 }
204 std::string response = AssembleResponseDigest(method, path, username,
205 password, cnonce, nc);
206 // No need to call HttpUtil::Quote() as the response digest cannot contain
207 // any characters needing to be escaped.
208 authorization += ", response=\"" + response + "\"";
209
210 if (!opaque_.empty()) {
211 authorization += ", opaque=" + HttpUtil::Quote(opaque_);
212 }
213 if (qop_ != QOP_UNSPECIFIED) {
214 // TODO(eroman): Supposedly IIS server requires quotes surrounding qop.
215 authorization += ", qop=" + QopToString(qop_);
216 authorization += ", nc=" + nc;
217 authorization += ", cnonce=" + HttpUtil::Quote(cnonce);
218 }
219
220 return authorization;
221 }
222
223 bool HttpAuthHandlerDigest::Init(HttpAuth::ChallengeTokenizer* challenge) {
224 return ParseChallenge(challenge);
225 }
226
227 HttpAuth::AuthorizationResult HttpAuthHandlerDigest::HandleAnotherChallenge(
228 HttpAuth::ChallengeTokenizer* challenge) {
229 // Even though Digest is not connection based, a "second round" is parsed
230 // to differentiate between stale and rejected responses.
231 // Note that the state of the current handler is not mutated - this way if
232 // there is a rejection the realm hasn't changed.
233 if (!LowerCaseEqualsASCII(challenge->scheme(), "digest"))
234 return HttpAuth::AUTHORIZATION_RESULT_INVALID;
235
236 HttpUtil::NameValuePairsIterator parameters = challenge->param_pairs();
237
238 // Try to find the "stale" value.
239 while (parameters.GetNext()) {
240 if (!LowerCaseEqualsASCII(parameters.name(), "stale"))
241 continue;
242 if (LowerCaseEqualsASCII(parameters.value(), "true"))
243 return HttpAuth::AUTHORIZATION_RESULT_STALE;
244 }
245
246 return HttpAuth::AUTHORIZATION_RESULT_REJECT;
247 } 166 }
248 167
249 // The digest challenge header looks like: 168 // The digest challenge header looks like:
250 // WWW-Authenticate: Digest 169 // WWW-Authenticate: Digest
251 // [realm="<realm-value>"] 170 // [realm="<realm-value>"]
252 // nonce="<nonce-value>" 171 // nonce="<nonce-value>"
253 // [domain="<list-of-URIs>"] 172 // [domain="<list-of-URIs>"]
254 // [opaque="<opaque-token-value>"] 173 // [opaque="<opaque-token-value>"]
255 // [stale="<true-or-false>"] 174 // [stale="<true-or-false>"]
256 // [algorithm="<digest-algorithm>"] 175 // [algorithm="<digest-algorithm>"]
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 break; 254 break;
336 } 255 }
337 } 256 }
338 } else { 257 } else {
339 DVLOG(1) << "Skipping unrecognized digest property"; 258 DVLOG(1) << "Skipping unrecognized digest property";
340 // TODO(eroman): perhaps we should fail instead of silently skipping? 259 // TODO(eroman): perhaps we should fail instead of silently skipping?
341 } 260 }
342 return true; 261 return true;
343 } 262 }
344 263
345 HttpAuthHandlerDigest::Factory::Factory() 264 // static
346 : nonce_generator_(new DynamicNonceGenerator()) { 265 std::string HttpAuthHandlerDigest::QopToString(QualityOfProtection qop) {
266 switch (qop) {
267 case QOP_UNSPECIFIED:
268 return "";
269 case QOP_AUTH:
270 return "auth";
271 default:
272 NOTREACHED();
273 return "";
274 }
347 } 275 }
348 276
349 HttpAuthHandlerDigest::Factory::~Factory() { 277 // static
278 std::string HttpAuthHandlerDigest::AlgorithmToString(
279 DigestAlgorithm algorithm) {
280 switch (algorithm) {
281 case ALGORITHM_UNSPECIFIED:
282 return "";
283 case ALGORITHM_MD5:
284 return "MD5";
285 case ALGORITHM_MD5_SESS:
286 return "MD5-sess";
287 default:
288 NOTREACHED();
289 return "";
290 }
350 } 291 }
351 292
352 void HttpAuthHandlerDigest::Factory::set_nonce_generator( 293 void HttpAuthHandlerDigest::GetRequestMethodAndPath(
353 const NonceGenerator* nonce_generator) { 294 const HttpRequestInfo* request,
354 nonce_generator_.reset(nonce_generator); 295 std::string* method,
296 std::string* path) const {
297 DCHECK(request);
298
299 const GURL& url = request->url;
300
301 if (target_ == HttpAuth::AUTH_PROXY && url.SchemeIs("https")) {
302 *method = "CONNECT";
303 *path = GetHostAndPort(url);
304 } else {
305 *method = request->method;
306 *path = HttpUtil::PathForRequest(url);
307 }
355 } 308 }
356 309
357 int HttpAuthHandlerDigest::Factory::CreateAuthHandler( 310 std::string HttpAuthHandlerDigest::AssembleResponseDigest(
358 HttpAuth::ChallengeTokenizer* challenge, 311 const std::string& method,
359 HttpAuth::Target target, 312 const std::string& path,
360 const GURL& origin, 313 const string16& username,
361 CreateReason reason, 314 const string16& password,
362 int digest_nonce_count, 315 const std::string& cnonce,
363 const BoundNetLog& net_log, 316 const std::string& nc) const {
364 scoped_ptr<HttpAuthHandler>* handler) { 317 // ha1 = MD5(A1)
365 // TODO(cbentzel): Move towards model of parsing in the factory 318 // TODO(eroman): is this the right encoding?
366 // method and only constructing when valid. 319 std::string ha1 = MD5String(UTF16ToUTF8(username) + ":" + realm_ + ":" +
367 scoped_ptr<HttpAuthHandler> tmp_handler( 320 UTF16ToUTF8(password));
368 new HttpAuthHandlerDigest(digest_nonce_count, nonce_generator_.get())); 321 if (algorithm_ == HttpAuthHandlerDigest::ALGORITHM_MD5_SESS)
369 if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log)) 322 ha1 = MD5String(ha1 + ":" + nonce_ + ":" + cnonce);
370 return ERR_INVALID_RESPONSE; 323
371 handler->swap(tmp_handler); 324 // ha2 = MD5(A2)
372 return OK; 325 // TODO(eroman): need to add MD5(req-entity-body) for qop=auth-int.
326 std::string ha2 = MD5String(method + ":" + path);
327
328 std::string nc_part;
329 if (qop_ != HttpAuthHandlerDigest::QOP_UNSPECIFIED) {
330 nc_part = nc + ":" + cnonce + ":" + QopToString(qop_) + ":";
331 }
332
333 return MD5String(ha1 + ":" + nonce_ + ":" + nc_part + ha2);
334 }
335
336 std::string HttpAuthHandlerDigest::AssembleCredentials(
337 const std::string& method,
338 const std::string& path,
339 const string16& username,
340 const string16& password,
341 const std::string& cnonce,
342 int nonce_count) const {
343 // the nonce-count is an 8 digit hex string.
344 std::string nc = base::StringPrintf("%08x", nonce_count);
345
346 // TODO(eroman): is this the right encoding?
347 std::string authorization = (std::string("Digest username=") +
348 HttpUtil::Quote(UTF16ToUTF8(username)));
349 authorization += ", realm=" + HttpUtil::Quote(realm_);
350 authorization += ", nonce=" + HttpUtil::Quote(nonce_);
351 authorization += ", uri=" + HttpUtil::Quote(path);
352
353 if (algorithm_ != ALGORITHM_UNSPECIFIED) {
354 authorization += ", algorithm=" + AlgorithmToString(algorithm_);
355 }
356 std::string response = AssembleResponseDigest(method, path, username,
357 password, cnonce, nc);
358 // No need to call HttpUtil::Quote() as the response digest cannot contain
359 // any characters needing to be escaped.
360 authorization += ", response=\"" + response + "\"";
361
362 if (!opaque_.empty()) {
363 authorization += ", opaque=" + HttpUtil::Quote(opaque_);
364 }
365 if (qop_ != QOP_UNSPECIFIED) {
366 // TODO(eroman): Supposedly IIS server requires quotes surrounding qop.
367 authorization += ", qop=" + QopToString(qop_);
368 authorization += ", nc=" + nc;
369 authorization += ", cnonce=" + HttpUtil::Quote(cnonce);
370 }
371
372 return authorization;
373 } 373 }
374 374
375 } // namespace net 375 } // namespace net
OLDNEW
« no previous file with comments | « net/http/http_auth_handler_digest.h ('k') | net/http/http_auth_handler_mock.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698