diff options
author | cbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-15 14:25:50 +0000 |
---|---|---|
committer | cbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-15 14:25:50 +0000 |
commit | fa55e1931013409ddbce59ed39f8b12a351fd0c4 (patch) | |
tree | 1ff77c48d22f36173c1fa63ae8acb1faf896aa0d /net | |
parent | e8da0a0066695284dbf698c9900617b3b159f33b (diff) | |
download | chromium_src-fa55e1931013409ddbce59ed39f8b12a351fd0c4.zip chromium_src-fa55e1931013409ddbce59ed39f8b12a351fd0c4.tar.gz chromium_src-fa55e1931013409ddbce59ed39f8b12a351fd0c4.tar.bz2 |
Added factories for HttpAuthHandler.
The driving rationale for this change was to prevent choosing an AuthHandler when it
is not supported on the system due to a missing runtime component (such as not being
able to locate a gssapi shared library when seeing a Negotiate scheme).
It also has the advantage (currently unused) of determining some per-auth-scheme properties
only the first time that a challenge for that scheme is seen (such as maximum token length for
the SSPI implementation of NTLM).
Finally, it may make unit tests easier to generate since the factory can be easily mocked.
BUG=34795
TEST=New unit test for HttpAuthHandlerDispatchFactory.
Review URL: http://codereview.chromium.org/582007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@39065 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
41 files changed, 772 insertions, 270 deletions
diff --git a/net/http/http_auth.cc b/net/http/http_auth.cc index aa97640..83da9ad 100644 --- a/net/http/http_auth.cc +++ b/net/http/http_auth.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,6 +8,7 @@ #include "base/basictypes.h" #include "base/string_util.h" +#include "net/base/net_errors.h" #include "net/http/http_auth_handler_basic.h" #include "net/http/http_auth_handler_digest.h" #include "net/http/http_auth_handler_negotiate.h" @@ -18,10 +19,14 @@ namespace net { // static -void HttpAuth::ChooseBestChallenge(const HttpResponseHeaders* headers, - Target target, - const GURL& origin, - scoped_refptr<HttpAuthHandler>* handler) { +void HttpAuth::ChooseBestChallenge( + HttpAuthHandlerFactory* http_auth_handler_factory, + const HttpResponseHeaders* headers, + Target target, + const GURL& origin, + scoped_refptr<HttpAuthHandler>* handler) { + DCHECK(http_auth_handler_factory); + // A connection-based authentication scheme must continue to use the // existing handler object in |*handler|. if (*handler && (*handler)->is_connection_based()) { @@ -31,8 +36,7 @@ void HttpAuth::ChooseBestChallenge(const HttpResponseHeaders* headers, while (headers->EnumerateHeader(&iter, header_name, &challenge)) { ChallengeTokenizer props(challenge.begin(), challenge.end()); if (LowerCaseEqualsASCII(props.scheme(), (*handler)->scheme().c_str()) && - (*handler)->InitFromChallenge(challenge.begin(), challenge.end(), - target, origin)) + (*handler)->InitFromChallenge(&props, target, origin)) return; } } @@ -44,45 +48,19 @@ void HttpAuth::ChooseBestChallenge(const HttpResponseHeaders* headers, void* iter = NULL; while (headers->EnumerateHeader(&iter, header_name, &cur_challenge)) { scoped_refptr<HttpAuthHandler> cur; - CreateAuthHandler(cur_challenge, target, origin, &cur); + int rv = http_auth_handler_factory->CreateAuthHandlerFromString( + cur_challenge, target, origin, &cur); + if (rv != OK) { + LOG(WARNING) << "Unable to create AuthHandler. Status: " + << ErrorToString(rv) << " Challenge: " << cur_challenge; + continue; + } if (cur && (!best || best->score() < cur->score())) best.swap(cur); } handler->swap(best); } -// static -void HttpAuth::CreateAuthHandler(const std::string& challenge, - Target target, - const GURL& origin, - scoped_refptr<HttpAuthHandler>* handler) { - // Find the right auth handler for the challenge's scheme. - ChallengeTokenizer props(challenge.begin(), challenge.end()); - if (!props.valid()) { - *handler = NULL; - return; - } - - scoped_refptr<HttpAuthHandler> tmp_handler; - if (LowerCaseEqualsASCII(props.scheme(), "basic")) { - tmp_handler = new HttpAuthHandlerBasic(); - } else if (LowerCaseEqualsASCII(props.scheme(), "digest")) { - tmp_handler = new HttpAuthHandlerDigest(); - } else if (LowerCaseEqualsASCII(props.scheme(), "negotiate")) { - tmp_handler = new HttpAuthHandlerNegotiate(); - } else if (LowerCaseEqualsASCII(props.scheme(), "ntlm")) { - tmp_handler = new HttpAuthHandlerNTLM(); - } - if (tmp_handler) { - if (!tmp_handler->InitFromChallenge(challenge.begin(), challenge.end(), - target, origin)) { - // Invalid/unsupported challenge. - tmp_handler = NULL; - } - } - handler->swap(tmp_handler); -} - void HttpAuth::ChallengeTokenizer::Init(std::string::const_iterator begin, std::string::const_iterator end) { // The first space-separated token is the auth-scheme. @@ -115,6 +93,21 @@ bool HttpAuth::ChallengeTokenizer::GetNext() { value_end_ = props_.value_end(); name_begin_ = name_end_ = value_end_; + if (expect_base64_token_) { + expect_base64_token_ = false; + // Strip off any padding. + // (See https://bugzilla.mozilla.org/show_bug.cgi?id=230351.) + // + // Our base64 decoder requires that the length be a multiple of 4. + int encoded_length = value_end_ - value_begin_; + while (encoded_length > 0 && encoded_length % 4 != 0 && + value_begin_[encoded_length - 1] == '=') { + --encoded_length; + --value_end_; + } + return true; + } + // Scan for the equals sign. std::string::const_iterator equals = std::find(value_begin_, value_end_, '='); if (equals == value_end_ || equals == value_begin_) diff --git a/net/http/http_auth.h b/net/http/http_auth.h index 38c9918..76deca8 100644 --- a/net/http/http_auth.h +++ b/net/http/http_auth.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -12,6 +12,7 @@ template <class T> class scoped_refptr; namespace net { class HttpAuthHandler; +class HttpAuthHandlerFactory; class HttpResponseHeaders; // Utility class for http authentication. @@ -70,14 +71,6 @@ class HttpAuth { // (either Authorization or Proxy-Authorization). static std::string GetAuthorizationHeaderName(Target target); - // Create a handler to generate credentials for the challenge, and pass - // it back in |*handler|. If the challenge is unsupported or invalid - // |*handler| is set to NULL. - static void CreateAuthHandler(const std::string& challenge, - Target target, - const GURL& origin, - scoped_refptr<HttpAuthHandler>* handler); - // Iterate through the challenge headers, and pick the best one that // we support. Obtains the implementation class for handling the challenge, // and passes it back in |*handler|. If the existing handler in |*handler| @@ -91,10 +84,12 @@ class HttpAuth { // TODO(wtc): Continuing to use the existing handler in |*handler| (for // NTLM) is new behavior. Rename ChooseBestChallenge to fully encompass // what it does now. - static void ChooseBestChallenge(const HttpResponseHeaders* headers, - Target target, - const GURL& origin, - scoped_refptr<HttpAuthHandler>* handler); + static void ChooseBestChallenge( + HttpAuthHandlerFactory* http_auth_handler_factory, + const HttpResponseHeaders* headers, + Target target, + const GURL& origin, + scoped_refptr<HttpAuthHandler>* handler); // ChallengeTokenizer breaks up a challenge string into the the auth scheme // and parameter list, according to RFC 2617 Sec 1.2: @@ -107,7 +102,7 @@ class HttpAuth { public: ChallengeTokenizer(std::string::const_iterator begin, std::string::const_iterator end) - : props_(begin, end, ','), valid_(true) { + : props_(begin, end, ','), valid_(true), expect_base64_token_(false) { Init(begin, end); } @@ -127,6 +122,17 @@ class HttpAuth { // Returns true if there is none to consume. bool GetNext(); + // Inform the tokenizer whether the next token should be treated as a base64 + // encoded value. If |expect_base64_token| is true, |GetNext| will treat the + // next token as a base64 encoded value, and will include the trailing '=' + // padding rather than attempt to split the token into a name/value pair. + // In this case, |name| will be empty, and |value| will contain the token. + // Subsequent calls to |GetNext()| will not treat the token like a base64 + // encoded token unless the caller again calls |set_expect_base64_token|. + void set_expect_base64_token(bool expect_base64_token) { + expect_base64_token_ = expect_base64_token; + } + // The name of the current name-value pair. std::string::const_iterator name_begin() const { return name_begin_; } std::string::const_iterator name_end() const { return name_end_; } @@ -164,6 +170,7 @@ class HttpAuth { std::string::const_iterator value_end_; bool value_is_quoted_; + bool expect_base64_token_; }; }; diff --git a/net/http/http_auth_cache_unittest.cc b/net/http/http_auth_cache_unittest.cc index b00e8d0..c233f01 100644 --- a/net/http/http_auth_cache_unittest.cc +++ b/net/http/http_auth_cache_unittest.cc @@ -41,7 +41,7 @@ class MockAuthHandler : public HttpAuthHandler { } protected: - virtual bool Init(std::string::const_iterator, std::string::const_iterator) { + virtual bool Init(HttpAuth::ChallengeTokenizer* challenge) { return false; // Unused. } diff --git a/net/http/http_auth_handler.cc b/net/http/http_auth_handler.cc index 9d70ca0..e61de2f 100644 --- a/net/http/http_auth_handler.cc +++ b/net/http/http_auth_handler.cc @@ -5,20 +5,19 @@ #include "net/http/http_auth_handler.h" #include "base/logging.h" -#include "net/base/net_errors.h" namespace net { -bool HttpAuthHandler::InitFromChallenge(std::string::const_iterator begin, - std::string::const_iterator end, - HttpAuth::Target target, - const GURL& origin) { +bool HttpAuthHandler::InitFromChallenge( + HttpAuth::ChallengeTokenizer* challenge, + HttpAuth::Target target, + const GURL& origin) { origin_ = origin; target_ = target; score_ = -1; properties_ = -1; - bool ok = Init(begin, end); + bool ok = Init(challenge); // Init() is expected to set the scheme, realm, score, and properties. The // realm may be empty. diff --git a/net/http/http_auth_handler.h b/net/http/http_auth_handler.h index 4b8f5261..dc0543e 100644 --- a/net/http/http_auth_handler.h +++ b/net/http/http_auth_handler.h @@ -16,14 +16,16 @@ class HttpRequestInfo; class ProxyInfo; // HttpAuthHandler is the interface for the authentication schemes -// (basic, digest, ...) -// The registry mapping auth-schemes to implementations is hardcoded in -// HttpAuth::CreateAuthHandler(). +// (basic, digest, NTLM, Negotiate). +// HttpAuthHandler objects are typically created by an HttpAuthHandlerFactory. class HttpAuthHandler : public base::RefCounted<HttpAuthHandler> { public: - // Initialize the handler by parsing a challenge string. - bool InitFromChallenge(std::string::const_iterator begin, - std::string::const_iterator end, + // Initializes the handler using a challenge issued by a server. + // |challenge| must be non-NULL and have already tokenized the + // authentication scheme, but none of the tokens occuring after the + // authentication scheme. |target| and |origin| are both stored + // for later use, and are not part of the initial challenge. + bool InitFromChallenge(HttpAuth::ChallengeTokenizer* challenge, HttpAuth::Target target, const GURL& origin); @@ -109,11 +111,13 @@ class HttpAuthHandler : public base::RefCounted<HttpAuthHandler> { virtual ~HttpAuthHandler() { } - // Initialize the handler by parsing a challenge string. + // Initializes the handler using a challenge issued by a server. + // |challenge| must be non-NULL and have already tokenized the + // authentication scheme, but none of the tokens occuring after the + // authentication scheme. // Implementations are expcted to initialize the following members: // scheme_, realm_, score_, properties_ - virtual bool Init(std::string::const_iterator challenge_begin, - std::string::const_iterator challenge_end) = 0; + virtual bool Init(HttpAuth::ChallengeTokenizer* challenge) = 0; // The lowercase auth-scheme {"basic", "digest", "ntlm", ...} std::string scheme_; diff --git a/net/http/http_auth_handler_basic.cc b/net/http/http_auth_handler_basic.cc index 2c70577..3510ee2 100644 --- a/net/http/http_auth_handler_basic.cc +++ b/net/http/http_auth_handler_basic.cc @@ -21,25 +21,23 @@ namespace net { // // We allow it to be compatibility with certain embedded webservers that don't // include a realm (see http://crbug.com/20984.) -bool HttpAuthHandlerBasic::Init(std::string::const_iterator challenge_begin, - std::string::const_iterator challenge_end) { +bool HttpAuthHandlerBasic::Init(HttpAuth::ChallengeTokenizer* challenge) { scheme_ = "basic"; score_ = 1; properties_ = 0; // Verify the challenge's auth-scheme. - HttpAuth::ChallengeTokenizer challenge_tok(challenge_begin, challenge_end); - if (!challenge_tok.valid() || - !LowerCaseEqualsASCII(challenge_tok.scheme(), "basic")) + if (!challenge->valid() || + !LowerCaseEqualsASCII(challenge->scheme(), "basic")) return false; // Extract the realm (may be missing). - while (challenge_tok.GetNext()) { - if (LowerCaseEqualsASCII(challenge_tok.name(), "realm")) - realm_ = challenge_tok.unquoted_value(); + while (challenge->GetNext()) { + if (LowerCaseEqualsASCII(challenge->name(), "realm")) + realm_ = challenge->unquoted_value(); } - return challenge_tok.valid(); + return challenge->valid(); } int HttpAuthHandlerBasic::GenerateAuthToken( @@ -68,5 +66,24 @@ int HttpAuthHandlerBasic::GenerateDefaultAuthToken( return ERR_NOT_IMPLEMENTED; } +HttpAuthHandlerBasic::Factory::Factory() { +} + +HttpAuthHandlerBasic::Factory::~Factory() { +} + +int HttpAuthHandlerBasic::Factory::CreateAuthHandler( + HttpAuth::ChallengeTokenizer* challenge, + HttpAuth::Target target, + const GURL& origin, + scoped_refptr<HttpAuthHandler>* handler) { + // TODO(cbentzel): Move towards model of parsing in the factory + // method and only constructing when valid. + scoped_refptr<HttpAuthHandler> tmp_handler(new HttpAuthHandlerBasic()); + if (!tmp_handler->InitFromChallenge(challenge, target, origin)) + return ERR_INVALID_RESPONSE; + handler->swap(tmp_handler); + return OK; +} } // namespace net diff --git a/net/http/http_auth_handler_basic.h b/net/http/http_auth_handler_basic.h index e4d2f25..be63e21 100644 --- a/net/http/http_auth_handler_basic.h +++ b/net/http/http_auth_handler_basic.h @@ -6,12 +6,24 @@ #define NET_HTTP_HTTP_AUTH_HANDLER_BASIC_H_ #include "net/http/http_auth_handler.h" +#include "net/http/http_auth_handler_factory.h" namespace net { // Code for handling http basic authentication. class HttpAuthHandlerBasic : public HttpAuthHandler { public: + class Factory : public HttpAuthHandlerFactory { + public: + Factory(); + virtual ~Factory(); + + virtual int CreateAuthHandler(HttpAuth::ChallengeTokenizer* challenge, + HttpAuth::Target target, + const GURL& origin, + scoped_refptr<HttpAuthHandler>* handler); + }; + virtual int GenerateAuthToken(const std::wstring& username, const std::wstring& password, const HttpRequestInfo*, @@ -22,10 +34,8 @@ class HttpAuthHandlerBasic : public HttpAuthHandler { const ProxyInfo* proxy, std::string* auth_token); - protected: - virtual bool Init(std::string::const_iterator challenge_begin, - std::string::const_iterator challenge_end); + virtual bool Init(HttpAuth::ChallengeTokenizer* challenge); private: ~HttpAuthHandlerBasic() {} diff --git a/net/http/http_auth_handler_basic_unittest.cc b/net/http/http_auth_handler_basic_unittest.cc index 59d9a56..3536c2c 100644 --- a/net/http/http_auth_handler_basic_unittest.cc +++ b/net/http/http_auth_handler_basic_unittest.cc @@ -25,12 +25,12 @@ TEST(HttpAuthHandlerBasicTest, GenerateAuthToken) { { L"", L"", "Basic Og==" }, }; GURL origin("http://www.example.com"); + HttpAuthHandlerBasic::Factory factory; for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { std::string challenge = "Basic realm=\"Atlantis\""; - scoped_refptr<HttpAuthHandlerBasic> basic = new HttpAuthHandlerBasic; - bool ok = basic->InitFromChallenge(challenge.begin(), challenge.end(), - HttpAuth::AUTH_SERVER, origin); - EXPECT_TRUE(ok); + scoped_refptr<HttpAuthHandler> basic = new HttpAuthHandlerBasic; + EXPECT_EQ(OK, factory.CreateAuthHandlerFromString( + challenge, HttpAuth::AUTH_SERVER, origin, &basic)); std::string credentials; int rv = basic->GenerateAuthToken(tests[i].username, tests[i].password, @@ -45,32 +45,33 @@ TEST(HttpAuthHandlerBasicTest, GenerateAuthToken) { TEST(HttpAuthHandlerBasicTest, InitFromChallenge) { static const struct { const char* challenge; - bool expected_success; + int expected_rv; const char* expected_realm; } tests[] = { // No realm (we allow this even though realm is supposed to be required // according to RFC 2617.) { "Basic", - true, + OK, "", }, // Realm is empty string. { "Basic realm=\"\"", - true, + OK, "", }, }; + HttpAuthHandlerBasic::Factory factory; GURL origin("http://www.example.com"); for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { std::string challenge = tests[i].challenge; - scoped_refptr<HttpAuthHandlerBasic> basic = new HttpAuthHandlerBasic; - bool ok = basic->InitFromChallenge(challenge.begin(), challenge.end(), - HttpAuth::AUTH_SERVER, origin); - EXPECT_EQ(tests[i].expected_success, ok); - if (ok) + scoped_refptr<HttpAuthHandler> basic = new HttpAuthHandlerBasic; + int rv = factory.CreateAuthHandlerFromString( + challenge, HttpAuth::AUTH_SERVER, origin, &basic); + EXPECT_EQ(tests[i].expected_rv, rv); + if (rv == OK) EXPECT_EQ(tests[i].expected_realm, basic->realm()); } } diff --git a/net/http/http_auth_handler_digest.cc b/net/http/http_auth_handler_digest.cc index 10af291..9441ba8 100644 --- a/net/http/http_auth_handler_digest.cc +++ b/net/http/http_auth_handler_digest.cc @@ -216,8 +216,7 @@ std::string HttpAuthHandlerDigest::AssembleCredentials( // send the realm (See http://crbug.com/20984 for an instance where a // webserver was not sending the realm with a BASIC challenge). bool HttpAuthHandlerDigest::ParseChallenge( - std::string::const_iterator challenge_begin, - std::string::const_iterator challenge_end) { + HttpAuth::ChallengeTokenizer* challenge) { scheme_ = "digest"; score_ = 2; properties_ = ENCRYPTS_IDENTITY; @@ -228,24 +227,23 @@ bool HttpAuthHandlerDigest::ParseChallenge( qop_ = QOP_UNSPECIFIED; realm_ = nonce_ = domain_ = opaque_ = std::string(); - HttpAuth::ChallengeTokenizer props(challenge_begin, challenge_end); - - if (!props.valid() || !LowerCaseEqualsASCII(props.scheme(), "digest")) + if (!challenge->valid() || + !LowerCaseEqualsASCII(challenge->scheme(), "digest")) return false; // FAIL -- Couldn't match auth-scheme. // Loop through all the properties. - while (props.GetNext()) { - if (props.value().empty()) { + while (challenge->GetNext()) { + if (challenge->value().empty()) { DLOG(INFO) << "Invalid digest property"; return false; } - if (!ParseChallengeProperty(props.name(), props.unquoted_value())) + if (!ParseChallengeProperty(challenge->name(), challenge->unquoted_value())) return false; // FAIL -- couldn't parse a property. } // Check if tokenizer failed. - if (!props.valid()) + if (!challenge->valid()) return false; // FAIL // Check that a minimum set of properties were provided. @@ -295,4 +293,24 @@ bool HttpAuthHandlerDigest::ParseChallengeProperty(const std::string& name, return true; } +HttpAuthHandlerDigest::Factory::Factory() { +} + +HttpAuthHandlerDigest::Factory::~Factory() { +} + +int HttpAuthHandlerDigest::Factory::CreateAuthHandler( + HttpAuth::ChallengeTokenizer* challenge, + HttpAuth::Target target, + const GURL& origin, + scoped_refptr<HttpAuthHandler>* handler) { + // TODO(cbentzel): Move towards model of parsing in the factory + // method and only constructing when valid. + scoped_refptr<HttpAuthHandler> tmp_handler(new HttpAuthHandlerDigest()); + if (!tmp_handler->InitFromChallenge(challenge, target, origin)) + return ERR_INVALID_RESPONSE; + handler->swap(tmp_handler); + return OK; +} + } // namespace net diff --git a/net/http/http_auth_handler_digest.h b/net/http/http_auth_handler_digest.h index 686f354..f718a14 100644 --- a/net/http/http_auth_handler_digest.h +++ b/net/http/http_auth_handler_digest.h @@ -6,6 +6,7 @@ #define NET_HTTP_HTTP_AUTH_HANDLER_DIGEST_H_ #include "net/http/http_auth_handler.h" +#include "net/http/http_auth_handler_factory.h" // This is needed for the FRIEND_TEST() macro. #include "testing/gtest/include/gtest/gtest_prod.h" @@ -15,6 +16,17 @@ namespace net { // Code for handling http digest authentication. class HttpAuthHandlerDigest : public HttpAuthHandler { public: + class Factory : public HttpAuthHandlerFactory { + public: + Factory(); + virtual ~Factory(); + + virtual int CreateAuthHandler(HttpAuth::ChallengeTokenizer* challenge, + HttpAuth::Target target, + const GURL& origin, + scoped_refptr<HttpAuthHandler>* handler); + }; + virtual int GenerateAuthToken(const std::wstring& username, const std::wstring& password, const HttpRequestInfo* request, @@ -26,10 +38,9 @@ class HttpAuthHandlerDigest : public HttpAuthHandler { std::string* auth_token); protected: - virtual bool Init(std::string::const_iterator challenge_begin, - std::string::const_iterator challenge_end) { + virtual bool Init(HttpAuth::ChallengeTokenizer* challenge) { nonce_count_ = 0; - return ParseChallenge(challenge_begin, challenge_end); + return ParseChallenge(challenge); } private: @@ -62,8 +73,7 @@ class HttpAuthHandlerDigest : public HttpAuthHandler { // Parse the challenge, saving the results into this instance. // Returns true on success. - bool ParseChallenge(std::string::const_iterator challenge_begin, - std::string::const_iterator challenge_end); + bool ParseChallenge(HttpAuth::ChallengeTokenizer* challenge); // Parse an individual property. Returns true on success. bool ParseChallengeProperty(const std::string& name, diff --git a/net/http/http_auth_handler_digest_unittest.cc b/net/http/http_auth_handler_digest_unittest.cc index eb5649b..e75ada4 100644 --- a/net/http/http_auth_handler_digest_unittest.cc +++ b/net/http/http_auth_handler_digest_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -104,7 +104,8 @@ TEST(HttpAuthHandlerDigestTest, ParseChallenge) { std::string challenge(tests[i].challenge); scoped_refptr<HttpAuthHandlerDigest> digest = new HttpAuthHandlerDigest; - bool ok = digest->ParseChallenge(challenge.begin(), challenge.end()); + HttpAuth::ChallengeTokenizer tok(challenge.begin(), challenge.end()); + bool ok = digest->ParseChallenge(&tok); EXPECT_EQ(tests[i].parsed_success, ok); EXPECT_STREQ(tests[i].parsed_realm, digest->realm_.c_str()); @@ -252,8 +253,8 @@ TEST(HttpAuthHandlerDigestTest, AssembleCredentials) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { scoped_refptr<HttpAuthHandlerDigest> digest = new HttpAuthHandlerDigest; std::string challenge = tests[i].challenge; - EXPECT_TRUE(digest->InitFromChallenge( - challenge.begin(), challenge.end(), HttpAuth::AUTH_SERVER, origin)); + HttpAuth::ChallengeTokenizer tok(challenge.begin(), challenge.end()); + EXPECT_TRUE(digest->InitFromChallenge(&tok, HttpAuth::AUTH_SERVER, origin)); std::string creds = digest->AssembleCredentials(tests[i].req_method, tests[i].req_path, tests[i].username, tests[i].password, diff --git a/net/http/http_auth_handler_factory.cc b/net/http/http_auth_handler_factory.cc new file mode 100644 index 0000000..36f1fcf --- /dev/null +++ b/net/http/http_auth_handler_factory.cc @@ -0,0 +1,82 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/http/http_auth_handler_factory.h" + +#include "base/stl_util-inl.h" +#include "base/string_util.h" +#include "net/base/net_errors.h" +#include "net/http/http_auth_handler_basic.h" +#include "net/http/http_auth_handler_digest.h" +#include "net/http/http_auth_handler_negotiate.h" +#include "net/http/http_auth_handler_ntlm.h" + +namespace net { + +int HttpAuthHandlerFactory::CreateAuthHandlerFromString( + const std::string& challenge, + HttpAuth::Target target, + const GURL& origin, + scoped_refptr<HttpAuthHandler>* handler) { + HttpAuth::ChallengeTokenizer props(challenge.begin(), challenge.end()); + return CreateAuthHandler(&props, target, origin, handler); +} + +// static +HttpAuthHandlerFactory* HttpAuthHandlerFactory::CreateDefault() { + HttpAuthHandlerRegistryFactory* registry_factory = + new HttpAuthHandlerRegistryFactory(); + registry_factory->RegisterSchemeFactory( + "basic", new HttpAuthHandlerBasic::Factory()); + registry_factory->RegisterSchemeFactory( + "digest", new HttpAuthHandlerDigest::Factory()); + registry_factory->RegisterSchemeFactory( + "negotiate", new HttpAuthHandlerNegotiate::Factory()); + registry_factory->RegisterSchemeFactory( + "ntlm", new HttpAuthHandlerNTLM::Factory()); + return registry_factory; +} + +HttpAuthHandlerRegistryFactory::HttpAuthHandlerRegistryFactory() { +} + +HttpAuthHandlerRegistryFactory::~HttpAuthHandlerRegistryFactory() { + STLDeleteContainerPairSecondPointers(factory_map_.begin(), + factory_map_.end()); +} + +void HttpAuthHandlerRegistryFactory::RegisterSchemeFactory( + const std::string& scheme, + HttpAuthHandlerFactory* factory) { + std::string lower_scheme = StringToLowerASCII(scheme); + FactoryMap::iterator it = factory_map_.find(lower_scheme); + if (it != factory_map_.end()) { + delete it->second; + } + if (factory) + factory_map_[lower_scheme] = factory; + else + factory_map_.erase(it); +} + +int HttpAuthHandlerRegistryFactory::CreateAuthHandler( + HttpAuth::ChallengeTokenizer* challenge, + HttpAuth::Target target, + const GURL& origin, + scoped_refptr<HttpAuthHandler>* handler) { + if (!challenge->valid()) { + *handler = NULL; + return ERR_INVALID_RESPONSE; + } + std::string lower_scheme = StringToLowerASCII(challenge->scheme()); + FactoryMap::iterator it = factory_map_.find(lower_scheme); + if (it == factory_map_.end()) { + *handler = NULL; + return ERR_UNSUPPORTED_AUTH_SCHEME; + } + DCHECK(it->second); + return it->second->CreateAuthHandler(challenge, target, origin, handler); +} + +} // namespace net diff --git a/net/http/http_auth_handler_factory.h b/net/http/http_auth_handler_factory.h new file mode 100644 index 0000000..d0fec29 --- /dev/null +++ b/net/http/http_auth_handler_factory.h @@ -0,0 +1,96 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_HTTP_HTTP_AUTH_HANDLER_FACTORY_H +#define NET_HTTP_HTTP_AUTH_HANDLER_FACTORY_H + +#include <map> + +#include "net/http/http_auth.h" + +class GURL; + +namespace net { + +class HttpAuthHandler; + +// An HttpAuthHandlerFactory is used to create HttpAuthHandler objects. +class HttpAuthHandlerFactory { + public: + HttpAuthHandlerFactory() {} + virtual ~HttpAuthHandlerFactory() {} + + // Creates an HttpAuthHandler object based on the authentication + // challenge specified by |*challenge|. |challenge| must point to a valid + // non-NULL tokenizer. + // + // If an HttpAuthHandler object is successfully created it is passed back to + // the caller through |*handler| and OK is returned. + // + // If |*challenge| specifies an unsupported authentication scheme, |*handler| + // is set to NULL and ERR_UNSUPPORTED_AUTH_SCHEME is returned. + // + // If |*challenge| is improperly formed, |*handler| is set to NULL and + // ERR_INVALID_RESPONSE is returned. + // + // |*challenge| should not be reused after a call to |CreateAuthHandler()|, + virtual int CreateAuthHandler(HttpAuth::ChallengeTokenizer* challenge, + HttpAuth::Target target, + const GURL& origin, + scoped_refptr<HttpAuthHandler>* handler) = 0; + + // Creates an HTTP authentication handler based on the authentication + // challenge string |challenge|. + // This is a convenience function which creates a ChallengeTokenizer for + // |challenge| and calls |CreateAuthHandler|. See |CreateAuthHandler| for + // more details on return values. + int CreateAuthHandlerFromString(const std::string& challenge, + HttpAuth::Target target, + const GURL& origin, + scoped_refptr<HttpAuthHandler>* handler); + + // Creates a standard HttpAuthHandlerFactory. The caller is responsible + // for deleting the factory. + // The default factory support Basic, Digest, NTLM, and Negotiate schemes. + static HttpAuthHandlerFactory* CreateDefault(); + + private: + DISALLOW_COPY_AND_ASSIGN(HttpAuthHandlerFactory); +}; + +// The HttpAuthHandlerRegistryFactory dispatches create requests out +// to other factories based on the auth scheme. +class HttpAuthHandlerRegistryFactory : public HttpAuthHandlerFactory { + public: + HttpAuthHandlerRegistryFactory(); + virtual ~HttpAuthHandlerRegistryFactory(); + + // Registers a |factory| that will be used for a particular HTTP + // authentication scheme such as Basic, Digest, or Negotiate. + // The |*factory| object is assumed to be new-allocated, and its lifetime + // will be managed by this HttpAuthHandlerRegistryFactory object (including + // deleting it when it is no longer used. + // A NULL |factory| value means that HttpAuthHandlers's will not be created + // for |scheme|. If a factory object used to exist for |scheme|, it will be + // deleted. + void RegisterSchemeFactory(const std::string& scheme, + HttpAuthHandlerFactory* factory); + + // Creates an auth handler by dispatching out to the registered factories + // based on the first token in |challenge|. + virtual int CreateAuthHandler(HttpAuth::ChallengeTokenizer* challenge, + HttpAuth::Target target, + const GURL& origin, + scoped_refptr<HttpAuthHandler>* handler); + + private: + typedef std::map<std::string, HttpAuthHandlerFactory*> FactoryMap; + + FactoryMap factory_map_; + DISALLOW_COPY_AND_ASSIGN(HttpAuthHandlerRegistryFactory); +}; + +} // namespace net + +#endif // NET_HTTP_HTTP_AUTH_HANDLER_FACTORY_H diff --git a/net/http/http_auth_handler_factory_unittest.cc b/net/http/http_auth_handler_factory_unittest.cc new file mode 100644 index 0000000..e67bcca --- /dev/null +++ b/net/http/http_auth_handler_factory_unittest.cc @@ -0,0 +1,177 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/scoped_ptr.h" +#include "net/base/net_errors.h" +#include "net/http/http_auth_handler.h" +#include "net/http/http_auth_handler_factory.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +class MockHttpAuthHandlerFactory : public HttpAuthHandlerFactory { + public: + explicit MockHttpAuthHandlerFactory(int return_code) : + return_code_(return_code) {} + virtual ~MockHttpAuthHandlerFactory() {} + + virtual int CreateAuthHandler(HttpAuth::ChallengeTokenizer* challenge, + HttpAuth::Target target, + const GURL& origin, + scoped_refptr<HttpAuthHandler>* handler) { + *handler = NULL; + return return_code_; + } + + private: + int return_code_; +}; + +TEST(HttpAuthHandlerFactoryTest, RegistryFactory) { + HttpAuthHandlerRegistryFactory registry_factory; + GURL gurl("www.google.com"); + const int kBasicReturnCode = ERR_INVALID_SPDY_STREAM; + MockHttpAuthHandlerFactory* mock_factory_basic = + new MockHttpAuthHandlerFactory(kBasicReturnCode); + + const int kDigestReturnCode = ERR_PAC_SCRIPT_FAILED; + MockHttpAuthHandlerFactory* mock_factory_digest = + new MockHttpAuthHandlerFactory(kDigestReturnCode); + + const int kDigestReturnCodeReplace = ERR_SYN_REPLY_NOT_RECEIVED; + MockHttpAuthHandlerFactory* mock_factory_digest_replace = + new MockHttpAuthHandlerFactory(kDigestReturnCodeReplace); + + scoped_refptr<HttpAuthHandler> handler; + + // No schemes should be supported in the beginning. + EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, + registry_factory.CreateAuthHandlerFromString( + "Basic", HttpAuth::AUTH_SERVER, gurl, &handler)); + + // Test what happens with a single scheme. + registry_factory.RegisterSchemeFactory("Basic", mock_factory_basic); + EXPECT_EQ(kBasicReturnCode, + registry_factory.CreateAuthHandlerFromString( + "Basic", HttpAuth::AUTH_SERVER, gurl, &handler)); + EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, + registry_factory.CreateAuthHandlerFromString( + "Digest", HttpAuth::AUTH_SERVER, gurl, &handler)); + + // Test multiple schemes + registry_factory.RegisterSchemeFactory("Digest", mock_factory_digest); + EXPECT_EQ(kBasicReturnCode, + registry_factory.CreateAuthHandlerFromString( + "Basic", HttpAuth::AUTH_SERVER, gurl, &handler)); + EXPECT_EQ(kDigestReturnCode, + registry_factory.CreateAuthHandlerFromString( + "Digest", HttpAuth::AUTH_SERVER, gurl, &handler)); + + // Test case-insensitivity + EXPECT_EQ(kBasicReturnCode, + registry_factory.CreateAuthHandlerFromString( + "basic", HttpAuth::AUTH_SERVER, gurl, &handler)); + + // Test replacement of existing auth scheme + registry_factory.RegisterSchemeFactory("Digest", mock_factory_digest_replace); + EXPECT_EQ(kBasicReturnCode, + registry_factory.CreateAuthHandlerFromString( + "Basic", HttpAuth::AUTH_SERVER, gurl, &handler)); + EXPECT_EQ(kDigestReturnCodeReplace, + registry_factory.CreateAuthHandlerFromString( + "Digest", HttpAuth::AUTH_SERVER, gurl, &handler)); +} + +TEST(HttpAuthHandlerFactoryTest, DefaultFactory) { + scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory( + HttpAuthHandlerFactory::CreateDefault()); + + GURL server_origin("http://www.example.com"); + GURL proxy_origin("http://cache.example.com:3128"); + { + scoped_refptr<HttpAuthHandler> handler; + int rv = http_auth_handler_factory->CreateAuthHandlerFromString( + "Basic realm=\"FooBar\"", + HttpAuth::AUTH_SERVER, + server_origin, + &handler); + EXPECT_EQ(OK, rv); + EXPECT_FALSE(handler.get() == NULL); + EXPECT_STREQ("basic", handler->scheme().c_str()); + EXPECT_STREQ("FooBar", handler->realm().c_str()); + EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target()); + EXPECT_FALSE(handler->encrypts_identity()); + EXPECT_FALSE(handler->is_connection_based()); + } + { + scoped_refptr<HttpAuthHandler> handler; + int rv = http_auth_handler_factory->CreateAuthHandlerFromString( + "UNSUPPORTED realm=\"FooBar\"", + HttpAuth::AUTH_SERVER, + server_origin, + &handler); + EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, rv); + EXPECT_TRUE(handler.get() == NULL); + } + { + scoped_refptr<HttpAuthHandler> handler; + int rv = http_auth_handler_factory->CreateAuthHandlerFromString( + "Digest realm=\"FooBar\", nonce=\"xyz\"", + HttpAuth::AUTH_PROXY, + proxy_origin, + &handler); + EXPECT_EQ(OK, rv); + EXPECT_FALSE(handler.get() == NULL); + EXPECT_STREQ("digest", handler->scheme().c_str()); + EXPECT_STREQ("FooBar", handler->realm().c_str()); + EXPECT_EQ(HttpAuth::AUTH_PROXY, handler->target()); + EXPECT_TRUE(handler->encrypts_identity()); + EXPECT_FALSE(handler->is_connection_based()); + } + { + scoped_refptr<HttpAuthHandler> handler; + int rv = http_auth_handler_factory->CreateAuthHandlerFromString( + "NTLM", + HttpAuth::AUTH_SERVER, + server_origin, + &handler); + EXPECT_EQ(OK, rv); + EXPECT_FALSE(handler.get() == NULL); + EXPECT_STREQ("ntlm", handler->scheme().c_str()); + EXPECT_STREQ("", handler->realm().c_str()); + EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target()); + EXPECT_TRUE(handler->encrypts_identity()); + EXPECT_TRUE(handler->is_connection_based()); + } +#if defined(OS_WIN) + { + scoped_refptr<HttpAuthHandler> handler; + int rv = http_auth_handler_factory->CreateAuthHandlerFromString( + "Negotiate", + HttpAuth::AUTH_SERVER, + server_origin, + &handler); + EXPECT_EQ(OK, rv); + EXPECT_FALSE(handler.get() == NULL); + EXPECT_STREQ("negotiate", handler->scheme().c_str()); + EXPECT_STREQ("", handler->realm().c_str()); + EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target()); + EXPECT_TRUE(handler->encrypts_identity()); + EXPECT_TRUE(handler->is_connection_based()); + } +#else // !defined(OS_WIN) + { + scoped_refptr<HttpAuthHandler> handler; + int rv = http_auth_handler_factory->CreateAuthHandlerFromString( + "Negotiate", + HttpAuth::AUTH_SERVER, + server_origin, + &handler); + EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, rv); + EXPECT_TRUE(handler.get() == NULL); + } +#endif // !defined(OS_WIN) +} + +} // namespace net diff --git a/net/http/http_auth_handler_negotiate.cc b/net/http/http_auth_handler_negotiate.cc new file mode 100644 index 0000000..1e99c71 --- /dev/null +++ b/net/http/http_auth_handler_negotiate.cc @@ -0,0 +1,15 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/http/http_auth_handler_negotiate.h" + +namespace net { + +HttpAuthHandlerNegotiate::Factory::Factory() { +} + +HttpAuthHandlerNegotiate::Factory::~Factory() { +} + +} // namespace net diff --git a/net/http/http_auth_handler_negotiate.h b/net/http/http_auth_handler_negotiate.h index b057f5c..c8e5585 100644 --- a/net/http/http_auth_handler_negotiate.h +++ b/net/http/http_auth_handler_negotiate.h @@ -10,6 +10,7 @@ #include <string> #include "net/http/http_auth_handler.h" +#include "net/http/http_auth_handler_factory.h" #if defined(OS_WIN) #include "net/http/http_auth_sspi_win.h" @@ -24,6 +25,17 @@ namespace net { class HttpAuthHandlerNegotiate : public HttpAuthHandler { public: + class Factory : public HttpAuthHandlerFactory { + public: + Factory(); + virtual ~Factory(); + + virtual int CreateAuthHandler(HttpAuth::ChallengeTokenizer* challenge, + HttpAuth::Target target, + const GURL& origin, + scoped_refptr<HttpAuthHandler>* handler); + }; + HttpAuthHandlerNegotiate(); virtual bool NeedsIdentity(); @@ -43,8 +55,7 @@ class HttpAuthHandlerNegotiate : public HttpAuthHandler { std::string* auth_token); protected: - virtual bool Init(std::string::const_iterator challenge_begin, - std::string::const_iterator challenge_end); + virtual bool Init(HttpAuth::ChallengeTokenizer* challenge); private: ~HttpAuthHandlerNegotiate(); diff --git a/net/http/http_auth_handler_negotiate_posix.cc b/net/http/http_auth_handler_negotiate_posix.cc index f70b58b..40ab439 100644 --- a/net/http/http_auth_handler_negotiate_posix.cc +++ b/net/http/http_auth_handler_negotiate_posix.cc @@ -37,8 +37,7 @@ bool HttpAuthHandlerNegotiate::AllowDefaultCredentials() { return false; } -bool HttpAuthHandlerNegotiate::Init(std::string::const_iterator challenge_begin, - std::string::const_iterator challenge_end) { +bool HttpAuthHandlerNegotiate::Init(HttpAuth::ChallengeTokenizer* tok) { return false; } @@ -62,4 +61,12 @@ int HttpAuthHandlerNegotiate::GenerateDefaultAuthToken( return ERR_NOT_IMPLEMENTED; } +int HttpAuthHandlerNegotiate::Factory::CreateAuthHandler( + HttpAuth::ChallengeTokenizer* challenge, + HttpAuth::Target target, + const GURL& origin, + scoped_refptr<HttpAuthHandler>* handler) { + return ERR_UNSUPPORTED_AUTH_SCHEME; +} + } // namespace net diff --git a/net/http/http_auth_handler_negotiate_win.cc b/net/http/http_auth_handler_negotiate_win.cc index c005590..917fc1d 100644 --- a/net/http/http_auth_handler_negotiate_win.cc +++ b/net/http/http_auth_handler_negotiate_win.cc @@ -32,13 +32,11 @@ int HttpAuthHandlerNegotiate::GenerateAuthToken( // The Negotiate challenge header looks like: // WWW-Authenticate: NEGOTIATE auth-data -bool HttpAuthHandlerNegotiate::Init( - std::string::const_iterator challenge_begin, - std::string::const_iterator challenge_end) { +bool HttpAuthHandlerNegotiate::Init(HttpAuth::ChallengeTokenizer* challenge) { scheme_ = "negotiate"; score_ = 4; properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED; - return auth_sspi_.ParseChallenge(challenge_begin, challenge_end); + return auth_sspi_.ParseChallenge(challenge); } // Require identity on first pass instead of second. @@ -76,4 +74,18 @@ int HttpAuthHandlerNegotiate::GenerateDefaultAuthToken( auth_token); } +int HttpAuthHandlerNegotiate::Factory::CreateAuthHandler( + HttpAuth::ChallengeTokenizer* challenge, + HttpAuth::Target target, + const GURL& origin, + scoped_refptr<HttpAuthHandler>* handler) { + // TODO(cbentzel): Move towards model of parsing in the factory + // method and only constructing when valid. + scoped_refptr<HttpAuthHandler> tmp_handler(new HttpAuthHandlerNegotiate()); + if (!tmp_handler->InitFromChallenge(challenge, target, origin)) + return ERR_INVALID_RESPONSE; + handler->swap(tmp_handler); + return OK; +} + } // namespace net diff --git a/net/http/http_auth_handler_ntlm.cc b/net/http/http_auth_handler_ntlm.cc index e191ce4..1e0c3f0 100644 --- a/net/http/http_auth_handler_ntlm.cc +++ b/net/http/http_auth_handler_ntlm.cc @@ -56,17 +56,6 @@ int HttpAuthHandlerNTLM::GenerateAuthToken( if (rv != OK) return rv; } else { - // Decode |auth_data_| into the input buffer. - int len = auth_data_.length(); - - // Strip off any padding. - // (See https://bugzilla.mozilla.org/show_bug.cgi?id=230351.) - // - // Our base64 decoder requires that the length be a multiple of 4. - while (len > 0 && len % 4 != 0 && auth_data_[len - 1] == '=') - len--; - auth_data_.erase(len); - if (!base::Base64Decode(auth_data_, &decoded_auth_data)) { LOG(ERROR) << "Unexpected problem Base64 decoding."; return ERR_UNEXPECTED; @@ -97,33 +86,45 @@ int HttpAuthHandlerNTLM::GenerateAuthToken( // The NTLM challenge header looks like: // WWW-Authenticate: NTLM auth-data bool HttpAuthHandlerNTLM::ParseChallenge( - std::string::const_iterator challenge_begin, - std::string::const_iterator challenge_end) { + HttpAuth::ChallengeTokenizer* tok) { scheme_ = "ntlm"; score_ = 3; properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED; #if defined(NTLM_SSPI) - return auth_sspi_.ParseChallenge(challenge_begin, challenge_end); + return auth_sspi_.ParseChallenge(tok); #else auth_data_.clear(); // Verify the challenge's auth-scheme. - HttpAuth::ChallengeTokenizer challenge_tok(challenge_begin, challenge_end); - if (!challenge_tok.valid() || - !LowerCaseEqualsASCII(challenge_tok.scheme(), "ntlm")) + if (!tok->valid() || !LowerCaseEqualsASCII(tok->scheme(), "ntlm")) return false; - // Extract the auth-data. We can't use challenge_tok.GetNext() because - // auth-data is base64-encoded and may contain '=' padding at the end, - // which would be mistaken for a name=value pair. - challenge_begin += 4; // Skip over "NTLM". - HttpUtil::TrimLWS(&challenge_begin, &challenge_end); + tok->set_expect_base64_token(true); + if (tok->GetNext()) + auth_data_.assign(tok->value_begin(), tok->value_end()); + return true; +#endif // defined(NTLM_SSPI) +} + +HttpAuthHandlerNTLM::Factory::Factory() { +} - auth_data_.assign(challenge_begin, challenge_end); +HttpAuthHandlerNTLM::Factory::~Factory() { +} - return true; -#endif +int HttpAuthHandlerNTLM::Factory::CreateAuthHandler( + HttpAuth::ChallengeTokenizer* challenge, + HttpAuth::Target target, + const GURL& origin, + scoped_refptr<HttpAuthHandler>* handler) { + // TODO(cbentzel): Move towards model of parsing in the factory + // method and only constructing when valid. + scoped_refptr<HttpAuthHandler> tmp_handler(new HttpAuthHandlerNTLM()); + if (!tmp_handler->InitFromChallenge(challenge, target, origin)) + return ERR_INVALID_RESPONSE; + handler->swap(tmp_handler); + return OK; } } // namespace net diff --git a/net/http/http_auth_handler_ntlm.h b/net/http/http_auth_handler_ntlm.h index c4b9dab..759d3a2 100644 --- a/net/http/http_auth_handler_ntlm.h +++ b/net/http/http_auth_handler_ntlm.h @@ -27,12 +27,24 @@ #include "base/basictypes.h" #include "base/string16.h" #include "net/http/http_auth_handler.h" +#include "net/http/http_auth_handler_factory.h" namespace net { // Code for handling HTTP NTLM authentication. class HttpAuthHandlerNTLM : public HttpAuthHandler { public: + class Factory : public HttpAuthHandlerFactory { + public: + Factory(); + virtual ~Factory(); + + virtual int CreateAuthHandler(HttpAuth::ChallengeTokenizer* challenge, + HttpAuth::Target target, + const GURL& origin, + scoped_refptr<HttpAuthHandler>* handler); + }; + #if defined(NTLM_PORTABLE) // A function that generates n random bytes in the output buffer. typedef void (*GenerateRandomProc)(uint8* output, size_t n); @@ -81,9 +93,8 @@ class HttpAuthHandlerNTLM : public HttpAuthHandler { std::string* auth_token); protected: - virtual bool Init(std::string::const_iterator challenge_begin, - std::string::const_iterator challenge_end) { - return ParseChallenge(challenge_begin, challenge_end); + virtual bool Init(HttpAuth::ChallengeTokenizer* tok) { + return ParseChallenge(tok); } // This function acquires a credentials handle in the SSPI implementation. @@ -102,8 +113,7 @@ class HttpAuthHandlerNTLM : public HttpAuthHandler { // Parse the challenge, saving the results into this instance. // Returns true on success. - bool ParseChallenge(std::string::const_iterator challenge_begin, - std::string::const_iterator challenge_end); + bool ParseChallenge(HttpAuth::ChallengeTokenizer* tok); // Given an input token received from the server, generate the next output // token to be sent to the server. diff --git a/net/http/http_auth_sspi_win.cc b/net/http/http_auth_sspi_win.cc index c858d36..d8a22c2 100644 --- a/net/http/http_auth_sspi_win.cc +++ b/net/http/http_auth_sspi_win.cc @@ -129,30 +129,19 @@ void HttpAuthSSPI::ResetSecurityContext() { } } -bool HttpAuthSSPI::ParseChallenge(std::string::const_iterator challenge_begin, - std::string::const_iterator challenge_end) { +bool HttpAuthSSPI::ParseChallenge(HttpAuth::ChallengeTokenizer* tok) { // Verify the challenge's auth-scheme. - HttpAuth::ChallengeTokenizer challenge_tok(challenge_begin, challenge_end); - if (!challenge_tok.valid() || - !LowerCaseEqualsASCII(challenge_tok.scheme(), - StringToLowerASCII(scheme_).c_str())) + if (!tok->valid() || + !LowerCaseEqualsASCII(tok->scheme(), StringToLowerASCII(scheme_).c_str())) return false; - // Extract the auth-data. We can't use challenge_tok.GetNext() because - // auth-data is base64-encoded and may contain '=' padding at the end, - // which would be mistaken for a name=value pair. - challenge_begin += scheme_.length(); // Skip over scheme name. - HttpUtil::TrimLWS(&challenge_begin, &challenge_end); - std::string encoded_auth_token(challenge_begin, challenge_end); - int encoded_length = encoded_auth_token.length(); - // Strip off any padding. - // (See https://bugzilla.mozilla.org/show_bug.cgi?id=230351.) - // - // Our base64 decoder requires that the length be a multiple of 4. - while (encoded_length > 0 && encoded_length % 4 != 0 && - encoded_auth_token[encoded_length - 1] == '=') - encoded_length--; - encoded_auth_token.erase(encoded_length); + tok->set_expect_base64_token(true); + if (!tok->GetNext()) { + decoded_server_auth_token_.clear(); + return true; + } + + std::string encoded_auth_token = tok->value(); std::string decoded_auth_token; bool base64_rv = base::Base64Decode(encoded_auth_token, &decoded_auth_token); if (!base64_rv) { diff --git a/net/http/http_auth_sspi_win.h b/net/http/http_auth_sspi_win.h index b94ffbc..526e25b 100644 --- a/net/http/http_auth_sspi_win.h +++ b/net/http/http_auth_sspi_win.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -16,6 +16,8 @@ #include <string> +#include "net/http/http_auth.h" + class GURL; namespace net { @@ -32,8 +34,7 @@ class HttpAuthSSPI { bool NeedsIdentity() const; bool IsFinalRound() const; - bool ParseChallenge(std::string::const_iterator challenge_begin, - std::string::const_iterator challenge_end); + bool ParseChallenge(HttpAuth::ChallengeTokenizer* tok); // Generates an authentication token. // The return value is an error code. If it's not |OK|, the value of diff --git a/net/http/http_auth_unittest.cc b/net/http/http_auth_unittest.cc index a960d70..14308a0 100644 --- a/net/http/http_auth_unittest.cc +++ b/net/http/http_auth_unittest.cc @@ -1,12 +1,14 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "testing/gtest/include/gtest/gtest.h" #include "base/ref_counted.h" +#include "base/scoped_ptr.h" #include "net/http/http_auth.h" #include "net/http/http_auth_handler.h" +#include "net/http/http_auth_handler_factory.h" #include "net/http/http_response_headers.h" #include "net/http/http_util.h" @@ -69,6 +71,9 @@ TEST(HttpAuthTest, ChooseBestChallenge) { }; GURL origin("http://www.example.com"); + scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory( + HttpAuthHandlerFactory::CreateDefault()); + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { // Make a HttpResponseHeaders object. std::string headers_with_status_line("HTTP/1.1 401 Unauthorized\n"); @@ -80,7 +85,8 @@ TEST(HttpAuthTest, ChooseBestChallenge) { headers_with_status_line.length()))); scoped_refptr<HttpAuthHandler> handler; - HttpAuth::ChooseBestChallenge(headers.get(), + HttpAuth::ChooseBestChallenge(http_auth_handler_factory.get(), + headers.get(), HttpAuth::AUTH_SERVER, origin, &handler); @@ -122,6 +128,9 @@ TEST(HttpAuthTest, ChooseBestChallengeConnectionBased) { GURL origin("http://www.example.com"); scoped_refptr<HttpAuthHandler> handler; + scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory( + HttpAuthHandlerFactory::CreateDefault()); + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { // Make a HttpResponseHeaders object. std::string headers_with_status_line("HTTP/1.1 401 Unauthorized\n"); @@ -133,7 +142,8 @@ TEST(HttpAuthTest, ChooseBestChallengeConnectionBased) { headers_with_status_line.length()))); scoped_refptr<HttpAuthHandler> old_handler = handler; - HttpAuth::ChooseBestChallenge(headers.get(), + HttpAuth::ChooseBestChallenge(http_auth_handler_factory.get(), + headers.get(), HttpAuth::AUTH_SERVER, origin, &handler); @@ -230,6 +240,20 @@ TEST(HttpAuthTest, ChallengeTokenizerNoProperty) { EXPECT_FALSE(challenge.GetNext()); } +// Use a challenge with Base64 encoded token. +TEST(HttpAuthTest, ChallengeTokenizerBase64) { + std::string challenge_str = "NTLM SGVsbG8sIFdvcmxkCg==="; + HttpAuth::ChallengeTokenizer challenge(challenge_str.begin(), + challenge_str.end()); + EXPECT_TRUE(challenge.valid()); + EXPECT_EQ(std::string("NTLM"), challenge.scheme()); + challenge.set_expect_base64_token(true); + EXPECT_TRUE(challenge.GetNext()); + // Notice the two equal statements below due to padding removal. + EXPECT_EQ(std::string("SGVsbG8sIFdvcmxkCg=="), challenge.value()); + EXPECT_FALSE(challenge.GetNext()); +} + TEST(HttpAuthTest, GetChallengeHeaderName) { std::string name; @@ -250,56 +274,4 @@ TEST(HttpAuthTest, GetAuthorizationHeaderName) { EXPECT_STREQ("Proxy-Authorization", name.c_str()); } -TEST(HttpAuthTest, CreateAuthHandler) { - GURL server_origin("http://www.example.com"); - GURL proxy_origin("http://cache.example.com:3128"); - { - scoped_refptr<HttpAuthHandler> handler; - HttpAuth::CreateAuthHandler("Basic realm=\"FooBar\"", - HttpAuth::AUTH_SERVER, - server_origin, - &handler); - EXPECT_FALSE(handler.get() == NULL); - EXPECT_STREQ("basic", handler->scheme().c_str()); - EXPECT_STREQ("FooBar", handler->realm().c_str()); - EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target()); - EXPECT_FALSE(handler->encrypts_identity()); - EXPECT_FALSE(handler->is_connection_based()); - } - { - scoped_refptr<HttpAuthHandler> handler; - HttpAuth::CreateAuthHandler("UNSUPPORTED realm=\"FooBar\"", - HttpAuth::AUTH_SERVER, - server_origin, - &handler); - EXPECT_TRUE(handler.get() == NULL); - } - { - scoped_refptr<HttpAuthHandler> handler; - HttpAuth::CreateAuthHandler("Digest realm=\"FooBar\", nonce=\"xyz\"", - HttpAuth::AUTH_PROXY, - proxy_origin, - &handler); - EXPECT_FALSE(handler.get() == NULL); - EXPECT_STREQ("digest", handler->scheme().c_str()); - EXPECT_STREQ("FooBar", handler->realm().c_str()); - EXPECT_EQ(HttpAuth::AUTH_PROXY, handler->target()); - EXPECT_TRUE(handler->encrypts_identity()); - EXPECT_FALSE(handler->is_connection_based()); - } - { - scoped_refptr<HttpAuthHandler> handler; - HttpAuth::CreateAuthHandler("NTLM", - HttpAuth::AUTH_SERVER, - server_origin, - &handler); - EXPECT_FALSE(handler.get() == NULL); - EXPECT_STREQ("ntlm", handler->scheme().c_str()); - EXPECT_STREQ("", handler->realm().c_str()); - EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target()); - EXPECT_TRUE(handler->encrypts_identity()); - EXPECT_TRUE(handler->is_connection_based()); - } -} - } // namespace net diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index b76fd07..52b9ebfb 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -127,6 +127,7 @@ HttpCache::HttpCache(NetworkChangeNotifier* network_change_notifier, HostResolver* host_resolver, ProxyService* proxy_service, SSLConfigService* ssl_config_service, + HttpAuthHandlerFactory* http_auth_handler_factory, const FilePath& cache_dir, int cache_size) : disk_cache_dir_(cache_dir), @@ -134,7 +135,7 @@ HttpCache::HttpCache(NetworkChangeNotifier* network_change_notifier, type_(DISK_CACHE), network_layer_(HttpNetworkLayer::CreateFactory( network_change_notifier, host_resolver, proxy_service, - ssl_config_service)), + ssl_config_service, http_auth_handler_factory)), ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), enable_range_support_(true), cache_size_(cache_size) { @@ -156,12 +157,13 @@ HttpCache::HttpCache(NetworkChangeNotifier* network_change_notifier, HostResolver* host_resolver, ProxyService* proxy_service, SSLConfigService* ssl_config_service, + HttpAuthHandlerFactory* http_auth_handler_factory, int cache_size) : mode_(NORMAL), type_(MEMORY_CACHE), network_layer_(HttpNetworkLayer::CreateFactory( network_change_notifier, host_resolver, proxy_service, - ssl_config_service)), + ssl_config_service, http_auth_handler_factory)), ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), enable_range_support_(true), cache_size_(cache_size) { diff --git a/net/http/http_cache.h b/net/http/http_cache.h index d85c12c..fd0c445 100644 --- a/net/http/http_cache.h +++ b/net/http/http_cache.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -35,6 +35,7 @@ class Entry; namespace net { class HostResolver; +class HttpAuthHandlerFactory; class HttpNetworkSession; class HttpRequestInfo; class HttpResponseInfo; @@ -68,6 +69,7 @@ class HttpCache : public HttpTransactionFactory, HostResolver* host_resolver, ProxyService* proxy_service, SSLConfigService* ssl_config_service, + HttpAuthHandlerFactory* http_auth_handler_factory, const FilePath& cache_dir, int cache_size); @@ -87,6 +89,7 @@ class HttpCache : public HttpTransactionFactory, HostResolver* host_resolver, ProxyService* proxy_service, SSLConfigService* ssl_config_service, + HttpAuthHandlerFactory* http_auth_handler_factory, int cache_size); // Initialize the cache from its component parts, which is useful for diff --git a/net/http/http_network_layer.cc b/net/http/http_network_layer.cc index 089807c..068b276 100644 --- a/net/http/http_network_layer.cc +++ b/net/http/http_network_layer.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -23,12 +23,14 @@ HttpTransactionFactory* HttpNetworkLayer::CreateFactory( NetworkChangeNotifier* network_change_notifier, HostResolver* host_resolver, ProxyService* proxy_service, - SSLConfigService* ssl_config_service) { + SSLConfigService* ssl_config_service, + HttpAuthHandlerFactory* http_auth_handler_factory) { DCHECK(proxy_service); return new HttpNetworkLayer(ClientSocketFactory::GetDefaultFactory(), network_change_notifier, - host_resolver, proxy_service, ssl_config_service); + host_resolver, proxy_service, ssl_config_service, + http_auth_handler_factory); } // static @@ -47,7 +49,8 @@ HttpNetworkLayer::HttpNetworkLayer( NetworkChangeNotifier* network_change_notifier, HostResolver* host_resolver, ProxyService* proxy_service, - SSLConfigService* ssl_config_service) + SSLConfigService* ssl_config_service, + HttpAuthHandlerFactory* http_auth_handler_factory) : socket_factory_(socket_factory), network_change_notifier_(network_change_notifier), host_resolver_(host_resolver), @@ -55,6 +58,7 @@ HttpNetworkLayer::HttpNetworkLayer( ssl_config_service_(ssl_config_service), session_(NULL), spdy_session_pool_(NULL), + http_auth_handler_factory_(http_auth_handler_factory), suspended_(false) { DCHECK(proxy_service_); DCHECK(ssl_config_service_.get()); @@ -66,6 +70,7 @@ HttpNetworkLayer::HttpNetworkLayer(HttpNetworkSession* session) ssl_config_service_(NULL), session_(session), spdy_session_pool_(session->spdy_session_pool()), + http_auth_handler_factory_(NULL), suspended_(false) { DCHECK(session_.get()); } @@ -101,12 +106,14 @@ HttpNetworkSession* HttpNetworkLayer::GetSession() { SpdySessionPool* spdy_pool = new SpdySessionPool; session_ = new HttpNetworkSession( network_change_notifier_, host_resolver_, proxy_service_, - socket_factory_, ssl_config_service_, spdy_pool); + socket_factory_, ssl_config_service_, spdy_pool, + http_auth_handler_factory_); // These were just temps for lazy-initializing HttpNetworkSession. network_change_notifier_ = NULL; host_resolver_ = NULL; proxy_service_ = NULL; socket_factory_ = NULL; + http_auth_handler_factory_ = NULL; } return session_; } diff --git a/net/http/http_network_layer.h b/net/http/http_network_layer.h index 3050298..2d4130d 100644 --- a/net/http/http_network_layer.h +++ b/net/http/http_network_layer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -15,6 +15,7 @@ namespace net { class ClientSocketFactory; class HostResolver; +class HttpAuthHandlerFactory; class HttpNetworkSession; class NetworkChangeNotifier; class ProxyInfo; @@ -29,7 +30,8 @@ class HttpNetworkLayer : public HttpTransactionFactory { HttpNetworkLayer(ClientSocketFactory* socket_factory, NetworkChangeNotifier* network_change_notifier, HostResolver* host_resolver, ProxyService* proxy_service, - SSLConfigService* ssl_config_service); + SSLConfigService* ssl_config_service, + HttpAuthHandlerFactory* http_auth_handler_factory); // Construct a HttpNetworkLayer with an existing HttpNetworkSession which // contains a valid ProxyService. explicit HttpNetworkLayer(HttpNetworkSession* session); @@ -41,7 +43,8 @@ class HttpNetworkLayer : public HttpTransactionFactory { NetworkChangeNotifier* network_change_notifier, HostResolver* host_resolver, ProxyService* proxy_service, - SSLConfigService* ssl_config_service); + SSLConfigService* ssl_config_service, + HttpAuthHandlerFactory* http_auth_handler_factory); // Create a transaction factory that instantiate a network layer over an // existing network session. Network session contains some valuable // information (e.g. authentication data) that we want to share across @@ -81,6 +84,8 @@ class HttpNetworkLayer : public HttpTransactionFactory { scoped_refptr<HttpNetworkSession> session_; scoped_refptr<SpdySessionPool> spdy_session_pool_; + HttpAuthHandlerFactory* http_auth_handler_factory_; + bool suspended_; static bool force_spdy_; }; diff --git a/net/http/http_network_layer_unittest.cc b/net/http/http_network_layer_unittest.cc index 8425304..b1b0c8a 100644 --- a/net/http/http_network_layer_unittest.cc +++ b/net/http/http_network_layer_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -17,7 +17,7 @@ class HttpNetworkLayerTest : public PlatformTest { TEST_F(HttpNetworkLayerTest, CreateAndDestroy) { net::HttpNetworkLayer factory( NULL, NULL, new net::MockHostResolver, net::ProxyService::CreateNull(), - new net::SSLConfigServiceDefaults); + new net::SSLConfigServiceDefaults, NULL); scoped_ptr<net::HttpTransaction> trans; int rv = factory.CreateTransaction(&trans); @@ -28,7 +28,7 @@ TEST_F(HttpNetworkLayerTest, CreateAndDestroy) { TEST_F(HttpNetworkLayerTest, Suspend) { net::HttpNetworkLayer factory( NULL, NULL, new net::MockHostResolver, net::ProxyService::CreateNull(), - new net::SSLConfigServiceDefaults); + new net::SSLConfigServiceDefaults, NULL); scoped_ptr<net::HttpTransaction> trans; int rv = factory.CreateTransaction(&trans); @@ -69,7 +69,8 @@ TEST_F(HttpNetworkLayerTest, GET) { net::HttpNetworkLayer factory(&mock_socket_factory, NULL, new net::MockHostResolver, net::ProxyService::CreateNull(), - new net::SSLConfigServiceDefaults); + new net::SSLConfigServiceDefaults, + NULL); TestCompletionCallback callback; diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc index f63105c..79af40f 100644 --- a/net/http/http_network_session.cc +++ b/net/http/http_network_session.cc @@ -1,10 +1,11 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/http/http_network_session.h" #include "base/logging.h" +#include "net/http/http_auth_handler_factory.h" #include "net/spdy/spdy_session_pool.h" namespace net { @@ -25,7 +26,8 @@ HttpNetworkSession::HttpNetworkSession( ProxyService* proxy_service, ClientSocketFactory* client_socket_factory, SSLConfigService* ssl_config_service, - SpdySessionPool* spdy_session_pool) + SpdySessionPool* spdy_session_pool, + HttpAuthHandlerFactory* http_auth_handler_factory) : network_change_notifier_(network_change_notifier), tcp_socket_pool_(new TCPClientSocketPool( max_sockets_, max_sockets_per_group_, @@ -34,7 +36,8 @@ HttpNetworkSession::HttpNetworkSession( host_resolver_(host_resolver), proxy_service_(proxy_service), ssl_config_service_(ssl_config_service), - spdy_session_pool_(spdy_session_pool) { + spdy_session_pool_(spdy_session_pool), + http_auth_handler_factory_(http_auth_handler_factory) { DCHECK(proxy_service); DCHECK(ssl_config_service); } diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h index 5049b41..3681970 100644 --- a/net/http/http_network_session.h +++ b/net/http/http_network_session.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -16,6 +16,7 @@ namespace net { class ClientSocketFactory; +class HttpAuthHandlerFactory; class SpdySessionPool; class NetworkChangeNotifier; @@ -28,7 +29,8 @@ class HttpNetworkSession : public base::RefCounted<HttpNetworkSession> { ProxyService* proxy_service, ClientSocketFactory* client_socket_factory, SSLConfigService* ssl_config_service, - SpdySessionPool* spdy_session_pool); + SpdySessionPool* spdy_session_pool, + HttpAuthHandlerFactory* http_auth_handler_factory); HttpAuthCache* auth_cache() { return &auth_cache_; } SSLClientAuthCache* ssl_client_auth_cache() { @@ -45,6 +47,9 @@ class HttpNetworkSession : public base::RefCounted<HttpNetworkSession> { const scoped_refptr<SpdySessionPool>& spdy_session_pool() { return spdy_session_pool_; } + HttpAuthHandlerFactory* http_auth_handler_factory() { + return http_auth_handler_factory_; + } // Replace the current socket pool with a new one. This effectively // abandons the current pool. This is only used for debugging. @@ -84,6 +89,7 @@ class HttpNetworkSession : public base::RefCounted<HttpNetworkSession> { scoped_refptr<ProxyService> proxy_service_; scoped_refptr<SSLConfigService> ssl_config_service_; scoped_refptr<SpdySessionPool> spdy_session_pool_; + HttpAuthHandlerFactory* http_auth_handler_factory_; }; } // namespace net diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 7a664a0..4be611d 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -1825,8 +1825,9 @@ int HttpNetworkTransaction::HandleAuthChallenge() { if (target != HttpAuth::AUTH_SERVER || !(request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA)) { // Find the best authentication challenge that we support. - HttpAuth::ChooseBestChallenge(headers, target, auth_origin, - &auth_handler_[target]); + HttpAuth::ChooseBestChallenge(session_->http_auth_handler_factory(), + headers, target, + auth_origin, &auth_handler_[target]); } if (!auth_handler_[target]) { diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index 548ee16..3d204bf 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -42,6 +42,7 @@ class SessionDependencies { : host_resolver(new MockHostResolver), proxy_service(ProxyService::CreateNull()), ssl_config_service(new SSLConfigServiceDefaults), + http_auth_handler_factory(HttpAuthHandlerFactory::CreateDefault()), spdy_session_pool(new SpdySessionPool) {} // Custom proxy service dependency. @@ -49,12 +50,14 @@ class SessionDependencies { : host_resolver(new MockHostResolver), proxy_service(proxy_service), ssl_config_service(new SSLConfigServiceDefaults), + http_auth_handler_factory(HttpAuthHandlerFactory::CreateDefault()), spdy_session_pool(new SpdySessionPool) {} scoped_refptr<MockHostResolverBase> host_resolver; scoped_refptr<ProxyService> proxy_service; scoped_refptr<SSLConfigService> ssl_config_service; MockClientSocketFactory socket_factory; + scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory; scoped_refptr<SpdySessionPool> spdy_session_pool; }; @@ -71,7 +74,8 @@ HttpNetworkSession* CreateSession(SessionDependencies* session_deps) { session_deps->proxy_service, &session_deps->socket_factory, session_deps->ssl_config_service, - session_deps->spdy_session_pool); + session_deps->spdy_session_pool, + session_deps->http_auth_handler_factory.get()); } class HttpNetworkTransactionTest : public PlatformTest { diff --git a/net/net.gyp b/net/net.gyp index 00f0615..b6f6062 100755 --- a/net/net.gyp +++ b/net/net.gyp @@ -312,13 +312,16 @@ 'http/http_auth.h', 'http/http_auth_cache.cc', 'http/http_auth_cache.h', - 'http/http_auth_handler.h', 'http/http_auth_handler.cc', + 'http/http_auth_handler.h', 'http/http_auth_handler_basic.cc', 'http/http_auth_handler_basic.h', 'http/http_auth_handler_digest.cc', 'http/http_auth_handler_digest.h', + 'http/http_auth_handler_factory.cc', + 'http/http_auth_handler_factory.h', 'http/http_auth_handler_negotiate.h', + 'http/http_auth_handler_negotiate.cc', 'http/http_auth_handler_negotiate_posix.cc', 'http/http_auth_handler_negotiate_win.cc', 'http/http_auth_handler_ntlm.cc', @@ -638,6 +641,7 @@ 'http/http_auth_cache_unittest.cc', 'http/http_auth_handler_basic_unittest.cc', 'http/http_auth_handler_digest_unittest.cc', + 'http/http_auth_handler_factory_unittest.cc', 'http/http_auth_sspi_win_unittest.cc', 'http/http_auth_unittest.cc', 'http/http_byte_range_unittest.cc', diff --git a/net/proxy/proxy_script_fetcher_unittest.cc b/net/proxy/proxy_script_fetcher_unittest.cc index 741e7d4..7c38470 100644 --- a/net/proxy/proxy_script_fetcher_unittest.cc +++ b/net/proxy/proxy_script_fetcher_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -37,8 +37,10 @@ class RequestContext : public URLRequestContext { ssl_config_service_ = new net::SSLConfigServiceDefaults; http_transaction_factory_ = - new net::HttpCache(net::HttpNetworkLayer::CreateFactory( - NULL, host_resolver_, proxy_service_, ssl_config_service_), + new net::HttpCache( + net::HttpNetworkLayer::CreateFactory( + NULL, host_resolver_, proxy_service_, ssl_config_service_, + NULL), disk_cache::CreateInMemoryCacheBackend(0)); } diff --git a/net/socket_stream/socket_stream.cc b/net/socket_stream/socket_stream.cc index aae234e..4d80df2 100644 --- a/net/socket_stream/socket_stream.cc +++ b/net/socket_stream/socket_stream.cc @@ -43,6 +43,7 @@ SocketStream::SocketStream(const GURL& url, Delegate* delegate) delegate_(delegate), max_pending_send_allowed_(kMaxPendingSendAllowed), next_state_(STATE_NONE), + http_auth_handler_factory_(NULL), factory_(ClientSocketFactory::GetDefaultFactory()), proxy_mode_(kDirectConnection), proxy_url_(url), @@ -107,9 +108,10 @@ void SocketStream::set_context(URLRequestContext* context) { } } - if (context_) + if (context_) { host_resolver_ = context_->host_resolver(); - + http_auth_handler_factory_ = context_->http_auth_handler_factory(); + } } void SocketStream::Connect() { @@ -869,8 +871,9 @@ int SocketStream::HandleAuthChallenge(const HttpResponseHeaders* headers) { } auth_identity_.invalid = true; - HttpAuth::ChooseBestChallenge(headers, HttpAuth::AUTH_PROXY, auth_origin, - &auth_handler_); + HttpAuth::ChooseBestChallenge(http_auth_handler_factory_, headers, + HttpAuth::AUTH_PROXY, + auth_origin, &auth_handler_); if (!auth_handler_) { LOG(ERROR) << "Can't perform auth to the proxy " << auth_origin; return ERR_TUNNEL_CONNECTION_FAILED; diff --git a/net/socket_stream/socket_stream.h b/net/socket_stream/socket_stream.h index cf6a6b0..5b1ae3e 100644 --- a/net/socket_stream/socket_stream.h +++ b/net/socket_stream/socket_stream.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -30,6 +30,7 @@ namespace net { class AuthChallengeInfo; class ClientSocketFactory; class HostResolver; +class HttpAuthHandlerFactory; class LoadLog; class SSLConfigService; class SingleRequestHostResolver; @@ -266,6 +267,7 @@ class SocketStream : public base::RefCountedThreadSafe<SocketStream> { State next_state_; scoped_refptr<HostResolver> host_resolver_; + HttpAuthHandlerFactory* http_auth_handler_factory_; ClientSocketFactory* factory_; ProxyMode proxy_mode_; diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc index c4caf88..888685a 100644 --- a/net/spdy/spdy_network_transaction_unittest.cc +++ b/net/spdy/spdy_network_transaction_unittest.cc @@ -12,6 +12,7 @@ #include "net/base/ssl_config_service_defaults.h" #include "net/base/test_completion_callback.h" #include "net/base/upload_data.h" +#include "net/http/http_auth_handler_factory.h" #include "net/http/http_network_session.h" #include "net/http/http_transaction_unittest.h" #include "net/proxy/proxy_config_service_fixed.h" @@ -39,6 +40,7 @@ class SessionDependencies { : host_resolver(new MockHostResolver), proxy_service(CreateNullProxyService()), ssl_config_service(new SSLConfigServiceDefaults), + http_auth_handler_factory(HttpAuthHandlerFactory::CreateDefault()), spdy_session_pool(new SpdySessionPool) { // Note: The CancelledTransaction test does cleanup by running all tasks // in the message loop (RunAllPending). Unfortunately, that doesn't clean @@ -54,12 +56,14 @@ class SessionDependencies { : host_resolver(new MockHostResolver), proxy_service(proxy_service), ssl_config_service(new SSLConfigServiceDefaults), + http_auth_handler_factory(HttpAuthHandlerFactory::CreateDefault()), spdy_session_pool(new SpdySessionPool) {} scoped_refptr<MockHostResolverBase> host_resolver; scoped_refptr<ProxyService> proxy_service; scoped_refptr<SSLConfigService> ssl_config_service; MockClientSocketFactory socket_factory; + scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory; scoped_refptr<SpdySessionPool> spdy_session_pool; }; @@ -76,7 +80,8 @@ HttpNetworkSession* CreateSession(SessionDependencies* session_deps) { session_deps->proxy_service, &session_deps->socket_factory, session_deps->ssl_config_service, - session_deps->spdy_session_pool); + session_deps->spdy_session_pool, + session_deps->http_auth_handler_factory.get()); } // Chop a frame into an array of MockWrites. diff --git a/net/spdy/spdy_stream_unittest.cc b/net/spdy/spdy_stream_unittest.cc index 1af987c..eb8ca5fc 100644 --- a/net/spdy/spdy_stream_unittest.cc +++ b/net/spdy/spdy_stream_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,6 +9,7 @@ #include "net/base/ssl_config_service.h" #include "net/base/ssl_config_service_defaults.h" #include "net/base/test_completion_callback.h" +#include "net/http/http_auth_handler_factory.h" #include "net/http/http_network_session.h" #include "net/http/http_request_info.h" #include "net/http/http_response_info.h" @@ -51,6 +52,7 @@ class SessionDependencies { : host_resolver(new MockHostResolver), proxy_service(CreateNullProxyService()), ssl_config_service(new SSLConfigServiceDefaults), + http_auth_handler_factory(HttpAuthHandlerFactory::CreateDefault()), spdy_session_pool(new SpdySessionPool) {} // Custom proxy service dependency. @@ -58,12 +60,14 @@ class SessionDependencies { : host_resolver(new MockHostResolver), proxy_service(proxy_service), ssl_config_service(new SSLConfigServiceDefaults), + http_auth_handler_factory(HttpAuthHandlerFactory::CreateDefault()), spdy_session_pool(new SpdySessionPool) {} scoped_refptr<MockHostResolverBase> host_resolver; scoped_refptr<ProxyService> proxy_service; scoped_refptr<SSLConfigService> ssl_config_service; MockClientSocketFactory socket_factory; + scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory; scoped_refptr<SpdySessionPool> spdy_session_pool; }; @@ -73,7 +77,8 @@ HttpNetworkSession* CreateSession(SessionDependencies* session_deps) { session_deps->proxy_service, &session_deps->socket_factory, session_deps->ssl_config_service, - session_deps->spdy_session_pool); + session_deps->spdy_session_pool, + session_deps->http_auth_handler_factory.get()); } class SpdyStreamTest : public testing::Test { diff --git a/net/tools/fetch/fetch_client.cc b/net/tools/fetch/fetch_client.cc index 120b5ca..197a0454 100644 --- a/net/tools/fetch/fetch_client.cc +++ b/net/tools/fetch/fetch_client.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -15,6 +15,7 @@ #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "net/base/ssl_config_service.h" +#include "net/http/http_auth_handler_factory.h" #include "net/http/http_cache.h" #include "net/http/http_network_layer.h" #include "net/http/http_request_info.h" @@ -139,13 +140,16 @@ int main(int argc, char**argv) { scoped_refptr<net::SSLConfigService> ssl_config_service( net::SSLConfigService::CreateSystemSSLConfigService()); net::HttpTransactionFactory* factory = NULL; + scoped_ptr<net::HttpAuthHandlerFactory> http_auth_handler_factory( + net::HttpAuthHandlerFactory::CreateDefault()); if (use_cache) { factory = new net::HttpCache(NULL, host_resolver, proxy_service, - ssl_config_service, 0); + ssl_config_service, + http_auth_handler_factory.get(), 0); } else { factory = new net::HttpNetworkLayer( net::ClientSocketFactory::GetDefaultFactory(), NULL, host_resolver, - proxy_service, ssl_config_service); + proxy_service, ssl_config_service, http_auth_handler_factory.get()); } { diff --git a/net/url_request/url_request_context.h b/net/url_request/url_request_context.h index d72f84d..fb2608f 100644 --- a/net/url_request/url_request_context.h +++ b/net/url_request/url_request_context.h @@ -23,6 +23,7 @@ namespace net { class CookiePolicy; class FtpTransactionFactory; +class HttpAuthHandlerFactory; class HttpTransactionFactory; class SocketStream; } @@ -77,6 +78,12 @@ class URLRequestContext : // Gets the FTP authentication cache for this context. net::FtpAuthCache* ftp_auth_cache() { return &ftp_auth_cache_; } + // Gets the HTTP Authentication Handler Factory for this context. + // The factory is only valid for the lifetime of this URLRequestContext + net::HttpAuthHandlerFactory* http_auth_handler_factory() { + return http_auth_handler_factory_; + } + // Gets the value of 'Accept-Charset' header field. const std::string& accept_charset() const { return accept_charset_; } @@ -133,6 +140,7 @@ class URLRequestContext : scoped_refptr<net::SSLConfigService> ssl_config_service_; net::HttpTransactionFactory* http_transaction_factory_; net::FtpTransactionFactory* ftp_transaction_factory_; + net::HttpAuthHandlerFactory* http_auth_handler_factory_; scoped_refptr<net::CookieStore> cookie_store_; net::CookiePolicy* cookie_policy_; scoped_refptr<net::TransportSecurityState> transport_security_state_; diff --git a/net/url_request/url_request_unittest.h b/net/url_request/url_request_unittest.h index 6ea2c15..e0868ff 100644 --- a/net/url_request/url_request_unittest.h +++ b/net/url_request/url_request_unittest.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -30,6 +30,7 @@ #include "net/base/ssl_config_service_defaults.h" #include "net/disk_cache/disk_cache.h" #include "net/ftp/ftp_network_layer.h" +#include "net/http/http_auth_handler_factory.h" #include "net/http/http_cache.h" #include "net/http/http_network_layer.h" #include "net/socket/ssl_test_util.h" @@ -151,17 +152,20 @@ class TestURLRequestContext : public URLRequestContext { virtual ~TestURLRequestContext() { delete ftp_transaction_factory_; delete http_transaction_factory_; + delete http_auth_handler_factory_; } private: void Init() { ftp_transaction_factory_ = new net::FtpNetworkLayer(host_resolver_); ssl_config_service_ = new net::SSLConfigServiceDefaults; + http_auth_handler_factory_ = net::HttpAuthHandlerFactory::CreateDefault(); http_transaction_factory_ = new net::HttpCache( net::HttpNetworkLayer::CreateFactory(NULL, host_resolver_, proxy_service_, - ssl_config_service_), + ssl_config_service_, + http_auth_handler_factory_), disk_cache::CreateInMemoryCacheBackend(0)); // In-memory cookie store. cookie_store_ = new net::CookieMonster(NULL); |