diff options
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); |