OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/http/http_auth_controller.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/bind_helpers.h" | |
9 #include "base/metrics/histogram.h" | |
10 #include "base/strings/string_util.h" | |
11 #include "base/strings/utf_string_conversions.h" | |
12 #include "base/threading/platform_thread.h" | |
13 #include "net/base/auth.h" | |
14 #include "net/base/net_util.h" | |
15 #include "net/dns/host_resolver.h" | |
16 #include "net/http/http_auth_handler.h" | |
17 #include "net/http/http_auth_handler_factory.h" | |
18 #include "net/http/http_network_session.h" | |
19 #include "net/http/http_request_headers.h" | |
20 #include "net/http/http_request_info.h" | |
21 #include "net/http/http_response_headers.h" | |
22 | |
23 namespace net { | |
24 | |
25 namespace { | |
26 | |
27 // Returns a log message for all the response headers related to the auth | |
28 // challenge. | |
29 std::string AuthChallengeLogMessage(HttpResponseHeaders* headers) { | |
30 std::string msg; | |
31 std::string header_val; | |
32 void* iter = NULL; | |
33 while (headers->EnumerateHeader(&iter, "proxy-authenticate", &header_val)) { | |
34 msg.append("\n Has header Proxy-Authenticate: "); | |
35 msg.append(header_val); | |
36 } | |
37 | |
38 iter = NULL; | |
39 while (headers->EnumerateHeader(&iter, "www-authenticate", &header_val)) { | |
40 msg.append("\n Has header WWW-Authenticate: "); | |
41 msg.append(header_val); | |
42 } | |
43 | |
44 // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate | |
45 // authentication with a "Proxy-Support: Session-Based-Authentication" | |
46 // response header. | |
47 iter = NULL; | |
48 while (headers->EnumerateHeader(&iter, "proxy-support", &header_val)) { | |
49 msg.append("\n Has header Proxy-Support: "); | |
50 msg.append(header_val); | |
51 } | |
52 | |
53 return msg; | |
54 } | |
55 | |
56 enum AuthEvent { | |
57 AUTH_EVENT_START = 0, | |
58 AUTH_EVENT_REJECT, | |
59 AUTH_EVENT_MAX, | |
60 }; | |
61 | |
62 enum AuthTarget { | |
63 AUTH_TARGET_PROXY = 0, | |
64 AUTH_TARGET_SECURE_PROXY, | |
65 AUTH_TARGET_SERVER, | |
66 AUTH_TARGET_SECURE_SERVER, | |
67 AUTH_TARGET_MAX, | |
68 }; | |
69 | |
70 AuthTarget DetermineAuthTarget(const HttpAuthHandler* handler) { | |
71 switch (handler->target()) { | |
72 case HttpAuth::AUTH_PROXY: | |
73 if (handler->origin().SchemeIsSecure()) | |
74 return AUTH_TARGET_SECURE_PROXY; | |
75 else | |
76 return AUTH_TARGET_PROXY; | |
77 case HttpAuth::AUTH_SERVER: | |
78 if (handler->origin().SchemeIsSecure()) | |
79 return AUTH_TARGET_SECURE_SERVER; | |
80 else | |
81 return AUTH_TARGET_SERVER; | |
82 default: | |
83 NOTREACHED(); | |
84 return AUTH_TARGET_MAX; | |
85 } | |
86 } | |
87 | |
88 // Records the number of authentication events per authentication scheme. | |
89 void HistogramAuthEvent(HttpAuthHandler* handler, AuthEvent auth_event) { | |
90 #if !defined(NDEBUG) | |
91 // Note: The on-same-thread check is intentionally not using a lock | |
92 // to protect access to first_thread. This method is meant to be only | |
93 // used on the same thread, in which case there are no race conditions. If | |
94 // there are race conditions (say, a read completes during a partial write), | |
95 // the DCHECK will correctly fail. | |
96 static base::PlatformThreadId first_thread = | |
97 base::PlatformThread::CurrentId(); | |
98 DCHECK_EQ(first_thread, base::PlatformThread::CurrentId()); | |
99 #endif | |
100 | |
101 HttpAuth::Scheme auth_scheme = handler->auth_scheme(); | |
102 DCHECK(auth_scheme >= 0 && auth_scheme < HttpAuth::AUTH_SCHEME_MAX); | |
103 | |
104 // Record start and rejection events for authentication. | |
105 // | |
106 // The results map to: | |
107 // Basic Start: 0 | |
108 // Basic Reject: 1 | |
109 // Digest Start: 2 | |
110 // Digest Reject: 3 | |
111 // NTLM Start: 4 | |
112 // NTLM Reject: 5 | |
113 // Negotiate Start: 6 | |
114 // Negotiate Reject: 7 | |
115 static const int kEventBucketsEnd = | |
116 HttpAuth::AUTH_SCHEME_MAX * AUTH_EVENT_MAX; | |
117 int event_bucket = auth_scheme * AUTH_EVENT_MAX + auth_event; | |
118 DCHECK(event_bucket >= 0 && event_bucket < kEventBucketsEnd); | |
119 UMA_HISTOGRAM_ENUMERATION("Net.HttpAuthCount", event_bucket, | |
120 kEventBucketsEnd); | |
121 | |
122 // Record the target of the authentication. | |
123 // | |
124 // The results map to: | |
125 // Basic Proxy: 0 | |
126 // Basic Secure Proxy: 1 | |
127 // Basic Server: 2 | |
128 // Basic Secure Server: 3 | |
129 // Digest Proxy: 4 | |
130 // Digest Secure Proxy: 5 | |
131 // Digest Server: 6 | |
132 // Digest Secure Server: 7 | |
133 // NTLM Proxy: 8 | |
134 // NTLM Secure Proxy: 9 | |
135 // NTLM Server: 10 | |
136 // NTLM Secure Server: 11 | |
137 // Negotiate Proxy: 12 | |
138 // Negotiate Secure Proxy: 13 | |
139 // Negotiate Server: 14 | |
140 // Negotiate Secure Server: 15 | |
141 if (auth_event != AUTH_EVENT_START) | |
142 return; | |
143 static const int kTargetBucketsEnd = | |
144 HttpAuth::AUTH_SCHEME_MAX * AUTH_TARGET_MAX; | |
145 AuthTarget auth_target = DetermineAuthTarget(handler); | |
146 int target_bucket = auth_scheme * AUTH_TARGET_MAX + auth_target; | |
147 DCHECK(target_bucket >= 0 && target_bucket < kTargetBucketsEnd); | |
148 UMA_HISTOGRAM_ENUMERATION("Net.HttpAuthTarget", target_bucket, | |
149 kTargetBucketsEnd); | |
150 } | |
151 | |
152 } // namespace | |
153 | |
154 HttpAuthController::HttpAuthController( | |
155 HttpAuth::Target target, | |
156 const GURL& auth_url, | |
157 HttpAuthCache* http_auth_cache, | |
158 HttpAuthHandlerFactory* http_auth_handler_factory) | |
159 : target_(target), | |
160 auth_url_(auth_url), | |
161 auth_origin_(auth_url.GetOrigin()), | |
162 auth_path_(HttpAuth::AUTH_PROXY ? std::string() : auth_url.path()), | |
163 embedded_identity_used_(false), | |
164 default_credentials_used_(false), | |
165 http_auth_cache_(http_auth_cache), | |
166 http_auth_handler_factory_(http_auth_handler_factory) { | |
167 } | |
168 | |
169 HttpAuthController::~HttpAuthController() { | |
170 DCHECK(CalledOnValidThread()); | |
171 } | |
172 | |
173 int HttpAuthController::MaybeGenerateAuthToken( | |
174 const HttpRequestInfo* request, const CompletionCallback& callback, | |
175 const BoundNetLog& net_log) { | |
176 DCHECK(CalledOnValidThread()); | |
177 bool needs_auth = HaveAuth() || SelectPreemptiveAuth(net_log); | |
178 if (!needs_auth) | |
179 return OK; | |
180 const AuthCredentials* credentials = NULL; | |
181 if (identity_.source != HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS) | |
182 credentials = &identity_.credentials; | |
183 DCHECK(auth_token_.empty()); | |
184 DCHECK(callback_.is_null()); | |
185 int rv = handler_->GenerateAuthToken( | |
186 credentials, request, | |
187 base::Bind(&HttpAuthController::OnIOComplete, base::Unretained(this)), | |
188 &auth_token_); | |
189 if (DisableOnAuthHandlerResult(rv)) | |
190 rv = OK; | |
191 if (rv == ERR_IO_PENDING) | |
192 callback_ = callback; | |
193 else | |
194 OnIOComplete(rv); | |
195 return rv; | |
196 } | |
197 | |
198 bool HttpAuthController::SelectPreemptiveAuth(const BoundNetLog& net_log) { | |
199 DCHECK(CalledOnValidThread()); | |
200 DCHECK(!HaveAuth()); | |
201 DCHECK(identity_.invalid); | |
202 | |
203 // Don't do preemptive authorization if the URL contains a username:password, | |
204 // since we must first be challenged in order to use the URL's identity. | |
205 if (auth_url_.has_username()) | |
206 return false; | |
207 | |
208 // SelectPreemptiveAuth() is on the critical path for each request, so it | |
209 // is expected to be fast. LookupByPath() is fast in the common case, since | |
210 // the number of http auth cache entries is expected to be very small. | |
211 // (For most users in fact, it will be 0.) | |
212 HttpAuthCache::Entry* entry = http_auth_cache_->LookupByPath( | |
213 auth_origin_, auth_path_); | |
214 if (!entry) | |
215 return false; | |
216 | |
217 // Try to create a handler using the previous auth challenge. | |
218 scoped_ptr<HttpAuthHandler> handler_preemptive; | |
219 int rv_create = http_auth_handler_factory_-> | |
220 CreatePreemptiveAuthHandlerFromString(entry->auth_challenge(), target_, | |
221 auth_origin_, | |
222 entry->IncrementNonceCount(), | |
223 net_log, &handler_preemptive); | |
224 if (rv_create != OK) | |
225 return false; | |
226 | |
227 // Set the state | |
228 identity_.source = HttpAuth::IDENT_SRC_PATH_LOOKUP; | |
229 identity_.invalid = false; | |
230 identity_.credentials = entry->credentials(); | |
231 handler_.swap(handler_preemptive); | |
232 return true; | |
233 } | |
234 | |
235 void HttpAuthController::AddAuthorizationHeader( | |
236 HttpRequestHeaders* authorization_headers) { | |
237 DCHECK(CalledOnValidThread()); | |
238 DCHECK(HaveAuth()); | |
239 // auth_token_ can be empty if we encountered a permanent error with | |
240 // the auth scheme and want to retry. | |
241 if (!auth_token_.empty()) { | |
242 authorization_headers->SetHeader( | |
243 HttpAuth::GetAuthorizationHeaderName(target_), auth_token_); | |
244 auth_token_.clear(); | |
245 } | |
246 } | |
247 | |
248 int HttpAuthController::HandleAuthChallenge( | |
249 scoped_refptr<HttpResponseHeaders> headers, | |
250 bool do_not_send_server_auth, | |
251 bool establishing_tunnel, | |
252 const BoundNetLog& net_log) { | |
253 DCHECK(CalledOnValidThread()); | |
254 DCHECK(headers.get()); | |
255 DCHECK(auth_origin_.is_valid()); | |
256 VLOG(1) << "The " << HttpAuth::GetAuthTargetString(target_) << " " | |
257 << auth_origin_ << " requested auth " | |
258 << AuthChallengeLogMessage(headers.get()); | |
259 | |
260 // Give the existing auth handler first try at the authentication headers. | |
261 // This will also evict the entry in the HttpAuthCache if the previous | |
262 // challenge appeared to be rejected, or is using a stale nonce in the Digest | |
263 // case. | |
264 if (HaveAuth()) { | |
265 std::string challenge_used; | |
266 HttpAuth::AuthorizationResult result = | |
267 HttpAuth::HandleChallengeResponse(handler_.get(), | |
268 headers.get(), | |
269 target_, | |
270 disabled_schemes_, | |
271 &challenge_used); | |
272 switch (result) { | |
273 case HttpAuth::AUTHORIZATION_RESULT_ACCEPT: | |
274 break; | |
275 case HttpAuth::AUTHORIZATION_RESULT_INVALID: | |
276 InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS); | |
277 break; | |
278 case HttpAuth::AUTHORIZATION_RESULT_REJECT: | |
279 HistogramAuthEvent(handler_.get(), AUTH_EVENT_REJECT); | |
280 InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS); | |
281 break; | |
282 case HttpAuth::AUTHORIZATION_RESULT_STALE: | |
283 if (http_auth_cache_->UpdateStaleChallenge(auth_origin_, | |
284 handler_->realm(), | |
285 handler_->auth_scheme(), | |
286 challenge_used)) { | |
287 InvalidateCurrentHandler(INVALIDATE_HANDLER); | |
288 } else { | |
289 // It's possible that a server could incorrectly issue a stale | |
290 // response when the entry is not in the cache. Just evict the | |
291 // current value from the cache. | |
292 InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS); | |
293 } | |
294 break; | |
295 case HttpAuth::AUTHORIZATION_RESULT_DIFFERENT_REALM: | |
296 // If the server changes the authentication realm in a | |
297 // subsequent challenge, invalidate cached credentials for the | |
298 // previous realm. If the server rejects a preemptive | |
299 // authorization and requests credentials for a different | |
300 // realm, we keep the cached credentials. | |
301 InvalidateCurrentHandler( | |
302 (identity_.source == HttpAuth::IDENT_SRC_PATH_LOOKUP) ? | |
303 INVALIDATE_HANDLER : | |
304 INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS); | |
305 break; | |
306 default: | |
307 NOTREACHED(); | |
308 break; | |
309 } | |
310 } | |
311 | |
312 identity_.invalid = true; | |
313 | |
314 bool can_send_auth = (target_ != HttpAuth::AUTH_SERVER || | |
315 !do_not_send_server_auth); | |
316 | |
317 do { | |
318 if (!handler_.get() && can_send_auth) { | |
319 // Find the best authentication challenge that we support. | |
320 HttpAuth::ChooseBestChallenge(http_auth_handler_factory_, | |
321 headers.get(), | |
322 target_, | |
323 auth_origin_, | |
324 disabled_schemes_, | |
325 net_log, | |
326 &handler_); | |
327 if (handler_.get()) | |
328 HistogramAuthEvent(handler_.get(), AUTH_EVENT_START); | |
329 } | |
330 | |
331 if (!handler_.get()) { | |
332 if (establishing_tunnel) { | |
333 LOG(ERROR) << "Can't perform auth to the " | |
334 << HttpAuth::GetAuthTargetString(target_) << " " | |
335 << auth_origin_ << " when establishing a tunnel" | |
336 << AuthChallengeLogMessage(headers.get()); | |
337 | |
338 // We are establishing a tunnel, we can't show the error page because an | |
339 // active network attacker could control its contents. Instead, we just | |
340 // fail to establish the tunnel. | |
341 DCHECK(target_ == HttpAuth::AUTH_PROXY); | |
342 return ERR_PROXY_AUTH_UNSUPPORTED; | |
343 } | |
344 // We found no supported challenge -- let the transaction continue so we | |
345 // end up displaying the error page. | |
346 return OK; | |
347 } | |
348 | |
349 if (handler_->NeedsIdentity()) { | |
350 // Pick a new auth identity to try, by looking to the URL and auth cache. | |
351 // If an identity to try is found, it is saved to identity_. | |
352 SelectNextAuthIdentityToTry(); | |
353 } else { | |
354 // Proceed with the existing identity or a null identity. | |
355 identity_.invalid = false; | |
356 } | |
357 | |
358 // From this point on, we are restartable. | |
359 | |
360 if (identity_.invalid) { | |
361 // We have exhausted all identity possibilities. | |
362 if (!handler_->AllowsExplicitCredentials()) { | |
363 // If the handler doesn't accept explicit credentials, then we need to | |
364 // choose a different auth scheme. | |
365 HistogramAuthEvent(handler_.get(), AUTH_EVENT_REJECT); | |
366 InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_DISABLE_SCHEME); | |
367 } else { | |
368 // Pass the challenge information back to the client. | |
369 PopulateAuthChallenge(); | |
370 } | |
371 } else { | |
372 auth_info_ = NULL; | |
373 } | |
374 | |
375 // 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 | |
377 // back and try again. | |
378 // TODO(asanka): Instead we should create a priority list of | |
379 // <handler,identity> and iterate through that. | |
380 } while(!handler_.get()); | |
381 return OK; | |
382 } | |
383 | |
384 void HttpAuthController::ResetAuth(const AuthCredentials& credentials) { | |
385 DCHECK(CalledOnValidThread()); | |
386 DCHECK(identity_.invalid || credentials.Empty()); | |
387 | |
388 if (identity_.invalid) { | |
389 // Update the credentials. | |
390 identity_.source = HttpAuth::IDENT_SRC_EXTERNAL; | |
391 identity_.invalid = false; | |
392 identity_.credentials = credentials; | |
393 } | |
394 | |
395 DCHECK(identity_.source != HttpAuth::IDENT_SRC_PATH_LOOKUP); | |
396 | |
397 // Add the auth entry to the cache before restarting. We don't know whether | |
398 // the identity is valid yet, but if it is valid we want other transactions | |
399 // to know about it. If an entry for (origin, handler->realm()) already | |
400 // exists, we update it. | |
401 // | |
402 // If identity_.source is HttpAuth::IDENT_SRC_NONE or | |
403 // HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS, identity_ contains no | |
404 // identity because identity is not required yet or we're using default | |
405 // credentials. | |
406 // | |
407 // TODO(wtc): For NTLM_SSPI, we add the same auth entry to the cache in | |
408 // round 1 and round 2, which is redundant but correct. It would be nice | |
409 // to add an auth entry to the cache only once, preferrably in round 1. | |
410 // See http://crbug.com/21015. | |
411 switch (identity_.source) { | |
412 case HttpAuth::IDENT_SRC_NONE: | |
413 case HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS: | |
414 break; | |
415 default: | |
416 http_auth_cache_->Add(auth_origin_, handler_->realm(), | |
417 handler_->auth_scheme(), handler_->challenge(), | |
418 identity_.credentials, auth_path_); | |
419 break; | |
420 } | |
421 } | |
422 | |
423 bool HttpAuthController::HaveAuthHandler() const { | |
424 return handler_.get() != NULL; | |
425 } | |
426 | |
427 bool HttpAuthController::HaveAuth() const { | |
428 return handler_.get() && !identity_.invalid; | |
429 } | |
430 | |
431 void HttpAuthController::InvalidateCurrentHandler( | |
432 InvalidateHandlerAction action) { | |
433 DCHECK(CalledOnValidThread()); | |
434 DCHECK(handler_.get()); | |
435 | |
436 if (action == INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS) | |
437 InvalidateRejectedAuthFromCache(); | |
438 if (action == INVALIDATE_HANDLER_AND_DISABLE_SCHEME) | |
439 DisableAuthScheme(handler_->auth_scheme()); | |
440 handler_.reset(); | |
441 identity_ = HttpAuth::Identity(); | |
442 } | |
443 | |
444 void HttpAuthController::InvalidateRejectedAuthFromCache() { | |
445 DCHECK(CalledOnValidThread()); | |
446 DCHECK(HaveAuth()); | |
447 | |
448 // Clear the cache entry for the identity we just failed on. | |
449 // Note: we require the credentials to match before invalidating | |
450 // since the entry in the cache may be newer than what we used last time. | |
451 http_auth_cache_->Remove(auth_origin_, handler_->realm(), | |
452 handler_->auth_scheme(), identity_.credentials); | |
453 } | |
454 | |
455 bool HttpAuthController::SelectNextAuthIdentityToTry() { | |
456 DCHECK(CalledOnValidThread()); | |
457 DCHECK(handler_.get()); | |
458 DCHECK(identity_.invalid); | |
459 | |
460 // Try to use the username:password encoded into the URL first. | |
461 if (target_ == HttpAuth::AUTH_SERVER && auth_url_.has_username() && | |
462 !embedded_identity_used_) { | |
463 identity_.source = HttpAuth::IDENT_SRC_URL; | |
464 identity_.invalid = false; | |
465 // Extract the username:password from the URL. | |
466 base::string16 username; | |
467 base::string16 password; | |
468 GetIdentityFromURL(auth_url_, &username, &password); | |
469 identity_.credentials.Set(username, password); | |
470 embedded_identity_used_ = true; | |
471 // TODO(eroman): If the password is blank, should we also try combining | |
472 // with a password from the cache? | |
473 UMA_HISTOGRAM_BOOLEAN("net.HttpIdentSrcURL", true); | |
474 return true; | |
475 } | |
476 | |
477 // Check the auth cache for a realm entry. | |
478 HttpAuthCache::Entry* entry = | |
479 http_auth_cache_->Lookup(auth_origin_, handler_->realm(), | |
480 handler_->auth_scheme()); | |
481 | |
482 if (entry) { | |
483 identity_.source = HttpAuth::IDENT_SRC_REALM_LOOKUP; | |
484 identity_.invalid = false; | |
485 identity_.credentials = entry->credentials(); | |
486 return true; | |
487 } | |
488 | |
489 // Use default credentials (single sign on) if this is the first attempt | |
490 // at identity. Do not allow multiple times as it will infinite loop. | |
491 // We use default credentials after checking the auth cache so that if | |
492 // single sign-on doesn't work, we won't try default credentials for future | |
493 // transactions. | |
494 if (!default_credentials_used_ && handler_->AllowsDefaultCredentials()) { | |
495 identity_.source = HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS; | |
496 identity_.invalid = false; | |
497 default_credentials_used_ = true; | |
498 return true; | |
499 } | |
500 | |
501 return false; | |
502 } | |
503 | |
504 void HttpAuthController::PopulateAuthChallenge() { | |
505 DCHECK(CalledOnValidThread()); | |
506 | |
507 // Populates response_.auth_challenge with the authentication challenge info. | |
508 // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo(). | |
509 | |
510 auth_info_ = new AuthChallengeInfo; | |
511 auth_info_->is_proxy = (target_ == HttpAuth::AUTH_PROXY); | |
512 auth_info_->challenger = HostPortPair::FromURL(auth_origin_); | |
513 auth_info_->scheme = HttpAuth::SchemeToString(handler_->auth_scheme()); | |
514 auth_info_->realm = handler_->realm(); | |
515 } | |
516 | |
517 bool HttpAuthController::DisableOnAuthHandlerResult(int result) { | |
518 DCHECK(CalledOnValidThread()); | |
519 | |
520 switch (result) { | |
521 // Occurs with GSSAPI, if the user has not already logged in. | |
522 case ERR_MISSING_AUTH_CREDENTIALS: | |
523 | |
524 // Can occur with GSSAPI or SSPI if the underlying library reports | |
525 // a permanent error. | |
526 case ERR_UNSUPPORTED_AUTH_SCHEME: | |
527 | |
528 // These two error codes represent failures we aren't handling. | |
529 case ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS: | |
530 case ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS: | |
531 | |
532 // Can be returned by SSPI if the authenticating authority or | |
533 // target is not known. | |
534 case ERR_MISCONFIGURED_AUTH_ENVIRONMENT: | |
535 | |
536 // In these cases, disable the current scheme as it cannot | |
537 // succeed. | |
538 DisableAuthScheme(handler_->auth_scheme()); | |
539 auth_token_.clear(); | |
540 return true; | |
541 | |
542 default: | |
543 return false; | |
544 } | |
545 } | |
546 | |
547 void HttpAuthController::OnIOComplete(int result) { | |
548 DCHECK(CalledOnValidThread()); | |
549 if (DisableOnAuthHandlerResult(result)) | |
550 result = OK; | |
551 if (!callback_.is_null()) { | |
552 CompletionCallback c = callback_; | |
553 callback_.Reset(); | |
554 c.Run(result); | |
555 } | |
556 } | |
557 | |
558 scoped_refptr<AuthChallengeInfo> HttpAuthController::auth_info() { | |
559 DCHECK(CalledOnValidThread()); | |
560 return auth_info_; | |
561 } | |
562 | |
563 bool HttpAuthController::IsAuthSchemeDisabled(HttpAuth::Scheme scheme) const { | |
564 DCHECK(CalledOnValidThread()); | |
565 return disabled_schemes_.find(scheme) != disabled_schemes_.end(); | |
566 } | |
567 | |
568 void HttpAuthController::DisableAuthScheme(HttpAuth::Scheme scheme) { | |
569 DCHECK(CalledOnValidThread()); | |
570 disabled_schemes_.insert(scheme); | |
571 } | |
572 | |
573 void HttpAuthController::DisableEmbeddedIdentity() { | |
574 DCHECK(CalledOnValidThread()); | |
575 embedded_identity_used_ = true; | |
576 } | |
577 | |
578 } // namespace net | |
OLD | NEW |