15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_auth_controller.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_util.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/platform_thread.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/auth.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/dns/host_resolver.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_auth_handler.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_auth_handler_factory.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_network_session.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_request_headers.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_request_info.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_response_headers.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns a log message for all the response headers related to the auth
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// challenge.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string AuthChallengeLogMessage(HttpResponseHeaders* headers) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string msg;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string header_val;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* iter = NULL;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (headers->EnumerateHeader(&iter, "proxy-authenticate", &header_val)) {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    msg.append("\n  Has header Proxy-Authenticate: ");
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    msg.append(header_val);
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iter = NULL;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (headers->EnumerateHeader(&iter, "www-authenticate", &header_val)) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    msg.append("\n  Has header WWW-Authenticate: ");
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    msg.append(header_val);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // RFC 4559 requires that a proxy indicate its support of NTLM/Negotiate
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // authentication with a "Proxy-Support: Session-Based-Authentication"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // response header.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iter = NULL;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (headers->EnumerateHeader(&iter, "proxy-support", &header_val)) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    msg.append("\n  Has header Proxy-Support: ");
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    msg.append(header_val);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return msg;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum AuthEvent {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AUTH_EVENT_START = 0,
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AUTH_EVENT_REJECT,
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AUTH_EVENT_MAX,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum AuthTarget {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AUTH_TARGET_PROXY = 0,
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AUTH_TARGET_SECURE_PROXY,
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AUTH_TARGET_SERVER,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AUTH_TARGET_SECURE_SERVER,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AUTH_TARGET_MAX,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AuthTarget DetermineAuthTarget(const HttpAuthHandler* handler) {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (handler->target()) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case HttpAuth::AUTH_PROXY:
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (handler->origin().SchemeIsSecure())
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return AUTH_TARGET_SECURE_PROXY;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return AUTH_TARGET_PROXY;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case HttpAuth::AUTH_SERVER:
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (handler->origin().SchemeIsSecure())
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return AUTH_TARGET_SECURE_SERVER;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return AUTH_TARGET_SERVER;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return AUTH_TARGET_MAX;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Records the number of authentication events per authentication scheme.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistogramAuthEvent(HttpAuthHandler* handler, AuthEvent auth_event) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(NDEBUG)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: The on-same-thread check is intentionally not using a lock
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to protect access to first_thread. This method is meant to be only
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // used on the same thread, in which case there are no race conditions. If
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // there are race conditions (say, a read completes during a partial write),
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the DCHECK will correctly fail.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static base::PlatformThreadId first_thread =
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::PlatformThread::CurrentId();
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(first_thread, base::PlatformThread::CurrentId());
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpAuth::Scheme auth_scheme = handler->auth_scheme();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(auth_scheme >= 0 && auth_scheme < HttpAuth::AUTH_SCHEME_MAX);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record start and rejection events for authentication.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The results map to:
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   Basic Start: 0
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   Basic Reject: 1
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   Digest Start: 2
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   Digest Reject: 3
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   NTLM Start: 4
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   NTLM Reject: 5
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   Negotiate Start: 6
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   Negotiate Reject: 7
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kEventBucketsEnd =
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HttpAuth::AUTH_SCHEME_MAX * AUTH_EVENT_MAX;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int event_bucket = auth_scheme * AUTH_EVENT_MAX + auth_event;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(event_bucket >= 0 && event_bucket < kEventBucketsEnd);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Net.HttpAuthCount", event_bucket,
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            kEventBucketsEnd);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record the target of the authentication.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The results map to:
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   Basic Proxy: 0
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   Basic Secure Proxy: 1
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   Basic Server: 2
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   Basic Secure Server: 3
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   Digest Proxy: 4
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   Digest Secure Proxy: 5
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   Digest Server: 6
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   Digest Secure Server: 7
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   NTLM Proxy: 8
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   NTLM Secure Proxy: 9
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   NTLM Server: 10
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   NTLM Secure Server: 11
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   Negotiate Proxy: 12
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   Negotiate Secure Proxy: 13
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   Negotiate Server: 14
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   Negotiate Secure Server: 15
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (auth_event != AUTH_EVENT_START)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kTargetBucketsEnd =
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HttpAuth::AUTH_SCHEME_MAX * AUTH_TARGET_MAX;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AuthTarget auth_target = DetermineAuthTarget(handler);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int target_bucket = auth_scheme * AUTH_TARGET_MAX + auth_target;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(target_bucket >= 0 && target_bucket < kTargetBucketsEnd);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Net.HttpAuthTarget", target_bucket,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            kTargetBucketsEnd);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpAuthController::HttpAuthController(
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HttpAuth::Target target,
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& auth_url,
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HttpAuthCache* http_auth_cache,
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HttpAuthHandlerFactory* http_auth_handler_factory)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : target_(target),
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      auth_url_(auth_url),
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      auth_origin_(auth_url.GetOrigin()),
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      auth_path_(HttpAuth::AUTH_PROXY ? std::string() : auth_url.path()),
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      embedded_identity_used_(false),
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default_credentials_used_(false),
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      http_auth_cache_(http_auth_cache),
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      http_auth_handler_factory_(http_auth_handler_factory) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpAuthController::~HttpAuthController() {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpAuthController::MaybeGenerateAuthToken(
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const HttpRequestInfo* request, const CompletionCallback& callback,
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BoundNetLog& net_log) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool needs_auth = HaveAuth() || SelectPreemptiveAuth(net_log);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!needs_auth)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return OK;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const AuthCredentials* credentials = NULL;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (identity_.source != HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    credentials = &identity_.credentials;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(auth_token_.empty());
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(callback_.is_null());
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rv = handler_->GenerateAuthToken(
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      credentials, request,
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&HttpAuthController::OnIOComplete, base::Unretained(this)),
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &auth_token_);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (DisableOnAuthHandlerResult(rv))
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv = OK;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv == ERR_IO_PENDING)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback_ = callback;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnIOComplete(rv);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpAuthController::SelectPreemptiveAuth(const BoundNetLog& net_log) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!HaveAuth());
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(identity_.invalid);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Don't do preemptive authorization if the URL contains a username:password,
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // since we must first be challenged in order to use the URL's identity.
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (auth_url_.has_username())
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // SelectPreemptiveAuth() is on the critical path for each request, so it
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is expected to be fast. LookupByPath() is fast in the common case, since
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the number of http auth cache entries is expected to be very small.
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (For most users in fact, it will be 0.)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpAuthCache::Entry* entry = http_auth_cache_->LookupByPath(
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      auth_origin_, auth_path_);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!entry)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try to create a handler using the previous auth challenge.
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<HttpAuthHandler> handler_preemptive;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rv_create = http_auth_handler_factory_->
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CreatePreemptiveAuthHandlerFromString(entry->auth_challenge(), target_,
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            auth_origin_,
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            entry->IncrementNonceCount(),
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            net_log, &handler_preemptive);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv_create != OK)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the state
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  identity_.source = HttpAuth::IDENT_SRC_PATH_LOOKUP;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  identity_.invalid = false;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  identity_.credentials = entry->credentials();
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handler_.swap(handler_preemptive);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpAuthController::AddAuthorizationHeader(
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HttpRequestHeaders* authorization_headers) {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(HaveAuth());
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // auth_token_ can be empty if we encountered a permanent error with
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the auth scheme and want to retry.
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!auth_token_.empty()) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    authorization_headers->SetHeader(
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        HttpAuth::GetAuthorizationHeaderName(target_), auth_token_);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    auth_token_.clear();
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpAuthController::HandleAuthChallenge(
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<HttpResponseHeaders> headers,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool do_not_send_server_auth,
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool establishing_tunnel,
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BoundNetLog& net_log) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
254868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(headers.get());
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(auth_origin_.is_valid());
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "The " << HttpAuth::GetAuthTargetString(target_) << " "
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << auth_origin_ << " requested auth "
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << AuthChallengeLogMessage(headers.get());
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Give the existing auth handler first try at the authentication headers.
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This will also evict the entry in the HttpAuthCache if the previous
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // challenge appeared to be rejected, or is using a stale nonce in the Digest
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // case.
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HaveAuth()) {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string challenge_used;
266868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    HttpAuth::AuthorizationResult result =
267868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        HttpAuth::HandleChallengeResponse(handler_.get(),
268868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                          headers.get(),
269868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                          target_,
270868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                          disabled_schemes_,
271868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                          &challenge_used);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (result) {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case HttpAuth::AUTHORIZATION_RESULT_ACCEPT:
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case HttpAuth::AUTHORIZATION_RESULT_INVALID:
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case HttpAuth::AUTHORIZATION_RESULT_REJECT:
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        HistogramAuthEvent(handler_.get(), AUTH_EVENT_REJECT);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case HttpAuth::AUTHORIZATION_RESULT_STALE:
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (http_auth_cache_->UpdateStaleChallenge(auth_origin_,
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   handler_->realm(),
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   handler_->auth_scheme(),
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   challenge_used)) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          InvalidateCurrentHandler(INVALIDATE_HANDLER);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // It's possible that a server could incorrectly issue a stale
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // response when the entry is not in the cache. Just evict the
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // current value from the cache.
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case HttpAuth::AUTHORIZATION_RESULT_DIFFERENT_REALM:
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the server changes the authentication realm in a
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // subsequent challenge, invalidate cached credentials for the
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // previous realm.  If the server rejects a preemptive
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // authorization and requests credentials for a different
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // realm, we keep the cached credentials.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        InvalidateCurrentHandler(
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            (identity_.source == HttpAuth::IDENT_SRC_PATH_LOOKUP) ?
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            INVALIDATE_HANDLER :
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS);
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  identity_.invalid = true;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool can_send_auth = (target_ != HttpAuth::AUTH_SERVER ||
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        !do_not_send_server_auth);
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do {
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!handler_.get() && can_send_auth) {
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Find the best authentication challenge that we support.
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HttpAuth::ChooseBestChallenge(http_auth_handler_factory_,
321868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                    headers.get(),
322868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                    target_,
323868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                    auth_origin_,
324868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                    disabled_schemes_,
325868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                    net_log,
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    &handler_);
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (handler_.get())
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        HistogramAuthEvent(handler_.get(), AUTH_EVENT_START);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!handler_.get()) {
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (establishing_tunnel) {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(ERROR) << "Can't perform auth to the "
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << HttpAuth::GetAuthTargetString(target_) << " "
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << auth_origin_ << " when establishing a tunnel"
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << AuthChallengeLogMessage(headers.get());
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // We are establishing a tunnel, we can't show the error page because an
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // active network attacker could control its contents.  Instead, we just
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // fail to establish the tunnel.
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK(target_ == HttpAuth::AUTH_PROXY);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return ERR_PROXY_AUTH_UNSUPPORTED;
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We found no supported challenge -- let the transaction continue so we
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // end up displaying the error page.
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return OK;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (handler_->NeedsIdentity()) {
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Pick a new auth identity to try, by looking to the URL and auth cache.
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If an identity to try is found, it is saved to identity_.
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SelectNextAuthIdentityToTry();
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Proceed with the existing identity or a null identity.
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      identity_.invalid = false;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // From this point on, we are restartable.
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (identity_.invalid) {
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We have exhausted all identity possibilities.
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!handler_->AllowsExplicitCredentials()) {
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the handler doesn't accept explicit credentials, then we need to
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // choose a different auth scheme.
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        HistogramAuthEvent(handler_.get(), AUTH_EVENT_REJECT);
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_DISABLE_SCHEME);
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Pass the challenge information back to the client.
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PopulateAuthChallenge();
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      auth_info_ = NULL;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we get here and we don't have a handler_, that's because we
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // invalidated it due to not having any viable identities to use with it. Go
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // back and try again.
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(asanka): Instead we should create a priority list of
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //     <handler,identity> and iterate through that.
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } while(!handler_.get());
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return OK;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpAuthController::ResetAuth(const AuthCredentials& credentials) {
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(identity_.invalid || credentials.Empty());
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (identity_.invalid) {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update the credentials.
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    identity_.source = HttpAuth::IDENT_SRC_EXTERNAL;
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    identity_.invalid = false;
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    identity_.credentials = credentials;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(identity_.source != HttpAuth::IDENT_SRC_PATH_LOOKUP);
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the auth entry to the cache before restarting. We don't know whether
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the identity is valid yet, but if it is valid we want other transactions
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to know about it. If an entry for (origin, handler->realm()) already
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // exists, we update it.
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If identity_.source is HttpAuth::IDENT_SRC_NONE or
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS, identity_ contains no
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // identity because identity is not required yet or we're using default
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // credentials.
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(wtc): For NTLM_SSPI, we add the same auth entry to the cache in
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // round 1 and round 2, which is redundant but correct.  It would be nice
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to add an auth entry to the cache only once, preferrably in round 1.
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See http://crbug.com/21015.
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (identity_.source) {
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case HttpAuth::IDENT_SRC_NONE:
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS:
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      http_auth_cache_->Add(auth_origin_, handler_->realm(),
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            handler_->auth_scheme(), handler_->challenge(),
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            identity_.credentials, auth_path_);
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpAuthController::HaveAuthHandler() const {
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return handler_.get() != NULL;
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpAuthController::HaveAuth() const {
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return handler_.get() && !identity_.invalid;
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpAuthController::InvalidateCurrentHandler(
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InvalidateHandlerAction action) {
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(handler_.get());
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (action == INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InvalidateRejectedAuthFromCache();
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (action == INVALIDATE_HANDLER_AND_DISABLE_SCHEME)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DisableAuthScheme(handler_->auth_scheme());
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handler_.reset();
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  identity_ = HttpAuth::Identity();
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpAuthController::InvalidateRejectedAuthFromCache() {
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(HaveAuth());
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clear the cache entry for the identity we just failed on.
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: we require the credentials to match before invalidating
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // since the entry in the cache may be newer than what we used last time.
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  http_auth_cache_->Remove(auth_origin_, handler_->realm(),
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           handler_->auth_scheme(), identity_.credentials);
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpAuthController::SelectNextAuthIdentityToTry() {
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(handler_.get());
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(identity_.invalid);
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try to use the username:password encoded into the URL first.
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (target_ == HttpAuth::AUTH_SERVER && auth_url_.has_username() &&
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !embedded_identity_used_) {
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    identity_.source = HttpAuth::IDENT_SRC_URL;
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    identity_.invalid = false;
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Extract the username:password from the URL.
466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::string16 username;
467c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::string16 password;
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetIdentityFromURL(auth_url_, &username, &password);
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    identity_.credentials.Set(username, password);
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    embedded_identity_used_ = true;
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(eroman): If the password is blank, should we also try combining
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // with a password from the cache?
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_BOOLEAN("net.HttpIdentSrcURL", true);
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check the auth cache for a realm entry.
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpAuthCache::Entry* entry =
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      http_auth_cache_->Lookup(auth_origin_, handler_->realm(),
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               handler_->auth_scheme());
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (entry) {
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    identity_.source = HttpAuth::IDENT_SRC_REALM_LOOKUP;
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    identity_.invalid = false;
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    identity_.credentials = entry->credentials();
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Use default credentials (single sign on) if this is the first attempt
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // at identity.  Do not allow multiple times as it will infinite loop.
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We use default credentials after checking the auth cache so that if
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // single sign-on doesn't work, we won't try default credentials for future
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // transactions.
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!default_credentials_used_ && handler_->AllowsDefaultCredentials()) {
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    identity_.source = HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS;
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    identity_.invalid = false;
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default_credentials_used_ = true;
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpAuthController::PopulateAuthChallenge() {
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Populates response_.auth_challenge with the authentication challenge info.
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This info is consumed by URLRequestHttpJob::GetAuthChallengeInfo().
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_info_ = new AuthChallengeInfo;
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_info_->is_proxy = (target_ == HttpAuth::AUTH_PROXY);
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_info_->challenger = HostPortPair::FromURL(auth_origin_);
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_info_->scheme = HttpAuth::SchemeToString(handler_->auth_scheme());
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_info_->realm = handler_->realm();
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpAuthController::DisableOnAuthHandlerResult(int result) {
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (result) {
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Occurs with GSSAPI, if the user has not already logged in.
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ERR_MISSING_AUTH_CREDENTIALS:
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Can occur with GSSAPI or SSPI if the underlying library reports
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // a permanent error.
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ERR_UNSUPPORTED_AUTH_SCHEME:
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // These two error codes represent failures we aren't handling.
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS:
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS:
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Can be returned by SSPI if the authenticating authority or
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // target is not known.
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ERR_MISCONFIGURED_AUTH_ENVIRONMENT:
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // In these cases, disable the current scheme as it cannot
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // succeed.
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DisableAuthScheme(handler_->auth_scheme());
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      auth_token_.clear();
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpAuthController::OnIOComplete(int result) {
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (DisableOnAuthHandlerResult(result))
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = OK;
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!callback_.is_null()) {
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CompletionCallback c = callback_;
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback_.Reset();
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c.Run(result);
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_refptr<AuthChallengeInfo> HttpAuthController::auth_info() {
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return auth_info_;
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpAuthController::IsAuthSchemeDisabled(HttpAuth::Scheme scheme) const {
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return disabled_schemes_.find(scheme) != disabled_schemes_.end();
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpAuthController::DisableAuthScheme(HttpAuth::Scheme scheme) {
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  disabled_schemes_.insert(scheme);
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void HttpAuthController::DisableEmbeddedIdentity() {
5744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(CalledOnValidThread());
5754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  embedded_identity_used_ = true;
5764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
5774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
579