diff options
Diffstat (limited to 'net/http/http_auth_handler_negotiate_win.cc')
-rw-r--r-- | net/http/http_auth_handler_negotiate_win.cc | 118 |
1 files changed, 112 insertions, 6 deletions
diff --git a/net/http/http_auth_handler_negotiate_win.cc b/net/http/http_auth_handler_negotiate_win.cc index fb849d4..6c6e767 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); |