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_handler_negotiate.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/stringprintf.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/address_family.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/dns/host_resolver.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/dns/single_request_host_resolver.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_auth_filter.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/url_security_manager.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpAuthHandlerNegotiate::Factory::Factory()
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : disable_cname_lookup_(false),
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      use_port_(false),
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      resolver_(NULL),
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      max_token_length_(0),
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_creation_(true),
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      is_unsupported_(false) {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpAuthHandlerNegotiate::Factory::~Factory() {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpAuthHandlerNegotiate::Factory::set_host_resolver(
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HostResolver* resolver) {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resolver_ = resolver;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpAuthHandlerNegotiate::Factory::CreateAuthHandler(
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    HttpAuthChallengeTokenizer* challenge,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HttpAuth::Target target,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& origin,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CreateReason reason,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int digest_nonce_count,
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BoundNetLog& net_log,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<HttpAuthHandler>* handler) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_unsupported_ || reason == CREATE_PREEMPTIVE)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERR_UNSUPPORTED_AUTH_SCHEME;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (max_token_length_ == 0) {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int rv = DetermineMaxTokenLength(auth_library_.get(), NEGOSSP_NAME,
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     &max_token_length_);
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (rv == ERR_UNSUPPORTED_AUTH_SCHEME)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_unsupported_ = true;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (rv != OK)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return rv;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(cbentzel): Move towards model of parsing in the factory
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //                 method and only constructing when valid.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<HttpAuthHandler> tmp_handler(
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new HttpAuthHandlerNegotiate(auth_library_.get(), max_token_length_,
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   url_security_manager(), resolver_,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   disable_cname_lookup_, use_port_));
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log))
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERR_INVALID_RESPONSE;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handler->swap(tmp_handler);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return OK;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_POSIX)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_unsupported_)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERR_UNSUPPORTED_AUTH_SCHEME;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!auth_library_->Init()) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_unsupported_ = true;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERR_UNSUPPORTED_AUTH_SCHEME;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(ahendrickson): Move towards model of parsing in the factory
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //                     method and only constructing when valid.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<HttpAuthHandler> tmp_handler(
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new HttpAuthHandlerNegotiate(auth_library_.get(), url_security_manager(),
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   resolver_, disable_cname_lookup_,
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   use_port_));
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log))
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERR_INVALID_RESPONSE;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handler->swap(tmp_handler);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return OK;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpAuthHandlerNegotiate::HttpAuthHandlerNegotiate(
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AuthLibrary* auth_library,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ULONG max_token_length,
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLSecurityManager* url_security_manager,
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HostResolver* resolver,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool disable_cname_lookup,
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool use_port)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : auth_system_(auth_library, "Negotiate", NEGOSSP_NAME, max_token_length),
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_POSIX)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : auth_system_(auth_library, "Negotiate", CHROME_GSS_SPNEGO_MECH_OID_DESC),
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      disable_cname_lookup_(disable_cname_lookup),
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      use_port_(use_port),
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      resolver_(resolver),
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      already_called_(false),
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      has_credentials_(false),
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      auth_token_(NULL),
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_state_(STATE_NONE),
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_security_manager_(url_security_manager) {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpAuthHandlerNegotiate::~HttpAuthHandlerNegotiate() {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)std::string HttpAuthHandlerNegotiate::CreateSPN(
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AddressList& address_list, const GURL& origin) {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Kerberos Web Server SPNs are in the form HTTP/<host>:<port> through SSPI,
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and in the form HTTP@<host>:<port> through GSSAPI
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   http://msdn.microsoft.com/en-us/library/ms677601%28VS.85%29.aspx
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // However, reality differs from the specification. A good description of
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the problems can be found here:
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   http://blog.michelbarneveld.nl/michel/archive/2009/11/14/the-reason-why-kb911149-and-kb908209-are-not-the-soluton.aspx
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Typically the <host> portion should be the canonical FQDN for the service.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If this could not be resolved, the original hostname in the URL will be
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // attempted instead. However, some intranets register SPNs using aliases
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for the same canonical DNS name to allow multiple web services to reside
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // on the same host machine without requiring different ports. IE6 and IE7
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // have hotpatches that allow the default behavior to be overridden.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   http://support.microsoft.com/kb/911149
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   http://support.microsoft.com/kb/938305
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // According to the spec, the <port> option should be included if it is a
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // non-standard port (i.e. not 80 or 443 in the HTTP case). However,
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // historically browsers have not included the port, even on non-standard
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ports. IE6 required a hotpatch and a registry setting to enable
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // including non-standard ports, and IE7 and IE8 also require the same
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // registry setting, but no hotpatch. Firefox does not appear to have an
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // option to include non-standard ports as of 3.6.
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   http://support.microsoft.com/kb/908209
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Without any command-line flags, Chrome matches the behavior of Firefox
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and IE. Users can override the behavior so aliases are allowed and
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // non-standard ports are included.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int port = origin.EffectiveIntPort();
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string server = address_list.canonical_name();
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (server.empty())
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    server = origin.host();
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const char kSpnSeparator = '/';
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_POSIX)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const char kSpnSeparator = '@';
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (port != 80 && port != 443 && use_port_) {
156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return base::StringPrintf("HTTP%c%s:%d", kSpnSeparator, server.c_str(),
157a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                              port);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
159a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return base::StringPrintf("HTTP%c%s", kSpnSeparator, server.c_str());
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpAuth::AuthorizationResult HttpAuthHandlerNegotiate::HandleAnotherChallenge(
164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    HttpAuthChallengeTokenizer* challenge) {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return auth_system_.ParseChallenge(challenge);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Require identity on first pass instead of second.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpAuthHandlerNegotiate::NeedsIdentity() {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return auth_system_.NeedsIdentity();
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpAuthHandlerNegotiate::AllowsDefaultCredentials() {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (target_ == HttpAuth::AUTH_PROXY)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!url_security_manager_)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return url_security_manager_->CanUseDefaultCredentials(origin_);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpAuthHandlerNegotiate::AllowsExplicitCredentials() {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return auth_system_.AllowsExplicitCredentials();
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The Negotiate challenge header looks like:
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   WWW-Authenticate: NEGOTIATE auth-data
187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool HttpAuthHandlerNegotiate::Init(HttpAuthChallengeTokenizer* challenge) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!auth_system_.Init()) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "can't initialize GSSAPI library";
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // GSSAPI does not provide a way to enter username/password to
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // obtain a TGT. If the default credentials are not allowed for
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a particular site (based on whitelist), fall back to a
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // different scheme.
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!AllowsDefaultCredentials())
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (CanDelegate())
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    auth_system_.Delegate();
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_scheme_ = HttpAuth::AUTH_SCHEME_NEGOTIATE;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  score_ = 4;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpAuth::AuthorizationResult auth_result =
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      auth_system_.ParseChallenge(challenge);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (auth_result == HttpAuth::AUTHORIZATION_RESULT_ACCEPT);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpAuthHandlerNegotiate::GenerateAuthTokenImpl(
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AuthCredentials* credentials, const HttpRequestInfo* request,
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const CompletionCallback& callback, std::string* auth_token) {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(callback_.is_null());
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(auth_token_ == NULL);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_token_ = auth_token;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (already_called_) {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK((!has_credentials_ && credentials == NULL) ||
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           (has_credentials_ && credentials->Equals(credentials_)));
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    next_state_ = STATE_GENERATE_AUTH_TOKEN;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    already_called_ = true;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (credentials) {
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      has_credentials_ = true;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      credentials_ = *credentials;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    next_state_ = STATE_RESOLVE_CANONICAL_NAME;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rv = DoLoop(OK);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv == ERR_IO_PENDING)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback_ = callback;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpAuthHandlerNegotiate::OnIOComplete(int result) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rv = DoLoop(result);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv != ERR_IO_PENDING)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DoCallback(rv);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpAuthHandlerNegotiate::DoCallback(int rv) {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(rv != ERR_IO_PENDING);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!callback_.is_null());
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CompletionCallback callback = callback_;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback_.Reset();
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback.Run(rv);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpAuthHandlerNegotiate::DoLoop(int result) {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(next_state_ != STATE_NONE);
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rv = result;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    State state = next_state_;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    next_state_ = STATE_NONE;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (state) {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case STATE_RESOLVE_CANONICAL_NAME:
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK_EQ(OK, rv);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rv = DoResolveCanonicalName();
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case STATE_RESOLVE_CANONICAL_NAME_COMPLETE:
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rv = DoResolveCanonicalNameComplete(rv);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case STATE_GENERATE_AUTH_TOKEN:
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK_EQ(OK, rv);
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rv = DoGenerateAuthToken();
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rv = DoGenerateAuthTokenComplete(rv);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED() << "bad state";
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rv = ERR_FAILED;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpAuthHandlerNegotiate::DoResolveCanonicalName() {
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  next_state_ = STATE_RESOLVE_CANONICAL_NAME_COMPLETE;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (disable_cname_lookup_ || !resolver_)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return OK;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(cbentzel): Add reverse DNS lookup for numeric addresses.
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!single_resolve_.get());
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HostResolver::RequestInfo info(HostPortPair(origin_.host(), 0));
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info.set_host_resolver_flags(HOST_RESOLVER_CANONNAME);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  single_resolve_.reset(new SingleRequestHostResolver(resolver_));
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return single_resolve_->Resolve(
2913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      info,
2923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      DEFAULT_PRIORITY,
2933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      &address_list_,
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&HttpAuthHandlerNegotiate::OnIOComplete,
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Unretained(this)),
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net_log_);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpAuthHandlerNegotiate::DoResolveCanonicalNameComplete(int rv) {
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(ERR_IO_PENDING, rv);
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv != OK) {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Even in the error case, try to use origin_.host instead of
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // passing the failure on to the caller.
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "Problem finding canonical name for SPN for host "
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << origin_.host() << ": " << ErrorToString(rv);
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv = OK;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  next_state_ = STATE_GENERATE_AUTH_TOKEN;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  spn_ = CreateSPN(address_list_, origin_);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  address_list_ = AddressList();
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpAuthHandlerNegotiate::DoGenerateAuthToken() {
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AuthCredentials* credentials = has_credentials_ ? &credentials_ : NULL;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(cbentzel): This should possibly be done async.
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return auth_system_.GenerateAuthToken(credentials, spn_, auth_token_);
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpAuthHandlerNegotiate::DoGenerateAuthTokenComplete(int rv) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(ERR_IO_PENDING, rv);
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_token_ = NULL;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpAuthHandlerNegotiate::CanDelegate() const {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(cbentzel): Should delegation be allowed on proxies?
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (target_ == HttpAuth::AUTH_PROXY)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!url_security_manager_)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return url_security_manager_->CanDelegate(origin_);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
338