diff options
author | ahendrickson@google.com <ahendrickson@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-20 04:43:31 +0000 |
---|---|---|
committer | ahendrickson@google.com <ahendrickson@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-20 04:43:31 +0000 |
commit | cee6312f189d2cbdeaf4888170919422b6c65cdd (patch) | |
tree | abfae8530416afc36f291884638fb2543b494acc /net/http | |
parent | c91e99322f0ac5ef76165c76eb5ac3ae03f923ab (diff) | |
download | chromium_src-cee6312f189d2cbdeaf4888170919422b6c65cdd.zip chromium_src-cee6312f189d2cbdeaf4888170919422b6c65cdd.tar.gz chromium_src-cee6312f189d2cbdeaf4888170919422b6c65cdd.tar.bz2 |
Attempt to back off from Kerberos authentication if we don't have credentials.
If the user has a stale TGT, or is unable to generate a TGS for the server they are trying to communicate to, then generating an authentication token fails.
Rather than fail the entire network transaction in that case, we resend the request with an empty Authenticate (or Proxy-Authenticate) header, and remember that the Negotiate scheme is not a valid option for this particular transaction.
If the server responds back with headers like
WWW-Authenticate: Negotiate
WWW-Authenticate: Digest realm=foo
then the digest scheme is chosen in the next round.
BUG=33033
TEST=None
Review URL: http://codereview.chromium.org/3010010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@53002 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/http')
-rw-r--r-- | net/http/http_auth.cc | 7 | ||||
-rw-r--r-- | net/http/http_auth.h | 5 | ||||
-rw-r--r-- | net/http/http_auth_controller.cc | 52 | ||||
-rw-r--r-- | net/http/http_auth_controller.h | 11 | ||||
-rw-r--r-- | net/http/http_auth_gssapi_posix.cc | 3 | ||||
-rw-r--r-- | net/http/http_auth_unittest.cc | 7 |
6 files changed, 76 insertions, 9 deletions
diff --git a/net/http/http_auth.cc b/net/http/http_auth.cc index 75b55a3..ff2ac4f 100644 --- a/net/http/http_auth.cc +++ b/net/http/http_auth.cc @@ -24,6 +24,7 @@ void HttpAuth::ChooseBestChallenge( const HttpResponseHeaders* headers, Target target, const GURL& origin, + const std::set<std::string>& disabled_schemes, const BoundNetLog& net_log, scoped_ptr<HttpAuthHandler>* handler) { DCHECK(http_auth_handler_factory); @@ -56,8 +57,10 @@ void HttpAuth::ChooseBestChallenge( << ErrorToString(rv) << " Challenge: " << cur_challenge; continue; } - if (cur.get() && (!best.get() || best->score() < cur->score())) - best.swap(cur); + if (cur.get() && (!best.get() || best->score() < cur->score())) { + if (disabled_schemes.find(cur->scheme()) == disabled_schemes.end()) + best.swap(cur); + } } handler->swap(best); } diff --git a/net/http/http_auth.h b/net/http/http_auth.h index 09b6f369..01afcc0 100644 --- a/net/http/http_auth.h +++ b/net/http/http_auth.h @@ -5,6 +5,8 @@ #ifndef NET_HTTP_HTTP_AUTH_H_ #define NET_HTTP_HTTP_AUTH_H_ +#include <set> + #include "base/scoped_ptr.h" #include "net/http/http_util.h" @@ -89,6 +91,8 @@ class HttpAuth { // |*handler| is unchanged. If no supported challenge was found, |*handler| // is set to NULL. // + // |disabled_schemes| is the set of schemes that we should not use. + // // |origin| is used by the NTLM authentication scheme to construct the // service principal name. It is ignored by other schemes. // @@ -100,6 +104,7 @@ class HttpAuth { const HttpResponseHeaders* headers, Target target, const GURL& origin, + const std::set<std::string>& disabled_schemes, const BoundNetLog& net_log, scoped_ptr<HttpAuthHandler>* handler); diff --git a/net/http/http_auth_controller.cc b/net/http/http_auth_controller.cc index eaf958a..e4196ba 100644 --- a/net/http/http_auth_controller.cc +++ b/net/http/http_auth_controller.cc @@ -57,10 +57,15 @@ HttpAuthController::HttpAuthController( auth_path_(HttpAuth::AUTH_PROXY ? std::string() : auth_url.path()), embedded_identity_used_(false), default_credentials_used_(false), - session_(session) { + session_(session), + ALLOW_THIS_IN_INITIALIZER_LIST( + io_callback_(this, &HttpAuthController::OnIOComplete)), + user_callback_(NULL) { } -HttpAuthController::~HttpAuthController() {} +HttpAuthController::~HttpAuthController() { + user_callback_ = NULL; +} int HttpAuthController::MaybeGenerateAuthToken(const HttpRequestInfo* request, CompletionCallback* callback, @@ -75,8 +80,20 @@ int HttpAuthController::MaybeGenerateAuthToken(const HttpRequestInfo* request, password = &identity_.password; } DCHECK(auth_token_.empty()); - return handler_->GenerateAuthToken(username, password, request, callback, - &auth_token_); + DCHECK(NULL == user_callback_); + int rv = handler_->GenerateAuthToken(username, + password, + request, + &io_callback_, + &auth_token_); + if (rv == ERR_IO_PENDING) + user_callback_ = callback; + if (rv != ERR_IO_PENDING) + OnIOComplete(rv); + // This error occurs with GSSAPI, if the user has not already logged in. + if (rv == ERR_MISSING_AUTH_CREDENTIALS) + rv = OK; + return rv; } bool HttpAuthController::SelectPreemptiveAuth(const BoundNetLog& net_log) { @@ -119,7 +136,6 @@ bool HttpAuthController::SelectPreemptiveAuth(const BoundNetLog& net_log) { void HttpAuthController::AddAuthorizationHeader( HttpRequestHeaders* authorization_headers) { DCHECK(HaveAuth()); - DCHECK(!auth_token_.empty()); authorization_headers->SetHeader( HttpAuth::GetAuthorizationHeaderName(target_), auth_token_); auth_token_.clear(); @@ -155,7 +171,8 @@ int HttpAuthController::HandleAuthChallenge( if (target_ != HttpAuth::AUTH_SERVER || !do_not_send_server_auth) { // Find the best authentication challenge that we support. HttpAuth::ChooseBestChallenge(session_->http_auth_handler_factory(), - headers, target_, auth_origin_, net_log, + headers, target_, auth_origin_, + disabled_schemes_, net_log, &handler_); } @@ -320,4 +337,27 @@ void HttpAuthController::PopulateAuthChallenge() { auth_info_->realm = ASCIIToWide(handler_->realm()); } +void HttpAuthController::OnIOComplete(int result) { + // This error occurs with GSSAPI, if the user has not already logged in. + // In that case, disable the current scheme as it cannot succeed. + if (result == ERR_MISSING_AUTH_CREDENTIALS) { + DisableAuthScheme(handler_->scheme()); + auth_token_.erase(); + result = OK; + } + if (user_callback_) { + CompletionCallback* c = user_callback_; + user_callback_ = NULL; + c->Run(result); + } +} + +bool HttpAuthController::IsAuthSchemeDisabled(const std::string& scheme) const { + return disabled_schemes_.find(scheme) != disabled_schemes_.end(); +} + +void HttpAuthController::DisableAuthScheme(const std::string& scheme) { + disabled_schemes_.insert(scheme); +} + } // namespace net diff --git a/net/http/http_auth_controller.h b/net/http/http_auth_controller.h index b4467bd..9bc8d59 100644 --- a/net/http/http_auth_controller.h +++ b/net/http/http_auth_controller.h @@ -5,6 +5,7 @@ #ifndef NET_HTTP_HTTP_AUTH_CONTROLLER_H_ #define NET_HTTP_HTTP_AUTH_CONTROLLER_H_ +#include <set> #include <string> #include "base/basictypes.h" @@ -68,6 +69,9 @@ class HttpAuthController : public base::RefCounted<HttpAuthController> { return auth_info_; } + virtual bool IsAuthSchemeDisabled(const std::string& scheme) const; + virtual void DisableAuthScheme(const std::string& scheme); + protected: // So that we can mock this object. friend class base::RefCounted<HttpAuthController>; virtual ~HttpAuthController(); @@ -91,6 +95,8 @@ class HttpAuthController : public base::RefCounted<HttpAuthController> { // URLRequestHttpJob can prompt for a username/password. void PopulateAuthChallenge(); + void OnIOComplete(int result); + // Indicates if this handler is for Proxy auth or Server auth. HttpAuth::Target target_; @@ -131,6 +137,11 @@ class HttpAuthController : public base::RefCounted<HttpAuthController> { bool default_credentials_used_; scoped_refptr<HttpNetworkSession> session_; + + std::set<std::string> disabled_schemes_; + + CompletionCallbackImpl<HttpAuthController> io_callback_; + CompletionCallback* user_callback_; }; } // namespace net diff --git a/net/http/http_auth_gssapi_posix.cc b/net/http/http_auth_gssapi_posix.cc index a75b046..5c88375 100644 --- a/net/http/http_auth_gssapi_posix.cc +++ b/net/http/http_auth_gssapi_posix.cc @@ -725,6 +725,7 @@ int HttpAuthGSSAPI::GenerateAuthToken(const std::wstring* username, const std::wstring* password, const std::wstring& spn, std::string* auth_token) { + DCHECK(auth_token); DCHECK((username == NULL) == (password == NULL)); if (!IsFinalRound()) { @@ -821,7 +822,7 @@ int HttpAuthGSSAPI::GetNextSecurityToken(const std::wstring& spn, minor_status) << std::endl << DescribeContext(library_, scoped_sec_context_.get()); - return ERR_UNEXPECTED; + return ERR_MISSING_AUTH_CREDENTIALS; } return OK; diff --git a/net/http/http_auth_unittest.cc b/net/http/http_auth_unittest.cc index b66e0be..cdc7e16 100644 --- a/net/http/http_auth_unittest.cc +++ b/net/http/http_auth_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <set> #include <string> #include "base/ref_counted.h" @@ -70,6 +71,7 @@ TEST(HttpAuthTest, ChooseBestChallenge) { } }; GURL origin("http://www.example.com"); + std::set<std::string> disabled_schemes; URLSecurityManagerAllow url_security_manager; scoped_ptr<HttpAuthHandlerRegistryFactory> http_auth_handler_factory( HttpAuthHandlerFactory::CreateDefault()); @@ -91,6 +93,7 @@ TEST(HttpAuthTest, ChooseBestChallenge) { headers.get(), HttpAuth::AUTH_SERVER, origin, + disabled_schemes, BoundNetLog(), &handler); @@ -129,6 +132,7 @@ TEST(HttpAuthTest, ChooseBestChallengeConnectionBasedNTLM) { } }; GURL origin("http://www.example.com"); + std::set<std::string> disabled_schemes; scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory( HttpAuthHandlerFactory::CreateDefault()); @@ -152,6 +156,7 @@ TEST(HttpAuthTest, ChooseBestChallengeConnectionBasedNTLM) { headers.get(), HttpAuth::AUTH_SERVER, origin, + disabled_schemes, BoundNetLog(), &handler); EXPECT_TRUE(handler != NULL); @@ -189,6 +194,7 @@ TEST(HttpAuthTest, ChooseBestChallengeConnectionBasedNegotiate) { } }; GURL origin("http://www.example.com"); + std::set<std::string> disabled_schemes; URLSecurityManagerAllow url_security_manager; scoped_ptr<HttpAuthHandlerRegistryFactory> http_auth_handler_factory( HttpAuthHandlerFactory::CreateDefault()); @@ -211,6 +217,7 @@ TEST(HttpAuthTest, ChooseBestChallengeConnectionBasedNegotiate) { headers.get(), HttpAuth::AUTH_SERVER, origin, + disabled_schemes, BoundNetLog(), &handler); |