| Index: net/http/http_auth_handler_negotiate_win.cc
|
| diff --git a/net/http/http_auth_handler_negotiate_win.cc b/net/http/http_auth_handler_negotiate_win.cc
|
| index fb849d4ee2ec2c1bea8f9a34ff3fe9c08c16efa8..6c6e76700571ff7698e721b61aabed164f30f036 100644
|
| --- a/net/http/http_auth_handler_negotiate_win.cc
|
| +++ b/net/http/http_auth_handler_negotiate_win.cc
|
| @@ -5,14 +5,23 @@
|
| #include "net/http/http_auth_handler_negotiate.h"
|
|
|
| #include "base/logging.h"
|
| +#include "net/base/address_family.h"
|
| +#include "net/base/host_resolver.h"
|
| #include "net/base/net_errors.h"
|
| #include "net/http/http_auth_filter.h"
|
|
|
| namespace net {
|
|
|
| HttpAuthHandlerNegotiate::HttpAuthHandlerNegotiate(SSPILibrary* library,
|
| - ULONG max_token_length)
|
| - : auth_sspi_(library, "Negotiate", NEGOSSP_NAME, max_token_length) {
|
| + ULONG max_token_length,
|
| + bool disable_cname_lookup,
|
| + bool use_port)
|
| + : auth_sspi_(library, "Negotiate", NEGOSSP_NAME, max_token_length),
|
| + user_callback_(NULL),
|
| + ALLOW_THIS_IN_INITIALIZER_LIST(resolve_cname_callback_(
|
| + this, &HttpAuthHandlerNegotiate::OnResolveCanonicalName)),
|
| + disable_cname_lookup_(disable_cname_lookup),
|
| + use_port_(use_port) {
|
| }
|
|
|
| HttpAuthHandlerNegotiate::~HttpAuthHandlerNegotiate() {
|
| @@ -27,7 +36,7 @@ int HttpAuthHandlerNegotiate::GenerateAuthToken(
|
| return auth_sspi_.GenerateAuthToken(
|
| &username,
|
| &password,
|
| - origin_,
|
| + spn_,
|
| request,
|
| proxy,
|
| auth_token);
|
| @@ -55,6 +64,100 @@ bool HttpAuthHandlerNegotiate::SupportsDefaultCredentials() {
|
| return true;
|
| }
|
|
|
| +bool HttpAuthHandlerNegotiate::NeedsCanonicalName() {
|
| + if (!spn_.empty())
|
| + return false;
|
| + if (disable_cname_lookup_) {
|
| + spn_ = CreateSPN(address_list_, origin_);
|
| + address_list_.Reset();
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +int HttpAuthHandlerNegotiate::ResolveCanonicalName(HostResolver* resolver,
|
| + CompletionCallback* callback,
|
| + const BoundNetLog& net_log) {
|
| + // TODO(cbentzel): Add reverse DNS lookup for numeric addresses.
|
| + DCHECK(!single_resolve_.get());
|
| + DCHECK(!disable_cname_lookup_);
|
| + DCHECK(callback);
|
| +
|
| + HostResolver::RequestInfo info(origin_.host(), 0);
|
| + info.set_host_resolver_flags(HOST_RESOLVER_CANONNAME);
|
| + single_resolve_.reset(new SingleRequestHostResolver(resolver));
|
| + int rv = single_resolve_->Resolve(info, &address_list_,
|
| + &resolve_cname_callback_,
|
| + net_log);
|
| + if (rv == ERR_IO_PENDING) {
|
| + user_callback_ = callback;
|
| + return rv;
|
| + }
|
| + OnResolveCanonicalName(rv);
|
| + // Always return OK. OnResolveCanonicalName logs the error code if not
|
| + // OK and attempts to use the original origin_ hostname rather than failing
|
| + // the auth attempt completely.
|
| + return OK;
|
| +}
|
| +
|
| +void HttpAuthHandlerNegotiate::OnResolveCanonicalName(int result) {
|
| + if (result != OK) {
|
| + // Even in the error case, try to use origin_.host instead of
|
| + // passing the failure on to the caller.
|
| + LOG(INFO) << "Problem finding canonical name for SPN for host "
|
| + << origin_.host() << ": " << ErrorToString(result);
|
| + result = OK;
|
| + }
|
| + spn_ = CreateSPN(address_list_, origin_);
|
| + address_list_.Reset();
|
| + if (user_callback_) {
|
| + CompletionCallback* callback = user_callback_;
|
| + user_callback_ = NULL;
|
| + callback->Run(result);
|
| + }
|
| +}
|
| +
|
| +std::wstring HttpAuthHandlerNegotiate::CreateSPN(
|
| + const AddressList& address_list, const GURL& origin) {
|
| + // Kerberos SPNs are in the form HTTP/<host>:<port>
|
| + // http://msdn.microsoft.com/en-us/library/ms677601%28VS.85%29.aspx
|
| + //
|
| + // However, reality differs from the specification. A good description of
|
| + // the problems can be found here:
|
| + // http://blog.michelbarneveld.nl/michel/archive/2009/11/14/the-reason-why-kb911149-and-kb908209-are-not-the-soluton.aspx
|
| + //
|
| + // Typically the <host> portion should be the canonical FQDN for the service.
|
| + // If this could not be resolved, the original hostname in the URL will be
|
| + // attempted instead. However, some intranets register SPNs using aliases
|
| + // for the same canonical DNS name to allow multiple web services to reside
|
| + // on the same host machine without requiring different ports. IE6 and IE7
|
| + // have hotpatches that allow the default behavior to be overridden.
|
| + // http://support.microsoft.com/kb/911149
|
| + // http://support.microsoft.com/kb/938305
|
| + //
|
| + // According to the spec, the <port> option should be included if it is a
|
| + // non-standard port (i.e. not 80 or 443 in the HTTP case). However,
|
| + // historically browsers have not included the port, even on non-standard
|
| + // ports. IE6 required a hotpatch and a registry setting to enable
|
| + // including non-standard ports, and IE7 and IE8 also require the same
|
| + // registry setting, but no hotpatch. Firefox does not appear to have an
|
| + // option to include non-standard ports as of 3.6.
|
| + // http://support.microsoft.com/kb/908209
|
| + //
|
| + // Without any command-line flags, Chrome matches the behavior of Firefox
|
| + // and IE. Users can override the behavior so aliases are allowed and
|
| + // non-standard ports are included.
|
| + int port = origin.EffectiveIntPort();
|
| + std::string server;
|
| + if (!address_list.GetCanonicalName(&server))
|
| + server = origin.host();
|
| + if (port != 80 && port != 443 && use_port_) {
|
| + return ASCIIToWide(StringPrintf("HTTP/%s:%d", server.c_str(), port));
|
| + } else {
|
| + return ASCIIToWide(StringPrintf("HTTP/%s", server.c_str()));
|
| + }
|
| +}
|
| +
|
| int HttpAuthHandlerNegotiate::GenerateDefaultAuthToken(
|
| const HttpRequestInfo* request,
|
| const ProxyInfo* proxy,
|
| @@ -62,14 +165,16 @@ int HttpAuthHandlerNegotiate::GenerateDefaultAuthToken(
|
| return auth_sspi_.GenerateAuthToken(
|
| NULL, // username
|
| NULL, // password
|
| - origin_,
|
| + spn_,
|
| request,
|
| proxy,
|
| auth_token);
|
| }
|
|
|
| HttpAuthHandlerNegotiate::Factory::Factory()
|
| - : max_token_length_(0),
|
| + : disable_cname_lookup_(false),
|
| + use_port_(false),
|
| + max_token_length_(0),
|
| first_creation_(true),
|
| is_unsupported_(false),
|
| sspi_library_(SSPILibrary::GetDefault()) {
|
| @@ -96,7 +201,8 @@ int HttpAuthHandlerNegotiate::Factory::CreateAuthHandler(
|
| // TODO(cbentzel): Move towards model of parsing in the factory
|
| // method and only constructing when valid.
|
| scoped_refptr<HttpAuthHandler> tmp_handler(
|
| - new HttpAuthHandlerNegotiate(sspi_library_, max_token_length_));
|
| + new HttpAuthHandlerNegotiate(sspi_library_, max_token_length_,
|
| + disable_cname_lookup_, use_port_));
|
| if (!tmp_handler->InitFromChallenge(challenge, target, origin))
|
| return ERR_INVALID_RESPONSE;
|
| handler->swap(tmp_handler);
|
|
|