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_controller.h" | 5 #include "net/http/http_auth_controller.h" |
6 | 6 |
7 #include "base/metrics/histogram.h" | 7 #include "base/metrics/histogram.h" |
8 #include "base/string_util.h" | 8 #include "base/string_util.h" |
9 #include "base/threading/platform_thread.h" | 9 #include "base/threading/platform_thread.h" |
10 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 user_callback_ = NULL; | 172 user_callback_ = NULL; |
173 } | 173 } |
174 | 174 |
175 int HttpAuthController::MaybeGenerateAuthToken(const HttpRequestInfo* request, | 175 int HttpAuthController::MaybeGenerateAuthToken(const HttpRequestInfo* request, |
176 OldCompletionCallback* callback, | 176 OldCompletionCallback* callback, |
177 const BoundNetLog& net_log) { | 177 const BoundNetLog& net_log) { |
178 DCHECK(CalledOnValidThread()); | 178 DCHECK(CalledOnValidThread()); |
179 bool needs_auth = HaveAuth() || SelectPreemptiveAuth(net_log); | 179 bool needs_auth = HaveAuth() || SelectPreemptiveAuth(net_log); |
180 if (!needs_auth) | 180 if (!needs_auth) |
181 return OK; | 181 return OK; |
182 const string16* username = NULL; | 182 const AuthCredentials* credentials = NULL; |
183 const string16* password = NULL; | 183 if (identity_.source != HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS) |
184 if (identity_.source != HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS) { | 184 credentials = &identity_.credentials; |
185 username = &identity_.username; | |
186 password = &identity_.password; | |
187 } | |
188 DCHECK(auth_token_.empty()); | 185 DCHECK(auth_token_.empty()); |
189 DCHECK(NULL == user_callback_); | 186 DCHECK(NULL == user_callback_); |
190 int rv = handler_->GenerateAuthToken(username, | 187 int rv = handler_->GenerateAuthToken(credentials, |
191 password, | |
192 request, | 188 request, |
193 &io_callback_, | 189 &io_callback_, |
194 &auth_token_); | 190 &auth_token_); |
195 if (DisableOnAuthHandlerResult(rv)) | 191 if (DisableOnAuthHandlerResult(rv)) |
196 rv = OK; | 192 rv = OK; |
197 if (rv == ERR_IO_PENDING) | 193 if (rv == ERR_IO_PENDING) |
198 user_callback_ = callback; | 194 user_callback_ = callback; |
199 else | 195 else |
200 OnIOComplete(rv); | 196 OnIOComplete(rv); |
201 return rv; | 197 return rv; |
(...skipping 24 matching lines...) Expand all Loading... |
226 CreatePreemptiveAuthHandlerFromString(entry->auth_challenge(), target_, | 222 CreatePreemptiveAuthHandlerFromString(entry->auth_challenge(), target_, |
227 auth_origin_, | 223 auth_origin_, |
228 entry->IncrementNonceCount(), | 224 entry->IncrementNonceCount(), |
229 net_log, &handler_preemptive); | 225 net_log, &handler_preemptive); |
230 if (rv_create != OK) | 226 if (rv_create != OK) |
231 return false; | 227 return false; |
232 | 228 |
233 // Set the state | 229 // Set the state |
234 identity_.source = HttpAuth::IDENT_SRC_PATH_LOOKUP; | 230 identity_.source = HttpAuth::IDENT_SRC_PATH_LOOKUP; |
235 identity_.invalid = false; | 231 identity_.invalid = false; |
236 identity_.username = entry->username(); | 232 identity_.credentials = entry->credentials(); |
237 identity_.password = entry->password(); | |
238 handler_.swap(handler_preemptive); | 233 handler_.swap(handler_preemptive); |
239 return true; | 234 return true; |
240 } | 235 } |
241 | 236 |
242 void HttpAuthController::AddAuthorizationHeader( | 237 void HttpAuthController::AddAuthorizationHeader( |
243 HttpRequestHeaders* authorization_headers) { | 238 HttpRequestHeaders* authorization_headers) { |
244 DCHECK(CalledOnValidThread()); | 239 DCHECK(CalledOnValidThread()); |
245 DCHECK(HaveAuth()); | 240 DCHECK(HaveAuth()); |
246 // auth_token_ can be empty if we encountered a permanent error with | 241 // auth_token_ can be empty if we encountered a permanent error with |
247 // the auth scheme and want to retry. | 242 // the auth scheme and want to retry. |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
374 | 369 |
375 // If we get here and we don't have a handler_, that's because we | 370 // If we get here and we don't have a handler_, that's because we |
376 // invalidated it due to not having any viable identities to use with it. Go | 371 // invalidated it due to not having any viable identities to use with it. Go |
377 // back and try again. | 372 // back and try again. |
378 // TODO(asanka): Instead we should create a priority list of | 373 // TODO(asanka): Instead we should create a priority list of |
379 // <handler,identity> and iterate through that. | 374 // <handler,identity> and iterate through that. |
380 } while(!handler_.get()); | 375 } while(!handler_.get()); |
381 return OK; | 376 return OK; |
382 } | 377 } |
383 | 378 |
384 void HttpAuthController::ResetAuth(const string16& username, | 379 void HttpAuthController::ResetAuth(const AuthCredentials& credentials) { |
385 const string16& password) { | |
386 DCHECK(CalledOnValidThread()); | 380 DCHECK(CalledOnValidThread()); |
387 DCHECK(identity_.invalid || (username.empty() && password.empty())); | 381 DCHECK(identity_.invalid || credentials.Empty()); |
388 | 382 |
389 if (identity_.invalid) { | 383 if (identity_.invalid) { |
390 // Update the username/password. | 384 // Update the username/password. |
391 identity_.source = HttpAuth::IDENT_SRC_EXTERNAL; | 385 identity_.source = HttpAuth::IDENT_SRC_EXTERNAL; |
392 identity_.invalid = false; | 386 identity_.invalid = false; |
393 identity_.username = username; | 387 identity_.credentials = credentials; |
394 identity_.password = password; | |
395 } | 388 } |
396 | 389 |
397 DCHECK(identity_.source != HttpAuth::IDENT_SRC_PATH_LOOKUP); | 390 DCHECK(identity_.source != HttpAuth::IDENT_SRC_PATH_LOOKUP); |
398 | 391 |
399 // Add the auth entry to the cache before restarting. We don't know whether | 392 // Add the auth entry to the cache before restarting. We don't know whether |
400 // the identity is valid yet, but if it is valid we want other transactions | 393 // the identity is valid yet, but if it is valid we want other transactions |
401 // to know about it. If an entry for (origin, handler->realm()) already | 394 // to know about it. If an entry for (origin, handler->realm()) already |
402 // exists, we update it. | 395 // exists, we update it. |
403 // | 396 // |
404 // If identity_.source is HttpAuth::IDENT_SRC_NONE or | 397 // If identity_.source is HttpAuth::IDENT_SRC_NONE or |
405 // HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS, identity_ contains no | 398 // HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS, identity_ contains no |
406 // identity because identity is not required yet or we're using default | 399 // identity because identity is not required yet or we're using default |
407 // credentials. | 400 // credentials. |
408 // | 401 // |
409 // TODO(wtc): For NTLM_SSPI, we add the same auth entry to the cache in | 402 // TODO(wtc): For NTLM_SSPI, we add the same auth entry to the cache in |
410 // round 1 and round 2, which is redundant but correct. It would be nice | 403 // round 1 and round 2, which is redundant but correct. It would be nice |
411 // to add an auth entry to the cache only once, preferrably in round 1. | 404 // to add an auth entry to the cache only once, preferrably in round 1. |
412 // See http://crbug.com/21015. | 405 // See http://crbug.com/21015. |
413 switch (identity_.source) { | 406 switch (identity_.source) { |
414 case HttpAuth::IDENT_SRC_NONE: | 407 case HttpAuth::IDENT_SRC_NONE: |
415 case HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS: | 408 case HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS: |
416 break; | 409 break; |
417 default: | 410 default: |
418 http_auth_cache_->Add(auth_origin_, handler_->realm(), | 411 http_auth_cache_->Add(auth_origin_, handler_->realm(), |
419 handler_->auth_scheme(), handler_->challenge(), | 412 handler_->auth_scheme(), handler_->challenge(), |
420 identity_.username, identity_.password, | 413 identity_.credentials, auth_path_); |
421 auth_path_); | |
422 break; | 414 break; |
423 } | 415 } |
424 } | 416 } |
425 | 417 |
426 bool HttpAuthController::HaveAuthHandler() const { | 418 bool HttpAuthController::HaveAuthHandler() const { |
427 return handler_.get() != NULL; | 419 return handler_.get() != NULL; |
428 } | 420 } |
429 | 421 |
430 bool HttpAuthController::HaveAuth() const { | 422 bool HttpAuthController::HaveAuth() const { |
431 return handler_.get() && !identity_.invalid; | 423 return handler_.get() && !identity_.invalid; |
(...skipping 13 matching lines...) Expand all Loading... |
445 } | 437 } |
446 | 438 |
447 void HttpAuthController::InvalidateRejectedAuthFromCache() { | 439 void HttpAuthController::InvalidateRejectedAuthFromCache() { |
448 DCHECK(CalledOnValidThread()); | 440 DCHECK(CalledOnValidThread()); |
449 DCHECK(HaveAuth()); | 441 DCHECK(HaveAuth()); |
450 | 442 |
451 // Clear the cache entry for the identity we just failed on. | 443 // Clear the cache entry for the identity we just failed on. |
452 // Note: we require the username/password to match before invalidating | 444 // Note: we require the username/password to match before invalidating |
453 // since the entry in the cache may be newer than what we used last time. | 445 // since the entry in the cache may be newer than what we used last time. |
454 http_auth_cache_->Remove(auth_origin_, handler_->realm(), | 446 http_auth_cache_->Remove(auth_origin_, handler_->realm(), |
455 handler_->auth_scheme(), identity_.username, | 447 handler_->auth_scheme(), identity_.credentials); |
456 identity_.password); | |
457 } | 448 } |
458 | 449 |
459 bool HttpAuthController::SelectNextAuthIdentityToTry() { | 450 bool HttpAuthController::SelectNextAuthIdentityToTry() { |
460 DCHECK(CalledOnValidThread()); | 451 DCHECK(CalledOnValidThread()); |
461 DCHECK(handler_.get()); | 452 DCHECK(handler_.get()); |
462 DCHECK(identity_.invalid); | 453 DCHECK(identity_.invalid); |
463 | 454 |
464 // Try to use the username/password encoded into the URL first. | 455 // Try to use the username/password encoded into the URL first. |
465 if (target_ == HttpAuth::AUTH_SERVER && auth_url_.has_username() && | 456 if (target_ == HttpAuth::AUTH_SERVER && auth_url_.has_username() && |
466 !embedded_identity_used_) { | 457 !embedded_identity_used_) { |
467 identity_.source = HttpAuth::IDENT_SRC_URL; | 458 identity_.source = HttpAuth::IDENT_SRC_URL; |
468 identity_.invalid = false; | 459 identity_.invalid = false; |
469 // Extract the username:password from the URL. | 460 // Extract the username:password from the URL. |
470 GetIdentityFromURL(auth_url_, | 461 string16 username; |
471 &identity_.username, | 462 string16 password; |
472 &identity_.password); | 463 GetIdentityFromURL(auth_url_, &username, &password); |
| 464 identity_.credentials.Set(username, password); |
473 embedded_identity_used_ = true; | 465 embedded_identity_used_ = true; |
474 // TODO(eroman): If the password is blank, should we also try combining | 466 // TODO(eroman): If the password is blank, should we also try combining |
475 // with a password from the cache? | 467 // with a password from the cache? |
476 return true; | 468 return true; |
477 } | 469 } |
478 | 470 |
479 // Check the auth cache for a realm entry. | 471 // Check the auth cache for a realm entry. |
480 HttpAuthCache::Entry* entry = | 472 HttpAuthCache::Entry* entry = |
481 http_auth_cache_->Lookup(auth_origin_, handler_->realm(), | 473 http_auth_cache_->Lookup(auth_origin_, handler_->realm(), |
482 handler_->auth_scheme()); | 474 handler_->auth_scheme()); |
483 | 475 |
484 if (entry) { | 476 if (entry) { |
485 identity_.source = HttpAuth::IDENT_SRC_REALM_LOOKUP; | 477 identity_.source = HttpAuth::IDENT_SRC_REALM_LOOKUP; |
486 identity_.invalid = false; | 478 identity_.invalid = false; |
487 identity_.username = entry->username(); | 479 identity_.credentials = entry->credentials(); |
488 identity_.password = entry->password(); | |
489 return true; | 480 return true; |
490 } | 481 } |
491 | 482 |
492 // Use default credentials (single sign on) if this is the first attempt | 483 // Use default credentials (single sign on) if this is the first attempt |
493 // at identity. Do not allow multiple times as it will infinite loop. | 484 // at identity. Do not allow multiple times as it will infinite loop. |
494 // We use default credentials after checking the auth cache so that if | 485 // We use default credentials after checking the auth cache so that if |
495 // single sign-on doesn't work, we won't try default credentials for future | 486 // single sign-on doesn't work, we won't try default credentials for future |
496 // transactions. | 487 // transactions. |
497 if (!default_credentials_used_ && handler_->AllowsDefaultCredentials()) { | 488 if (!default_credentials_used_ && handler_->AllowsDefaultCredentials()) { |
498 identity_.source = HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS; | 489 identity_.source = HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS; |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
567 DCHECK(CalledOnValidThread()); | 558 DCHECK(CalledOnValidThread()); |
568 return disabled_schemes_.find(scheme) != disabled_schemes_.end(); | 559 return disabled_schemes_.find(scheme) != disabled_schemes_.end(); |
569 } | 560 } |
570 | 561 |
571 void HttpAuthController::DisableAuthScheme(HttpAuth::Scheme scheme) { | 562 void HttpAuthController::DisableAuthScheme(HttpAuth::Scheme scheme) { |
572 DCHECK(CalledOnValidThread()); | 563 DCHECK(CalledOnValidThread()); |
573 disabled_schemes_.insert(scheme); | 564 disabled_schemes_.insert(scheme); |
574 } | 565 } |
575 | 566 |
576 } // namespace net | 567 } // namespace net |
OLD | NEW |