This source file includes following definitions.
- is_unsupported_
- set_host_resolver
- CreateAuthHandler
- url_security_manager_
- CreateSPN
- HandleAnotherChallenge
- NeedsIdentity
- AllowsDefaultCredentials
- AllowsExplicitCredentials
- Init
- GenerateAuthTokenImpl
- OnIOComplete
- DoCallback
- DoLoop
- DoResolveCanonicalName
- DoResolveCanonicalNameComplete
- DoGenerateAuthToken
- DoGenerateAuthTokenComplete
- CanDelegate
#include "net/http/http_auth_handler_negotiate.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "net/base/address_family.h"
#include "net/base/net_errors.h"
#include "net/dns/host_resolver.h"
#include "net/dns/single_request_host_resolver.h"
#include "net/http/http_auth_filter.h"
#include "net/http/url_security_manager.h"
namespace net {
HttpAuthHandlerNegotiate::Factory::Factory()
: disable_cname_lookup_(false),
use_port_(false),
resolver_(NULL),
#if defined(OS_WIN)
max_token_length_(0),
first_creation_(true),
#endif
is_unsupported_(false) {
}
HttpAuthHandlerNegotiate::Factory::~Factory() {
}
void HttpAuthHandlerNegotiate::Factory::set_host_resolver(
HostResolver* resolver) {
resolver_ = resolver;
}
int HttpAuthHandlerNegotiate::Factory::CreateAuthHandler(
HttpAuthChallengeTokenizer* challenge,
HttpAuth::Target target,
const GURL& origin,
CreateReason reason,
int digest_nonce_count,
const BoundNetLog& net_log,
scoped_ptr<HttpAuthHandler>* handler) {
#if defined(OS_WIN)
if (is_unsupported_ || reason == CREATE_PREEMPTIVE)
return ERR_UNSUPPORTED_AUTH_SCHEME;
if (max_token_length_ == 0) {
int rv = DetermineMaxTokenLength(auth_library_.get(), NEGOSSP_NAME,
&max_token_length_);
if (rv == ERR_UNSUPPORTED_AUTH_SCHEME)
is_unsupported_ = true;
if (rv != OK)
return rv;
}
scoped_ptr<HttpAuthHandler> tmp_handler(
new HttpAuthHandlerNegotiate(auth_library_.get(), max_token_length_,
url_security_manager(), resolver_,
disable_cname_lookup_, use_port_));
if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log))
return ERR_INVALID_RESPONSE;
handler->swap(tmp_handler);
return OK;
#elif defined(OS_POSIX)
if (is_unsupported_)
return ERR_UNSUPPORTED_AUTH_SCHEME;
if (!auth_library_->Init()) {
is_unsupported_ = true;
return ERR_UNSUPPORTED_AUTH_SCHEME;
}
scoped_ptr<HttpAuthHandler> tmp_handler(
new HttpAuthHandlerNegotiate(auth_library_.get(), url_security_manager(),
resolver_, disable_cname_lookup_,
use_port_));
if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log))
return ERR_INVALID_RESPONSE;
handler->swap(tmp_handler);
return OK;
#endif
}
HttpAuthHandlerNegotiate::HttpAuthHandlerNegotiate(
AuthLibrary* auth_library,
#if defined(OS_WIN)
ULONG max_token_length,
#endif
URLSecurityManager* url_security_manager,
HostResolver* resolver,
bool disable_cname_lookup,
bool use_port)
#if defined(OS_WIN)
: auth_system_(auth_library, "Negotiate", NEGOSSP_NAME, max_token_length),
#elif defined(OS_POSIX)
: auth_system_(auth_library, "Negotiate", CHROME_GSS_SPNEGO_MECH_OID_DESC),
#endif
disable_cname_lookup_(disable_cname_lookup),
use_port_(use_port),
resolver_(resolver),
already_called_(false),
has_credentials_(false),
auth_token_(NULL),
next_state_(STATE_NONE),
url_security_manager_(url_security_manager) {
}
HttpAuthHandlerNegotiate::~HttpAuthHandlerNegotiate() {
}
std::string HttpAuthHandlerNegotiate::CreateSPN(
const AddressList& address_list, const GURL& origin) {
int port = origin.EffectiveIntPort();
std::string server = address_list.canonical_name();
if (server.empty())
server = origin.host();
#if defined(OS_WIN)
static const char kSpnSeparator = '/';
#elif defined(OS_POSIX)
static const char kSpnSeparator = '@';
#endif
if (port != 80 && port != 443 && use_port_) {
return base::StringPrintf("HTTP%c%s:%d", kSpnSeparator, server.c_str(),
port);
} else {
return base::StringPrintf("HTTP%c%s", kSpnSeparator, server.c_str());
}
}
HttpAuth::AuthorizationResult HttpAuthHandlerNegotiate::HandleAnotherChallenge(
HttpAuthChallengeTokenizer* challenge) {
return auth_system_.ParseChallenge(challenge);
}
bool HttpAuthHandlerNegotiate::NeedsIdentity() {
return auth_system_.NeedsIdentity();
}
bool HttpAuthHandlerNegotiate::AllowsDefaultCredentials() {
if (target_ == HttpAuth::AUTH_PROXY)
return true;
if (!url_security_manager_)
return false;
return url_security_manager_->CanUseDefaultCredentials(origin_);
}
bool HttpAuthHandlerNegotiate::AllowsExplicitCredentials() {
return auth_system_.AllowsExplicitCredentials();
}
bool HttpAuthHandlerNegotiate::Init(HttpAuthChallengeTokenizer* challenge) {
#if defined(OS_POSIX)
if (!auth_system_.Init()) {
VLOG(1) << "can't initialize GSSAPI library";
return false;
}
if (!AllowsDefaultCredentials())
return false;
#endif
if (CanDelegate())
auth_system_.Delegate();
auth_scheme_ = HttpAuth::AUTH_SCHEME_NEGOTIATE;
score_ = 4;
properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED;
HttpAuth::AuthorizationResult auth_result =
auth_system_.ParseChallenge(challenge);
return (auth_result == HttpAuth::AUTHORIZATION_RESULT_ACCEPT);
}
int HttpAuthHandlerNegotiate::GenerateAuthTokenImpl(
const AuthCredentials* credentials, const HttpRequestInfo* request,
const CompletionCallback& callback, std::string* auth_token) {
DCHECK(callback_.is_null());
DCHECK(auth_token_ == NULL);
auth_token_ = auth_token;
if (already_called_) {
DCHECK((!has_credentials_ && credentials == NULL) ||
(has_credentials_ && credentials->Equals(credentials_)));
next_state_ = STATE_GENERATE_AUTH_TOKEN;
} else {
already_called_ = true;
if (credentials) {
has_credentials_ = true;
credentials_ = *credentials;
}
next_state_ = STATE_RESOLVE_CANONICAL_NAME;
}
int rv = DoLoop(OK);
if (rv == ERR_IO_PENDING)
callback_ = callback;
return rv;
}
void HttpAuthHandlerNegotiate::OnIOComplete(int result) {
int rv = DoLoop(result);
if (rv != ERR_IO_PENDING)
DoCallback(rv);
}
void HttpAuthHandlerNegotiate::DoCallback(int rv) {
DCHECK(rv != ERR_IO_PENDING);
DCHECK(!callback_.is_null());
CompletionCallback callback = callback_;
callback_.Reset();
callback.Run(rv);
}
int HttpAuthHandlerNegotiate::DoLoop(int result) {
DCHECK(next_state_ != STATE_NONE);
int rv = result;
do {
State state = next_state_;
next_state_ = STATE_NONE;
switch (state) {
case STATE_RESOLVE_CANONICAL_NAME:
DCHECK_EQ(OK, rv);
rv = DoResolveCanonicalName();
break;
case STATE_RESOLVE_CANONICAL_NAME_COMPLETE:
rv = DoResolveCanonicalNameComplete(rv);
break;
case STATE_GENERATE_AUTH_TOKEN:
DCHECK_EQ(OK, rv);
rv = DoGenerateAuthToken();
break;
case STATE_GENERATE_AUTH_TOKEN_COMPLETE:
rv = DoGenerateAuthTokenComplete(rv);
break;
default:
NOTREACHED() << "bad state";
rv = ERR_FAILED;
break;
}
} while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
return rv;
}
int HttpAuthHandlerNegotiate::DoResolveCanonicalName() {
next_state_ = STATE_RESOLVE_CANONICAL_NAME_COMPLETE;
if (disable_cname_lookup_ || !resolver_)
return OK;
DCHECK(!single_resolve_.get());
HostResolver::RequestInfo info(HostPortPair(origin_.host(), 0));
info.set_host_resolver_flags(HOST_RESOLVER_CANONNAME);
single_resolve_.reset(new SingleRequestHostResolver(resolver_));
return single_resolve_->Resolve(
info,
DEFAULT_PRIORITY,
&address_list_,
base::Bind(&HttpAuthHandlerNegotiate::OnIOComplete,
base::Unretained(this)),
net_log_);
}
int HttpAuthHandlerNegotiate::DoResolveCanonicalNameComplete(int rv) {
DCHECK_NE(ERR_IO_PENDING, rv);
if (rv != OK) {
VLOG(1) << "Problem finding canonical name for SPN for host "
<< origin_.host() << ": " << ErrorToString(rv);
rv = OK;
}
next_state_ = STATE_GENERATE_AUTH_TOKEN;
spn_ = CreateSPN(address_list_, origin_);
address_list_ = AddressList();
return rv;
}
int HttpAuthHandlerNegotiate::DoGenerateAuthToken() {
next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
AuthCredentials* credentials = has_credentials_ ? &credentials_ : NULL;
return auth_system_.GenerateAuthToken(credentials, spn_, auth_token_);
}
int HttpAuthHandlerNegotiate::DoGenerateAuthTokenComplete(int rv) {
DCHECK_NE(ERR_IO_PENDING, rv);
auth_token_ = NULL;
return rv;
}
bool HttpAuthHandlerNegotiate::CanDelegate() const {
if (target_ == HttpAuth::AUTH_PROXY)
return false;
if (!url_security_manager_)
return false;
return url_security_manager_->CanDelegate(origin_);
}
}