• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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 <utility>
8 
9 #include "base/functional/bind.h"
10 #include "base/functional/callback_helpers.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/values.h"
15 #include "net/base/auth.h"
16 #include "net/base/url_util.h"
17 #include "net/dns/host_resolver.h"
18 #include "net/http/http_auth_handler.h"
19 #include "net/http/http_auth_handler_factory.h"
20 #include "net/http/http_network_session.h"
21 #include "net/http/http_request_headers.h"
22 #include "net/http/http_request_info.h"
23 #include "net/http/http_response_headers.h"
24 #include "net/log/net_log_event_type.h"
25 #include "net/log/net_log_source.h"
26 #include "net/log/net_log_source_type.h"
27 #include "net/log/net_log_with_source.h"
28 #include "url/scheme_host_port.h"
29 
30 namespace net {
31 
32 namespace {
33 
ControllerParamsToValue(HttpAuth::Target target,const GURL & url)34 base::Value::Dict ControllerParamsToValue(HttpAuth::Target target,
35                                           const GURL& url) {
36   base::Value::Dict params;
37   params.Set("target", HttpAuth::GetAuthTargetString(target));
38   params.Set("url", url.spec());
39   return params;
40 }
41 
42 }  // namespace
43 
HttpAuthController(HttpAuth::Target target,const GURL & auth_url,const NetworkAnonymizationKey & network_anonymization_key,HttpAuthCache * http_auth_cache,HttpAuthHandlerFactory * http_auth_handler_factory,HostResolver * host_resolver)44 HttpAuthController::HttpAuthController(
45     HttpAuth::Target target,
46     const GURL& auth_url,
47     const NetworkAnonymizationKey& network_anonymization_key,
48     HttpAuthCache* http_auth_cache,
49     HttpAuthHandlerFactory* http_auth_handler_factory,
50     HostResolver* host_resolver)
51     : target_(target),
52       auth_url_(auth_url),
53       auth_scheme_host_port_(auth_url),
54       auth_path_(auth_url.path()),
55       network_anonymization_key_(network_anonymization_key),
56       http_auth_cache_(http_auth_cache),
57       http_auth_handler_factory_(http_auth_handler_factory),
58       host_resolver_(host_resolver) {
59   DCHECK(target != HttpAuth::AUTH_PROXY || auth_path_ == "/");
60   DCHECK(auth_scheme_host_port_.IsValid());
61 }
62 
~HttpAuthController()63 HttpAuthController::~HttpAuthController() {
64   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
65   if (net_log_.source().IsValid())
66     net_log_.EndEvent(NetLogEventType::AUTH_CONTROLLER);
67 }
68 
BindToCallingNetLog(const NetLogWithSource & caller_net_log)69 void HttpAuthController::BindToCallingNetLog(
70     const NetLogWithSource& caller_net_log) {
71   if (!net_log_.source().IsValid()) {
72     net_log_ = NetLogWithSource::Make(caller_net_log.net_log(),
73                                       NetLogSourceType::HTTP_AUTH_CONTROLLER);
74     net_log_.BeginEvent(NetLogEventType::AUTH_CONTROLLER, [&] {
75       return ControllerParamsToValue(target_, auth_url_);
76     });
77   }
78   caller_net_log.AddEventReferencingSource(
79       NetLogEventType::AUTH_BOUND_TO_CONTROLLER, net_log_.source());
80 }
81 
MaybeGenerateAuthToken(const HttpRequestInfo * request,CompletionOnceCallback callback,const NetLogWithSource & caller_net_log)82 int HttpAuthController::MaybeGenerateAuthToken(
83     const HttpRequestInfo* request,
84     CompletionOnceCallback callback,
85     const NetLogWithSource& caller_net_log) {
86   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
87   DCHECK(!auth_info_);
88   bool needs_auth = HaveAuth() || SelectPreemptiveAuth(caller_net_log);
89   if (!needs_auth)
90     return OK;
91   net_log_.BeginEventReferencingSource(NetLogEventType::AUTH_GENERATE_TOKEN,
92                                        caller_net_log.source());
93   const AuthCredentials* credentials = nullptr;
94   if (identity_.source != HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS)
95     credentials = &identity_.credentials;
96   DCHECK(auth_token_.empty());
97   DCHECK(callback_.is_null());
98   int rv = handler_->GenerateAuthToken(
99       credentials, request,
100       base::BindOnce(&HttpAuthController::OnGenerateAuthTokenDone,
101                      base::Unretained(this)),
102       &auth_token_);
103 
104   if (rv == ERR_IO_PENDING) {
105     callback_ = std::move(callback);
106     return rv;
107   }
108 
109   return HandleGenerateTokenResult(rv);
110 }
111 
SelectPreemptiveAuth(const NetLogWithSource & caller_net_log)112 bool HttpAuthController::SelectPreemptiveAuth(
113     const NetLogWithSource& caller_net_log) {
114   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
115   DCHECK(!HaveAuth());
116   DCHECK(identity_.invalid);
117 
118   // Don't do preemptive authorization if the URL contains a username:password,
119   // since we must first be challenged in order to use the URL's identity.
120   if (auth_url_.has_username())
121     return false;
122 
123   // SelectPreemptiveAuth() is on the critical path for each request, so it
124   // is expected to be fast. LookupByPath() is fast in the common case, since
125   // the number of http auth cache entries is expected to be very small.
126   // (For most users in fact, it will be 0.)
127   HttpAuthCache::Entry* entry = http_auth_cache_->LookupByPath(
128       auth_scheme_host_port_, target_, network_anonymization_key_, auth_path_);
129   if (!entry)
130     return false;
131 
132   BindToCallingNetLog(caller_net_log);
133 
134   // Try to create a handler using the previous auth challenge.
135   std::unique_ptr<HttpAuthHandler> handler_preemptive;
136   int rv_create =
137       http_auth_handler_factory_->CreatePreemptiveAuthHandlerFromString(
138           entry->auth_challenge(), target_, network_anonymization_key_,
139           auth_scheme_host_port_, entry->IncrementNonceCount(), net_log_,
140           host_resolver_, &handler_preemptive);
141   if (rv_create != OK)
142     return false;
143 
144   // Set the state
145   identity_.source = HttpAuth::IDENT_SRC_PATH_LOOKUP;
146   identity_.invalid = false;
147   identity_.credentials = entry->credentials();
148   handler_.swap(handler_preemptive);
149   return true;
150 }
151 
AddAuthorizationHeader(HttpRequestHeaders * authorization_headers)152 void HttpAuthController::AddAuthorizationHeader(
153     HttpRequestHeaders* authorization_headers) {
154   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
155   DCHECK(HaveAuth());
156   // auth_token_ can be empty if we encountered a permanent error with
157   // the auth scheme and want to retry.
158   if (!auth_token_.empty()) {
159     authorization_headers->SetHeader(
160         HttpAuth::GetAuthorizationHeaderName(target_), auth_token_);
161     auth_token_.clear();
162   }
163 }
164 
HandleAuthChallenge(scoped_refptr<HttpResponseHeaders> headers,const SSLInfo & ssl_info,bool do_not_send_server_auth,bool establishing_tunnel,const NetLogWithSource & caller_net_log)165 int HttpAuthController::HandleAuthChallenge(
166     scoped_refptr<HttpResponseHeaders> headers,
167     const SSLInfo& ssl_info,
168     bool do_not_send_server_auth,
169     bool establishing_tunnel,
170     const NetLogWithSource& caller_net_log) {
171   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
172   DCHECK(headers.get());
173   DCHECK(auth_scheme_host_port_.IsValid());
174   DCHECK(!auth_info_);
175 
176   BindToCallingNetLog(caller_net_log);
177   net_log_.BeginEventReferencingSource(NetLogEventType::AUTH_HANDLE_CHALLENGE,
178                                        caller_net_log.source());
179 
180   // Give the existing auth handler first try at the authentication headers.
181   // This will also evict the entry in the HttpAuthCache if the previous
182   // challenge appeared to be rejected, or is using a stale nonce in the Digest
183   // case.
184   if (HaveAuth()) {
185     std::string challenge_used;
186     HttpAuth::AuthorizationResult result = HttpAuth::HandleChallengeResponse(
187         handler_.get(), *headers, target_, disabled_schemes_, &challenge_used);
188     switch (result) {
189       case HttpAuth::AUTHORIZATION_RESULT_ACCEPT:
190         break;
191       case HttpAuth::AUTHORIZATION_RESULT_INVALID:
192         InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS);
193         break;
194       case HttpAuth::AUTHORIZATION_RESULT_REJECT:
195         InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS);
196         break;
197       case HttpAuth::AUTHORIZATION_RESULT_STALE:
198         if (http_auth_cache_->UpdateStaleChallenge(
199                 auth_scheme_host_port_, target_, handler_->realm(),
200                 handler_->auth_scheme(), network_anonymization_key_,
201                 challenge_used)) {
202           InvalidateCurrentHandler(INVALIDATE_HANDLER);
203         } else {
204           // It's possible that a server could incorrectly issue a stale
205           // response when the entry is not in the cache. Just evict the
206           // current value from the cache.
207           InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS);
208         }
209         break;
210       case HttpAuth::AUTHORIZATION_RESULT_DIFFERENT_REALM:
211         // If the server changes the authentication realm in a
212         // subsequent challenge, invalidate cached credentials for the
213         // previous realm.  If the server rejects a preemptive
214         // authorization and requests credentials for a different
215         // realm, we keep the cached credentials.
216         InvalidateCurrentHandler(
217             (identity_.source == HttpAuth::IDENT_SRC_PATH_LOOKUP) ?
218             INVALIDATE_HANDLER :
219             INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS);
220         break;
221       default:
222         NOTREACHED();
223         break;
224     }
225   }
226 
227   identity_.invalid = true;
228   bool can_send_auth = (target_ != HttpAuth::AUTH_SERVER ||
229                         !do_not_send_server_auth);
230 
231   do {
232     if (!handler_.get() && can_send_auth) {
233       // Find the best authentication challenge that we support.
234       HttpAuth::ChooseBestChallenge(
235           http_auth_handler_factory_, *headers, ssl_info,
236           network_anonymization_key_, target_, auth_scheme_host_port_,
237           disabled_schemes_, net_log_, host_resolver_, &handler_);
238     }
239 
240     if (!handler_.get()) {
241       if (establishing_tunnel) {
242         // We are establishing a tunnel, we can't show the error page because an
243         // active network attacker could control its contents.  Instead, we just
244         // fail to establish the tunnel.
245         DCHECK_EQ(target_, HttpAuth::AUTH_PROXY);
246         net_log_.EndEventWithNetErrorCode(
247             NetLogEventType::AUTH_HANDLE_CHALLENGE, ERR_PROXY_AUTH_UNSUPPORTED);
248         return ERR_PROXY_AUTH_UNSUPPORTED;
249       }
250       // We found no supported challenge -- let the transaction continue so we
251       // end up displaying the error page.
252       net_log_.EndEvent(NetLogEventType::AUTH_HANDLE_CHALLENGE);
253       return OK;
254     }
255 
256     if (handler_->NeedsIdentity()) {
257       // Pick a new auth identity to try, by looking to the URL and auth cache.
258       // If an identity to try is found, it is saved to identity_.
259       SelectNextAuthIdentityToTry();
260     } else {
261       // Proceed with the existing identity or a null identity.
262       identity_.invalid = false;
263     }
264 
265     // From this point on, we are restartable.
266 
267     if (identity_.invalid) {
268       // We have exhausted all identity possibilities.
269       if (!handler_->AllowsExplicitCredentials()) {
270         // If the handler doesn't accept explicit credentials, then we need to
271         // choose a different auth scheme.
272         InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_DISABLE_SCHEME);
273       } else {
274         // Pass the challenge information back to the client.
275         PopulateAuthChallenge();
276       }
277     }
278 
279     // If we get here and we don't have a handler_, that's because we
280     // invalidated it due to not having any viable identities to use with it. Go
281     // back and try again.
282     // TODO(asanka): Instead we should create a priority list of
283     //     <handler,identity> and iterate through that.
284   } while(!handler_.get());
285   net_log_.EndEvent(NetLogEventType::AUTH_HANDLE_CHALLENGE);
286   return OK;
287 }
288 
ResetAuth(const AuthCredentials & credentials)289 void HttpAuthController::ResetAuth(const AuthCredentials& credentials) {
290   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
291   DCHECK(identity_.invalid || credentials.Empty());
292 
293   if (identity_.invalid) {
294     // Update the credentials.
295     identity_.source = HttpAuth::IDENT_SRC_EXTERNAL;
296     identity_.invalid = false;
297     identity_.credentials = credentials;
298 
299     // auth_info_ is no longer necessary.
300     auth_info_ = absl::nullopt;
301   }
302 
303   DCHECK(identity_.source != HttpAuth::IDENT_SRC_PATH_LOOKUP);
304 
305   // Add the auth entry to the cache before restarting. We don't know whether
306   // the identity is valid yet, but if it is valid we want other transactions
307   // to know about it. If an entry for (origin, handler->realm()) already
308   // exists, we update it.
309   //
310   // If identity_.source is HttpAuth::IDENT_SRC_NONE or
311   // HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS, identity_ contains no
312   // identity because identity is not required yet or we're using default
313   // credentials.
314   //
315   // TODO(wtc): For NTLM_SSPI, we add the same auth entry to the cache in
316   // round 1 and round 2, which is redundant but correct.  It would be nice
317   // to add an auth entry to the cache only once, preferrably in round 1.
318   // See http://crbug.com/21015.
319   switch (identity_.source) {
320     case HttpAuth::IDENT_SRC_NONE:
321     case HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS:
322       break;
323     default:
324       http_auth_cache_->Add(auth_scheme_host_port_, target_, handler_->realm(),
325                             handler_->auth_scheme(), network_anonymization_key_,
326                             handler_->challenge(), identity_.credentials,
327                             auth_path_);
328       break;
329   }
330 }
331 
HaveAuthHandler() const332 bool HttpAuthController::HaveAuthHandler() const {
333   return handler_.get() != nullptr;
334 }
335 
HaveAuth() const336 bool HttpAuthController::HaveAuth() const {
337   return handler_.get() && !identity_.invalid;
338 }
339 
NeedsHTTP11() const340 bool HttpAuthController::NeedsHTTP11() const {
341   return handler_ && handler_->is_connection_based();
342 }
343 
InvalidateCurrentHandler(InvalidateHandlerAction action)344 void HttpAuthController::InvalidateCurrentHandler(
345     InvalidateHandlerAction action) {
346   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
347   DCHECK(handler_.get());
348 
349   switch (action) {
350     case INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS:
351       InvalidateRejectedAuthFromCache();
352       break;
353 
354     case INVALIDATE_HANDLER_AND_DISABLE_SCHEME:
355       DisableAuthScheme(handler_->auth_scheme());
356       break;
357 
358     case INVALIDATE_HANDLER:
359       PrepareIdentityForReuse();
360       break;
361   }
362 
363   handler_.reset();
364   identity_ = HttpAuth::Identity();
365 }
366 
InvalidateRejectedAuthFromCache()367 void HttpAuthController::InvalidateRejectedAuthFromCache() {
368   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
369   DCHECK(HaveAuth());
370 
371   // Clear the cache entry for the identity we just failed on.
372   // Note: we require the credentials to match before invalidating
373   // since the entry in the cache may be newer than what we used last time.
374   http_auth_cache_->Remove(auth_scheme_host_port_, target_, handler_->realm(),
375                            handler_->auth_scheme(), network_anonymization_key_,
376                            identity_.credentials);
377 }
378 
PrepareIdentityForReuse()379 void HttpAuthController::PrepareIdentityForReuse() {
380   if (identity_.invalid)
381     return;
382 
383   switch (identity_.source) {
384     case HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS:
385       DCHECK(default_credentials_used_);
386       default_credentials_used_ = false;
387       break;
388 
389     case HttpAuth::IDENT_SRC_URL:
390       DCHECK(embedded_identity_used_);
391       embedded_identity_used_ = false;
392       break;
393 
394     case HttpAuth::IDENT_SRC_NONE:
395     case HttpAuth::IDENT_SRC_PATH_LOOKUP:
396     case HttpAuth::IDENT_SRC_REALM_LOOKUP:
397     case HttpAuth::IDENT_SRC_EXTERNAL:
398       break;
399   }
400 }
401 
SelectNextAuthIdentityToTry()402 bool HttpAuthController::SelectNextAuthIdentityToTry() {
403   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
404   DCHECK(handler_.get());
405   DCHECK(identity_.invalid);
406 
407   // Try to use the username:password encoded into the URL first.
408   if (target_ == HttpAuth::AUTH_SERVER && auth_url_.has_username() &&
409       !embedded_identity_used_) {
410     identity_.source = HttpAuth::IDENT_SRC_URL;
411     identity_.invalid = false;
412     // Extract the username:password from the URL.
413     std::u16string username;
414     std::u16string password;
415     GetIdentityFromURL(auth_url_, &username, &password);
416     identity_.credentials.Set(username, password);
417     embedded_identity_used_ = true;
418     // TODO(eroman): If the password is blank, should we also try combining
419     // with a password from the cache?
420     UMA_HISTOGRAM_BOOLEAN("net.HttpIdentSrcURL", true);
421     return true;
422   }
423 
424   // Check the auth cache for a realm entry.
425   HttpAuthCache::Entry* entry = http_auth_cache_->Lookup(
426       auth_scheme_host_port_, target_, handler_->realm(),
427       handler_->auth_scheme(), network_anonymization_key_);
428 
429   if (entry) {
430     identity_.source = HttpAuth::IDENT_SRC_REALM_LOOKUP;
431     identity_.invalid = false;
432     identity_.credentials = entry->credentials();
433     return true;
434   }
435 
436   // Use default credentials (single sign-on) if they're allowed and this is the
437   // first attempt at using an identity. Do not allow multiple times as it will
438   // infinite loop. We use default credentials after checking the auth cache so
439   // that if single sign-on doesn't work, we won't try default credentials for
440   // future transactions.
441   if (!default_credentials_used_ && handler_->AllowsDefaultCredentials()) {
442     identity_.source = HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS;
443     identity_.invalid = false;
444     default_credentials_used_ = true;
445     return true;
446   }
447 
448   return false;
449 }
450 
PopulateAuthChallenge()451 void HttpAuthController::PopulateAuthChallenge() {
452   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
453 
454   // Populates response_.auth_challenge with the authentication challenge info.
455   // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo().
456 
457   auth_info_ = AuthChallengeInfo();
458   auth_info_->is_proxy = (target_ == HttpAuth::AUTH_PROXY);
459   auth_info_->challenger = auth_scheme_host_port_;
460   auth_info_->scheme = HttpAuth::SchemeToString(handler_->auth_scheme());
461   auth_info_->realm = handler_->realm();
462   auth_info_->path = auth_path_;
463   auth_info_->challenge = handler_->challenge();
464 }
465 
HandleGenerateTokenResult(int result)466 int HttpAuthController::HandleGenerateTokenResult(int result) {
467   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
468   net_log_.EndEventWithNetErrorCode(NetLogEventType::AUTH_GENERATE_TOKEN,
469                                     result);
470   switch (result) {
471     // Occurs if the credential handle is found to be invalid at the point it is
472     // exercised (i.e. GenerateAuthToken stage). We are going to consider this
473     // to be an error that invalidates the identity but not necessarily the
474     // scheme. Doing so allows a different identity to be used with the same
475     // scheme. See https://crbug.com/648366.
476     case ERR_INVALID_HANDLE:
477 
478     // If the GenerateAuthToken call fails with this error, this means that the
479     // handler can no longer be used. However, the authentication scheme is
480     // considered still usable. This allows a scheme that attempted and failed
481     // to use default credentials to recover and use explicit credentials.
482     //
483     // The current handler may be tied to external state that is no longer
484     // valid, hence should be discarded. Since the scheme is still valid, a new
485     // handler can be created for the current scheme.
486     case ERR_INVALID_AUTH_CREDENTIALS:
487       InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS);
488       auth_token_.clear();
489       return OK;
490 
491     // Occurs with GSSAPI, if the user has not already logged in.
492     case ERR_MISSING_AUTH_CREDENTIALS:
493       // Usually, GSSAPI doesn't allow explicit credentials and the scheme
494       // cannot succeed anymore hence it gets disabled. However, on ChromeOS
495       // it's not the case so we invalidate the current handler and can ask for
496       // explicit credentials later. (See b/260522530).
497       if (!handler_->AllowsExplicitCredentials()) {
498         InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_DISABLE_SCHEME);
499       } else {
500         InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS);
501       }
502       auth_token_.clear();
503       return OK;
504 
505     // Can occur with GSSAPI or SSPI if the underlying library reports
506     // a permanent error.
507     case ERR_UNSUPPORTED_AUTH_SCHEME:
508 
509     // These two error codes represent failures we aren't handling.
510     case ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS:
511     case ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS:
512 
513     // Can be returned by SSPI if the authenticating authority or
514     // target is not known.
515     case ERR_MISCONFIGURED_AUTH_ENVIRONMENT:
516 
517       // In these cases, disable the current scheme as it cannot
518       // succeed.
519       InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_DISABLE_SCHEME);
520       auth_token_.clear();
521       return OK;
522 
523     default:
524       return result;
525   }
526 }
527 
OnGenerateAuthTokenDone(int result)528 void HttpAuthController::OnGenerateAuthTokenDone(int result) {
529   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
530   result = HandleGenerateTokenResult(result);
531   if (!callback_.is_null()) {
532     std::move(callback_).Run(result);
533   }
534 }
535 
TakeAuthInfo(absl::optional<AuthChallengeInfo> * other)536 void HttpAuthController::TakeAuthInfo(
537     absl::optional<AuthChallengeInfo>* other) {
538   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
539   auth_info_.swap(*other);
540 }
541 
IsAuthSchemeDisabled(HttpAuth::Scheme scheme) const542 bool HttpAuthController::IsAuthSchemeDisabled(HttpAuth::Scheme scheme) const {
543   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
544   return disabled_schemes_.find(scheme) != disabled_schemes_.end();
545 }
546 
DisableAuthScheme(HttpAuth::Scheme scheme)547 void HttpAuthController::DisableAuthScheme(HttpAuth::Scheme scheme) {
548   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
549   disabled_schemes_.insert(scheme);
550 }
551 
DisableEmbeddedIdentity()552 void HttpAuthController::DisableEmbeddedIdentity() {
553   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
554   embedded_identity_used_ = true;
555 }
556 
OnConnectionClosed()557 void HttpAuthController::OnConnectionClosed() {
558   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
559   InvalidateCurrentHandler(INVALIDATE_HANDLER);
560 }
561 
562 }  // namespace net
563