diff options
21 files changed, 457 insertions, 185 deletions
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h index 7c0c3de..6ea5457 100644 --- a/net/base/net_error_list.h +++ b/net/base/net_error_list.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. @@ -305,6 +305,13 @@ NET_ERROR(NO_SUPPORTED_PROXIES, -336) // There is a FLIP protocol framing error. NET_ERROR(FLIP_PROTOCOL_ERROR, -337) +// Credentials could not be estalished during HTTP Authentication. +NET_ERROR(INVALID_AUTH_CREDENTIALS, -338) + +// An HTTP Authentication scheme was tried which is not supported on this +// machine. +NET_ERROR(UNSUPPORTED_AUTH_SCHEME, -339) + // The cache does not have the requested entry. NET_ERROR(CACHE_MISS, -400) diff --git a/net/http/http_auth_cache_unittest.cc b/net/http/http_auth_cache_unittest.cc index 52fa5cd..b00e8d0 100644 --- a/net/http/http_auth_cache_unittest.cc +++ b/net/http/http_auth_cache_unittest.cc @@ -1,8 +1,9 @@ -// 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. #include "base/string_util.h" +#include "net/base/net_errors.h" #include "net/http/http_auth_cache.h" #include "testing/gtest/include/gtest/gtest.h" @@ -23,11 +24,20 @@ class MockAuthHandler : public HttpAuthHandler { properties_ = 0; } - virtual std::string GenerateCredentials(const std::wstring&, - const std::wstring&, - const HttpRequestInfo*, - const ProxyInfo*) { - return "mock-credentials"; // Unused. + virtual int GenerateAuthToken(const std::wstring&, + const std::wstring&, + const HttpRequestInfo*, + const ProxyInfo*, + std::string* auth_token) { + *auth_token = "mock-credentials"; + return OK; + } + + virtual int GenerateDefaultAuthToken(const HttpRequestInfo*, + const ProxyInfo*, + std::string* auth_token) { + *auth_token = "mock-credentials"; + return OK; } protected: @@ -52,12 +62,12 @@ TEST(HttpAuthCacheTest, Basic) { scoped_refptr<HttpAuthHandler> realm1_handler = new MockAuthHandler("basic", "Realm1", HttpAuth::AUTH_SERVER); cache.Add(origin, realm1_handler, L"realm1-user", L"realm1-password", - "/foo/bar/index.html"); + "/foo/bar/index.html"); scoped_refptr<HttpAuthHandler> realm2_handler = new MockAuthHandler("basic", "Realm2", HttpAuth::AUTH_SERVER); cache.Add(origin, realm2_handler, L"realm2-user", L"realm2-password", - "/foo2/index.html"); + "/foo2/index.html"); scoped_refptr<HttpAuthHandler> realm3_handler = new MockAuthHandler("basic", "Realm3", HttpAuth::AUTH_PROXY); @@ -227,7 +237,8 @@ class HttpAuthCacheEvictionTest : public testing::Test { } void AddPathToRealm(int realm_i, int path_i) { - scoped_refptr<HttpAuthHandler> handler = new MockAuthHandler("basic", + scoped_refptr<HttpAuthHandler> handler = new MockAuthHandler( + "basic", GenerateRealm(realm_i), HttpAuth::AUTH_SERVER); std::string path = GeneratePath(realm_i, path_i); cache_.Add(origin_, handler, L"username", L"password", path); diff --git a/net/http/http_auth_handler.cc b/net/http/http_auth_handler.cc index 9abdd9a..9d70ca0 100644 --- a/net/http/http_auth_handler.cc +++ b/net/http/http_auth_handler.cc @@ -1,10 +1,12 @@ -// 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 "base/logging.h" #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, diff --git a/net/http/http_auth_handler.h b/net/http/http_auth_handler.h index 02a410e..4b8f5261 100644 --- a/net/http/http_auth_handler.h +++ b/net/http/http_auth_handler.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. @@ -72,11 +72,32 @@ class HttpAuthHandler : public base::RefCounted<HttpAuthHandler> { // single-round schemes. virtual bool IsFinalRound() { return true; } - // Generate the Authorization header value. - virtual std::string GenerateCredentials(const std::wstring& username, - const std::wstring& password, - const HttpRequestInfo* request, - const ProxyInfo* proxy) = 0; + // Returns whether the default credentials may be used for the |origin| passed + // into |InitFromChallenge|. If true, the user does not need to be prompted + // for username and password to establish credentials. + virtual bool AllowDefaultCredentials() { return false; } + + // TODO(cbentzel): Separate providing credentials from generating the + // authentication token in the API. + + // Generates an authentication token. + // The return value is an error code. If the code is not |OK|, the value of + // |*auth_token| is unspecified. + // |auth_token| is a return value and must be non-NULL. + virtual int GenerateAuthToken(const std::wstring& username, + const std::wstring& password, + const HttpRequestInfo* request, + const ProxyInfo* proxy, + std::string* auth_token) = 0; + + // Generates an authentication token using default credentials. + // The return value is an error code. If the code is not |OK|, the value of + // |*auth_token| is unspecified. + // |auth_token| is a return value and must be non-NULL. + // This should only be called after |AllowDefaultCredentials| returns true. + virtual int GenerateDefaultAuthToken(const HttpRequestInfo* request, + const ProxyInfo* proxy, + std::string* auth_token) = 0; protected: enum Property { diff --git a/net/http/http_auth_handler_basic.cc b/net/http/http_auth_handler_basic.cc index 71c310c..2c70577 100644 --- a/net/http/http_auth_handler_basic.cc +++ b/net/http/http_auth_handler_basic.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/base64.h" #include "base/string_util.h" +#include "net/base/net_errors.h" #include "net/http/http_auth.h" namespace net { @@ -41,17 +42,31 @@ bool HttpAuthHandlerBasic::Init(std::string::const_iterator challenge_begin, return challenge_tok.valid(); } -std::string HttpAuthHandlerBasic::GenerateCredentials( +int HttpAuthHandlerBasic::GenerateAuthToken( const std::wstring& username, const std::wstring& password, const HttpRequestInfo*, - const ProxyInfo*) { + const ProxyInfo*, + std::string* auth_token) { // TODO(eroman): is this the right encoding of username/password? std::string base64_username_password; if (!base::Base64Encode(WideToUTF8(username) + ":" + WideToUTF8(password), - &base64_username_password)) - return std::string(); // FAIL - return std::string("Basic ") + base64_username_password; + &base64_username_password)) { + LOG(ERROR) << "Unexpected problem Base64 encoding."; + return ERR_UNEXPECTED; + } + *auth_token = "Basic " + base64_username_password; + return OK; +} + +int HttpAuthHandlerBasic::GenerateDefaultAuthToken( + const HttpRequestInfo* request, + const ProxyInfo* proxy, + std::string* auth_token) { + NOTREACHED(); + LOG(ERROR) << ErrorToString(ERR_NOT_IMPLEMENTED); + return ERR_NOT_IMPLEMENTED; } + } // namespace net diff --git a/net/http/http_auth_handler_basic.h b/net/http/http_auth_handler_basic.h index 679c91a..e4d2f25 100644 --- a/net/http/http_auth_handler_basic.h +++ b/net/http/http_auth_handler_basic.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,10 +12,17 @@ namespace net { // Code for handling http basic authentication. class HttpAuthHandlerBasic : public HttpAuthHandler { public: - virtual std::string GenerateCredentials(const std::wstring& username, - const std::wstring& password, - const HttpRequestInfo*, - const ProxyInfo*); + virtual int GenerateAuthToken(const std::wstring& username, + const std::wstring& password, + const HttpRequestInfo*, + const ProxyInfo*, + std::string* auth_token); + + virtual int GenerateDefaultAuthToken(const HttpRequestInfo* request, + const ProxyInfo* proxy, + std::string* auth_token); + + protected: virtual bool Init(std::string::const_iterator challenge_begin, std::string::const_iterator challenge_end); diff --git a/net/http/http_auth_handler_basic_unittest.cc b/net/http/http_auth_handler_basic_unittest.cc index d7a1437..59d9a56 100644 --- a/net/http/http_auth_handler_basic_unittest.cc +++ b/net/http/http_auth_handler_basic_unittest.cc @@ -1,15 +1,16 @@ -// 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/basictypes.h" +#include "net/base/net_errors.h" #include "net/http/http_auth_handler_basic.h" namespace net { -TEST(HttpAuthHandlerBasicTest, GenerateCredentials) { +TEST(HttpAuthHandlerBasicTest, GenerateAuthToken) { static const struct { const wchar_t* username; const wchar_t* password; @@ -30,9 +31,13 @@ TEST(HttpAuthHandlerBasicTest, GenerateCredentials) { bool ok = basic->InitFromChallenge(challenge.begin(), challenge.end(), HttpAuth::AUTH_SERVER, origin); EXPECT_TRUE(ok); - std::string credentials = basic->GenerateCredentials(tests[i].username, - tests[i].password, - NULL, NULL); + std::string credentials; + int rv = basic->GenerateAuthToken(tests[i].username, + tests[i].password, + NULL, + NULL, + &credentials); + EXPECT_EQ(OK, rv); EXPECT_STREQ(tests[i].expected_credentials, credentials.c_str()); } } diff --git a/net/http/http_auth_handler_digest.cc b/net/http/http_auth_handler_digest.cc index a0c443c..10af291 100644 --- a/net/http/http_auth_handler_digest.cc +++ b/net/http/http_auth_handler_digest.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. @@ -7,6 +7,7 @@ #include "base/md5.h" #include "base/rand_util.h" #include "base/string_util.h" +#include "net/base/net_errors.h" #include "net/base/net_util.h" #include "net/http/http_auth.h" #include "net/http/http_request_info.h" @@ -77,11 +78,12 @@ std::string HttpAuthHandlerDigest::AlgorithmToString(int algorithm) { } } -std::string HttpAuthHandlerDigest::GenerateCredentials( +int HttpAuthHandlerDigest::GenerateAuthToken( const std::wstring& username, const std::wstring& password, const HttpRequestInfo* request, - const ProxyInfo* proxy) { + const ProxyInfo* proxy, + std::string* auth_token) { // Generate a random client nonce. std::string cnonce = GenerateNonce(); @@ -97,11 +99,21 @@ std::string HttpAuthHandlerDigest::GenerateCredentials( std::string path; GetRequestMethodAndPath(request, proxy, &method, &path); - return AssembleCredentials(method, path, - // TODO(eroman): is this the right encoding? - WideToUTF8(username), - WideToUTF8(password), - cnonce, nonce_count); + *auth_token = AssembleCredentials(method, path, + // TODO(eroman): is this the right encoding? + WideToUTF8(username), + WideToUTF8(password), + cnonce, nonce_count); + return OK; +} + +int HttpAuthHandlerDigest::GenerateDefaultAuthToken( + const HttpRequestInfo* request, + const ProxyInfo* proxy, + std::string* auth_token) { + NOTREACHED(); + LOG(ERROR) << ErrorToString(ERR_NOT_IMPLEMENTED); + return ERR_NOT_IMPLEMENTED; } void HttpAuthHandlerDigest::GetRequestMethodAndPath( diff --git a/net/http/http_auth_handler_digest.h b/net/http/http_auth_handler_digest.h index b4c8687..686f354 100644 --- a/net/http/http_auth_handler_digest.h +++ b/net/http/http_auth_handler_digest.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,10 +15,15 @@ namespace net { // Code for handling http digest authentication. class HttpAuthHandlerDigest : public HttpAuthHandler { public: - virtual std::string GenerateCredentials(const std::wstring& username, - const std::wstring& password, - const HttpRequestInfo* request, - const ProxyInfo* proxy); + virtual int GenerateAuthToken(const std::wstring& username, + const std::wstring& password, + const HttpRequestInfo* request, + const ProxyInfo* proxy, + std::string* auth_token); + + virtual int GenerateDefaultAuthToken(const HttpRequestInfo* request, + const ProxyInfo* proxy, + std::string* auth_token); protected: virtual bool Init(std::string::const_iterator challenge_begin, diff --git a/net/http/http_auth_handler_negotiate.h b/net/http/http_auth_handler_negotiate.h index eb4d11f..b057f5c 100644 --- a/net/http/http_auth_handler_negotiate.h +++ b/net/http/http_auth_handler_negotiate.h @@ -30,11 +30,17 @@ class HttpAuthHandlerNegotiate : public HttpAuthHandler { virtual bool IsFinalRound(); - virtual std::string GenerateCredentials(const std::wstring& username, - const std::wstring& password, - const HttpRequestInfo* request, - const ProxyInfo* proxy); + virtual bool AllowDefaultCredentials(); + virtual int GenerateAuthToken(const std::wstring& username, + const std::wstring& password, + const HttpRequestInfo* request, + const ProxyInfo* proxy, + std::string* auth_token); + + virtual int GenerateDefaultAuthToken(const HttpRequestInfo* request, + const ProxyInfo* proxy, + std::string* auth_token); protected: virtual bool Init(std::string::const_iterator challenge_begin, diff --git a/net/http/http_auth_handler_negotiate_posix.cc b/net/http/http_auth_handler_negotiate_posix.cc index 581b489..f70b58b 100755..100644 --- a/net/http/http_auth_handler_negotiate_posix.cc +++ b/net/http/http_auth_handler_negotiate_posix.cc @@ -5,6 +5,7 @@ #include "net/http/http_auth_handler_negotiate.h" #include "base/logging.h" +#include "net/base/net_errors.h" namespace net { @@ -20,11 +21,19 @@ HttpAuthHandlerNegotiate::~HttpAuthHandlerNegotiate() { bool HttpAuthHandlerNegotiate::NeedsIdentity() { NOTREACHED(); + LOG(ERROR) << ErrorToString(ERR_NOT_IMPLEMENTED); return false; } bool HttpAuthHandlerNegotiate::IsFinalRound() { NOTREACHED(); + LOG(ERROR) << ErrorToString(ERR_NOT_IMPLEMENTED); + return false; +} + +bool HttpAuthHandlerNegotiate::AllowDefaultCredentials() { + NOTREACHED(); + LOG(ERROR) << ErrorToString(ERR_NOT_IMPLEMENTED); return false; } @@ -33,13 +42,24 @@ bool HttpAuthHandlerNegotiate::Init(std::string::const_iterator challenge_begin, return false; } -std::string HttpAuthHandlerNegotiate::GenerateCredentials( +int HttpAuthHandlerNegotiate::GenerateAuthToken( const std::wstring& username, const std::wstring& password, const HttpRequestInfo* request, - const ProxyInfo* proxy) { + const ProxyInfo* proxy, + std::string* auth_token) { + NOTREACHED(); + LOG(ERROR) << ErrorToString(ERR_NOT_IMPLEMENTED); + return ERR_NOT_IMPLEMENTED; +} + +int HttpAuthHandlerNegotiate::GenerateDefaultAuthToken( + const HttpRequestInfo* request, + const ProxyInfo* proxy, + std::string* auth_token) { NOTREACHED(); - return std::string(); + LOG(ERROR) << ErrorToString(ERR_NOT_IMPLEMENTED); + return ERR_NOT_IMPLEMENTED; } } // namespace net diff --git a/net/http/http_auth_handler_negotiate_win.cc b/net/http/http_auth_handler_negotiate_win.cc index 782cb5c..c005590 100644 --- a/net/http/http_auth_handler_negotiate_win.cc +++ b/net/http/http_auth_handler_negotiate_win.cc @@ -15,23 +15,19 @@ HttpAuthHandlerNegotiate::HttpAuthHandlerNegotiate() : HttpAuthHandlerNegotiate::~HttpAuthHandlerNegotiate() { } -std::string HttpAuthHandlerNegotiate::GenerateCredentials( +int HttpAuthHandlerNegotiate::GenerateAuthToken( const std::wstring& username, const std::wstring& password, const HttpRequestInfo* request, - const ProxyInfo* proxy) { - std::string auth_credentials; - - int rv = auth_sspi_.GenerateCredentials( - username, - password, + const ProxyInfo* proxy, + std::string* auth_token) { + return auth_sspi_.GenerateAuthToken( + &username, + &password, origin_, request, proxy, - &auth_credentials); - if (rv == OK) - return auth_credentials; - return std::string(); + auth_token); } // The Negotiate challenge header looks like: @@ -54,4 +50,30 @@ bool HttpAuthHandlerNegotiate::IsFinalRound() { return auth_sspi_.IsFinalRound(); } +bool HttpAuthHandlerNegotiate::AllowDefaultCredentials() { + // NOTE: Temporarily disabled. SSO is a potential security risk. + // TODO(cbentzel): Add a pointer to Firefox documentation about risk. + + // TODO(cbentzel): Add a blanket command line flag to enable/disable? + // TODO(cbentzel): Add a whitelist regexp command line flag? + // TODO(cbentzel): Resolve the origin_ (helpful if doing already) and see if + // it is in private IP space? + // TODO(cbentzel): Compare origin_ to this machine's hostname and allow if + // it matches at least two or three layers deep? + return false; +} + +int HttpAuthHandlerNegotiate::GenerateDefaultAuthToken( + const HttpRequestInfo* request, + const ProxyInfo* proxy, + std::string* auth_token) { + return auth_sspi_.GenerateAuthToken( + NULL, // username + NULL, // password + origin_, + request, + proxy, + auth_token); +} + } // namespace net diff --git a/net/http/http_auth_handler_ntlm.cc b/net/http/http_auth_handler_ntlm.cc index 6e10e79..e191ce4 100755..100644 --- a/net/http/http_auth_handler_ntlm.cc +++ b/net/http/http_auth_handler_ntlm.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. @@ -10,24 +10,20 @@ namespace net { -std::string HttpAuthHandlerNTLM::GenerateCredentials( +int HttpAuthHandlerNTLM::GenerateAuthToken( const std::wstring& username, const std::wstring& password, const HttpRequestInfo* request, - const ProxyInfo* proxy) { + const ProxyInfo* proxy, + std::string* auth_token) { #if defined(NTLM_SSPI) - std::string auth_credentials; - - int rv = auth_sspi_.GenerateCredentials( - username, - password, + return auth_sspi_.GenerateAuthToken( + &username, + &password, origin_, request, proxy, - &auth_credentials); - if (rv == OK) - return auth_credentials; - return std::string(); + auth_token); #else // !defined(NTLM_SSPI) // TODO(wtc): See if we can use char* instead of void* for in_buf and // out_buf. This change will need to propagate to GetNextToken, @@ -58,7 +54,7 @@ std::string HttpAuthHandlerNTLM::GenerateCredentials( in_buf = NULL; int rv = InitializeBeforeFirstChallenge(); if (rv != OK) - return std::string(); + return rv; } else { // Decode |auth_data_| into the input buffer. int len = auth_data_.length(); @@ -71,25 +67,30 @@ std::string HttpAuthHandlerNTLM::GenerateCredentials( len--; auth_data_.erase(len); - if (!base::Base64Decode(auth_data_, &decoded_auth_data)) - return std::string(); // Improper base64 encoding + if (!base::Base64Decode(auth_data_, &decoded_auth_data)) { + LOG(ERROR) << "Unexpected problem Base64 decoding."; + return ERR_UNEXPECTED; + } in_buf_len = decoded_auth_data.length(); in_buf = decoded_auth_data.data(); } int rv = GetNextToken(in_buf, in_buf_len, &out_buf, &out_buf_len); if (rv != OK) - return std::string(); + return rv; // Base64 encode data in output buffer and prepend "NTLM ". std::string encode_input(static_cast<char*>(out_buf), out_buf_len); std::string encode_output; - bool ok = base::Base64Encode(encode_input, &encode_output); + bool base64_rv = base::Base64Encode(encode_input, &encode_output); // OK, we are done with |out_buf| free(out_buf); - if (!ok) - return std::string(); - return std::string("NTLM ") + encode_output; + if (!base64_rv) { + LOG(ERROR) << "Unexpected problem Base64 encoding."; + return ERR_UNEXPECTED; + } + *auth_token = std::string("NTLM ") + encode_output; + return OK; #endif } diff --git a/net/http/http_auth_handler_ntlm.h b/net/http/http_auth_handler_ntlm.h index c3bda62..c4b9dab 100644 --- a/net/http/http_auth_handler_ntlm.h +++ b/net/http/http_auth_handler_ntlm.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. @@ -68,10 +68,17 @@ class HttpAuthHandlerNTLM : public HttpAuthHandler { virtual bool IsFinalRound(); - virtual std::string GenerateCredentials(const std::wstring& username, - const std::wstring& password, - const HttpRequestInfo* request, - const ProxyInfo* proxy); + virtual bool AllowDefaultCredentials(); + + virtual int GenerateAuthToken(const std::wstring& username, + const std::wstring& password, + const HttpRequestInfo* request, + const ProxyInfo* proxy, + std::string* auth_token); + + virtual int GenerateDefaultAuthToken(const HttpRequestInfo* request, + const ProxyInfo* proxy, + std::string* auth_token); protected: virtual bool Init(std::string::const_iterator challenge_begin, diff --git a/net/http/http_auth_handler_ntlm_portable.cc b/net/http/http_auth_handler_ntlm_portable.cc index 7976878..7fccfce 100644 --- a/net/http/http_auth_handler_ntlm_portable.cc +++ b/net/http/http_auth_handler_ntlm_portable.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. @@ -657,6 +657,12 @@ bool HttpAuthHandlerNTLM::IsFinalRound() { return !auth_data_.empty(); } +bool HttpAuthHandlerNTLM::AllowDefaultCredentials() { + // Default credentials are not supported in the portable implementation of + // NTLM, but are supported in the SSPI implementation. + return false; +} + // static HttpAuthHandlerNTLM::GenerateRandomProc HttpAuthHandlerNTLM::SetGenerateRandomProc( @@ -704,4 +710,13 @@ int HttpAuthHandlerNTLM::InitializeBeforeFirstChallenge() { return OK; } +int HttpAuthHandlerNTLM::GenerateDefaultAuthToken( + const HttpRequestInfo* request, + const ProxyInfo* proxy, + std::string* auth_token) { + NOTREACHED(); + LOG(ERROR) << ErrorToString(ERR_NOT_IMPLEMENTED); + return ERR_NOT_IMPLEMENTED; +} + } // namespace net diff --git a/net/http/http_auth_handler_ntlm_win.cc b/net/http/http_auth_handler_ntlm_win.cc index fba9c1b..c096aaf 100644 --- a/net/http/http_auth_handler_ntlm_win.cc +++ b/net/http/http_auth_handler_ntlm_win.cc @@ -34,6 +34,31 @@ bool HttpAuthHandlerNTLM::IsFinalRound() { return auth_sspi_.IsFinalRound(); } +bool HttpAuthHandlerNTLM::AllowDefaultCredentials() { + // NOTE: Temporarily disabled. SSO is a potential security risk with NTLM. + // TODO(cbentzel): Add a pointer to Firefox documentation about risk. + + // TODO(cbentzel): Add a blanket command line flag to enable/disable? + // TODO(cbentzel): Add a whitelist regexp command line flag? + // TODO(cbentzel): Resolve the origin_ (helpful if doing already) and see if + // it is in private IP space? + // TODO(cbentzel): Compare origin_ to this machine's hostname and allow if + // it matches at least two or three layers deep? + return false; +} + +int HttpAuthHandlerNTLM::GenerateDefaultAuthToken( + const HttpRequestInfo* request, + const ProxyInfo* proxy, + std::string* auth_token) { + return auth_sspi_.GenerateAuthToken( + NULL, // username + NULL, // password + origin_, + request, + proxy, + auth_token); +} } // namespace net diff --git a/net/http/http_auth_sspi_win.cc b/net/http/http_auth_sspi_win.cc index 00861e5..c858d36 100644 --- a/net/http/http_auth_sspi_win.cc +++ b/net/http/http_auth_sspi_win.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,87 @@ #include "net/http/http_auth.h" namespace net { +namespace { + +int MapAcquireCredentialsStatusToError(SECURITY_STATUS status, + const SEC_WCHAR* package) { + switch (status) { + case SEC_E_OK: + return OK; + case SEC_E_INSUFFICIENT_MEMORY: + return ERR_OUT_OF_MEMORY; + case SEC_E_INTERNAL_ERROR: + return ERR_UNEXPECTED; + case SEC_E_NO_CREDENTIALS: + case SEC_E_NOT_OWNER: + case SEC_E_UNKNOWN_CREDENTIALS: + return ERR_INVALID_AUTH_CREDENTIALS; + case SEC_E_SECPKG_NOT_FOUND: + // This indicates that the SSPI configuration does not match expectations + LOG(ERROR) << "Received SEC_E_SECPKG_NOT_FOUND for " << package; + return ERR_UNSUPPORTED_AUTH_SCHEME; + default: + LOG(ERROR) << "Unexpected SECURITY_STATUS " << status; + return ERR_UNEXPECTED; + } +} + +int AcquireCredentials(const SEC_WCHAR* package, + const std::wstring& domain, + const std::wstring& user, + const std::wstring& password, + CredHandle* cred) { + SEC_WINNT_AUTH_IDENTITY identity; + identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; + identity.User = + reinterpret_cast<unsigned short*>(const_cast<wchar_t*>(user.c_str())); + identity.UserLength = user.size(); + identity.Domain = + reinterpret_cast<unsigned short*>(const_cast<wchar_t*>(domain.c_str())); + identity.DomainLength = domain.size(); + identity.Password = + reinterpret_cast<unsigned short*>(const_cast<wchar_t*>(password.c_str())); + identity.PasswordLength = password.size(); + + TimeStamp expiry; + + // Pass the username/password to get the credentials handle. + SECURITY_STATUS status = AcquireCredentialsHandle( + NULL, // pszPrincipal + const_cast<SEC_WCHAR*>(package), // pszPackage + SECPKG_CRED_OUTBOUND, // fCredentialUse + NULL, // pvLogonID + &identity, // pAuthData + NULL, // pGetKeyFn (not used) + NULL, // pvGetKeyArgument (not used) + cred, // phCredential + &expiry); // ptsExpiry + + return MapAcquireCredentialsStatusToError(status, package); +} + +int AcquireDefaultCredentials(const SEC_WCHAR* package, CredHandle* cred) { + TimeStamp expiry; + + // Pass the username/password to get the credentials handle. + // Note: Since the 5th argument is NULL, it uses the default + // cached credentials for the logged in user, which can be used + // for a single sign-on. + SECURITY_STATUS status = AcquireCredentialsHandle( + NULL, // pszPrincipal + const_cast<SEC_WCHAR*>(package), // pszPackage + SECPKG_CRED_OUTBOUND, // fCredentialUse + NULL, // pvLogonID + NULL, // pAuthData + NULL, // pGetKeyFn (not used) + NULL, // pvGetKeyArgument (not used) + cred, // phCredential + &expiry); // ptsExpiry + + return MapAcquireCredentialsStatusToError(status, package); +} + +} // anonymous namespace HttpAuthSSPI::HttpAuthSSPI(const std::string& scheme, SEC_WCHAR* security_package) @@ -73,28 +154,26 @@ bool HttpAuthSSPI::ParseChallenge(std::string::const_iterator challenge_begin, encoded_auth_token.erase(encoded_length); std::string decoded_auth_token; - bool rv = base::Base64Decode(encoded_auth_token, &decoded_auth_token); - if (rv) { - decoded_server_auth_token_ = decoded_auth_token; + bool base64_rv = base::Base64Decode(encoded_auth_token, &decoded_auth_token); + if (!base64_rv) { + LOG(ERROR) << "Base64 decoding of auth token failed."; + return false; } - return rv; + decoded_server_auth_token_ = decoded_auth_token; + return true; } -int HttpAuthSSPI::GenerateCredentials(const std::wstring& username, - const std::wstring& password, - const GURL& origin, - const HttpRequestInfo* request, - const ProxyInfo* proxy, - std::string* out_credentials) { - // |username| may be in the form "DOMAIN\user". Parse it into the two - // components. - std::wstring domain; - std::wstring user; - SplitDomainAndUser(username, &domain, &user); +int HttpAuthSSPI::GenerateAuthToken(const std::wstring* username, + const std::wstring* password, + const GURL& origin, + const HttpRequestInfo* request, + const ProxyInfo* proxy, + std::string* auth_token) { + DCHECK((username == NULL) == (password == NULL)); // Initial challenge. if (!IsFinalRound()) { - int rv = OnFirstRound(domain, user, password); + int rv = OnFirstRound(username, password); if (rv != OK) return rv; } @@ -114,23 +193,38 @@ int HttpAuthSSPI::GenerateCredentials(const std::wstring& username, // Base64 encode data in output buffer and prepend the scheme. std::string encode_input(static_cast<char*>(out_buf), out_buf_len); std::string encode_output; - bool ok = base::Base64Encode(encode_input, &encode_output); + bool base64_rv = base::Base64Encode(encode_input, &encode_output); // OK, we are done with |out_buf| free(out_buf); - if (!ok) - return rv; - *out_credentials = scheme_ + " " + encode_output; + if (!base64_rv) { + LOG(ERROR) << "Base64 encoding of auth token failed."; + return ERR_UNEXPECTED; + } + *auth_token = scheme_ + " " + encode_output; return OK; } -int HttpAuthSSPI::OnFirstRound(const std::wstring& domain, - const std::wstring& user, - const std::wstring& password) { +int HttpAuthSSPI::OnFirstRound(const std::wstring* username, + const std::wstring* password) { + DCHECK((username == NULL) == (password == NULL)); + int rv = DetermineMaxTokenLength(security_package_, &max_token_length_); - if (rv != OK) { + if (rv != OK) return rv; + + if (username) { + std::wstring domain; + std::wstring user; + SplitDomainAndUser(*username, &domain, &user); + rv = AcquireCredentials(security_package_, domain, user, *password, &cred_); + if (rv != OK) + return rv; + } else { + rv = AcquireDefaultCredentials(security_package_, &cred_); + if (rv != OK) + return rv; } - rv = AcquireCredentials(security_package_, domain, user, password, &cred_); + return rv; } @@ -204,7 +298,7 @@ int HttpAuthSSPI::GetNextSecurityToken( // and SEC_E_OK on the second call. On failure, the function returns an // error code. if (status != SEC_I_CONTINUE_NEEDED && status != SEC_E_OK) { - LOG(ERROR) << "InitializeSecurityContext failed: " << status; + LOG(ERROR) << "InitializeSecurityContext failed " << status; ResetSecurityContext(); free(out_buffer.pvBuffer); return ERR_UNEXPECTED; // TODO(wtc): map error code. @@ -221,6 +315,9 @@ int HttpAuthSSPI::GetNextSecurityToken( void SplitDomainAndUser(const std::wstring& combined, std::wstring* domain, std::wstring* user) { + // |combined| may be in the form "user" or "DOMAIN\user". + // Separatethe two parts if they exist. + // TODO(cbentzel): I believe user@domain is also a valid form. size_t backslash_idx = combined.find(L'\\'); if (backslash_idx == std::wstring::npos) { domain->clear(); @@ -233,54 +330,36 @@ void SplitDomainAndUser(const std::wstring& combined, int DetermineMaxTokenLength(const std::wstring& package, ULONG* max_token_length) { - PSecPkgInfo pkg_info; + PSecPkgInfo pkg_info = NULL; SECURITY_STATUS status = QuerySecurityPackageInfo( const_cast<wchar_t *>(package.c_str()), &pkg_info); if (status != SEC_E_OK) { - LOG(ERROR) << "Security package " << package << " not found"; - return ERR_UNEXPECTED; + // The documentation at + // http://msdn.microsoft.com/en-us/library/aa379359(VS.85).aspx + // only mentions that a non-zero (or non-SEC_E_OK) value is returned + // if the function fails. In practice, it appears to return + // SEC_E_SECPKG_NOT_FOUND for invalid/unknown packages. + LOG(ERROR) << "Security package " << package << " not found." + << " Status code: " << status; + if (status == SEC_E_SECPKG_NOT_FOUND) + return ERR_UNSUPPORTED_AUTH_SCHEME; + else + return ERR_UNEXPECTED; } *max_token_length = pkg_info->cbMaxToken; - FreeContextBuffer(pkg_info); - return OK; -} - -int AcquireCredentials(const SEC_WCHAR* package, - const std::wstring& domain, - const std::wstring& user, - const std::wstring& password, - CredHandle* cred) { - SEC_WINNT_AUTH_IDENTITY identity; - identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; - identity.User = - reinterpret_cast<unsigned short*>(const_cast<wchar_t*>(user.c_str())); - identity.UserLength = user.size(); - identity.Domain = - reinterpret_cast<unsigned short*>(const_cast<wchar_t*>(domain.c_str())); - identity.DomainLength = domain.size(); - identity.Password = - reinterpret_cast<unsigned short*>(const_cast<wchar_t*>(password.c_str())); - identity.PasswordLength = password.size(); - - TimeStamp expiry; - - // Pass the username/password to get the credentials handle. - // Note: If the 5th argument is NULL, it uses the default cached credentials - // for the logged in user, which can be used for single sign-on. - SECURITY_STATUS status = AcquireCredentialsHandle( - NULL, // pszPrincipal - const_cast<SEC_WCHAR*>(package), // pszPackage - SECPKG_CRED_OUTBOUND, // fCredentialUse - NULL, // pvLogonID - &identity, // pAuthData - NULL, // pGetKeyFn (not used) - NULL, // pvGetKeyArgument (not used) - cred, // phCredential - &expiry); // ptsExpiry - - if (status != SEC_E_OK) + status = FreeContextBuffer(pkg_info); + if (status != SEC_E_OK) { + // The documentation at + // http://msdn.microsoft.com/en-us/library/aa375416(VS.85).aspx + // only mentions that a non-zero (or non-SEC_E_OK) value is returned + // if the function fails, and does not indicate what the failure conditions + // are. + LOG(ERROR) << "Unexpected problem freeing context buffer. Status code: " + << status; return ERR_UNEXPECTED; + } return OK; } + } // namespace net diff --git a/net/http/http_auth_sspi_win.h b/net/http/http_auth_sspi_win.h index 4d340aa..b94ffbc 100755..100644 --- a/net/http/http_auth_sspi_win.h +++ b/net/http/http_auth_sspi_win.h @@ -35,17 +35,22 @@ class HttpAuthSSPI { bool ParseChallenge(std::string::const_iterator challenge_begin, std::string::const_iterator challenge_end); - int GenerateCredentials(const std::wstring& username, - const std::wstring& password, - const GURL& origin, - const HttpRequestInfo* request, - const ProxyInfo* proxy, - std::string* out_credentials); + // Generates an authentication token. + // The return value is an error code. If it's not |OK|, the value of + // |*auth_token| is unspecified. + // If this is the first round of a multiple round scheme, credentials are + // obtained using |*username| and |*password|. If |username| and |password| + // are NULL, the default credentials are used instead. + int GenerateAuthToken(const std::wstring* username, + const std::wstring* password, + const GURL& origin, + const HttpRequestInfo* request, + const ProxyInfo* proxy, + std::string* auth_token); private: - int OnFirstRound(const std::wstring& domain, - const std::wstring& user, - const std::wstring& password); + int OnFirstRound(const std::wstring* username, + const std::wstring* password); int GetNextSecurityToken( const GURL& origin, @@ -80,13 +85,6 @@ void SplitDomainAndUser(const std::wstring& combined, int DetermineMaxTokenLength(const std::wstring& package, ULONG* max_token_length); -// Acquire credentials for a user. -int AcquireCredentials(const SEC_WCHAR* package, - const std::wstring& domain, - const std::wstring& user, - const std::wstring& password, - CredHandle* cred); - } // namespace net #endif // NET_HTTP_HTTP_AUTH_SSPI_WIN_H_ diff --git a/net/http/http_auth_unittest.cc b/net/http/http_auth_unittest.cc index a960d70..a960d70 100755..100644 --- a/net/http/http_auth_unittest.cc +++ b/net/http/http_auth_unittest.cc diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 300482f..d89a84a 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.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. @@ -1609,14 +1609,21 @@ std::string HttpNetworkTransaction::BuildAuthorizationHeader( DCHECK(HaveAuth(target)); // Add a Authorization/Proxy-Authorization header line. - std::string credentials = auth_handler_[target]->GenerateCredentials( + std::string auth_token; + int rv = auth_handler_[target]->GenerateAuthToken( auth_identity_[target].username, auth_identity_[target].password, request_, - &proxy_info_); - - return HttpAuth::GetAuthorizationHeaderName(target) + - ": " + credentials + "\r\n"; + &proxy_info_, + &auth_token); + if (rv == OK) + return HttpAuth::GetAuthorizationHeaderName(target) + + ": " + auth_token + "\r\n"; + + // TODO(cbentzel): Evict username and password from cache on non-OK return? + // TODO(cbentzel): Never use this scheme again if + // ERR_UNSUPPORTED_AUTH_SCHEME is returned. + return std::string(); } GURL HttpNetworkTransaction::AuthOrigin(HttpAuth::Target target) const { diff --git a/net/socket_stream/socket_stream.cc b/net/socket_stream/socket_stream.cc index 2a01f17..aae234e 100644 --- a/net/socket_stream/socket_stream.cc +++ b/net/socket_stream/socket_stream.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. // @@ -556,14 +556,21 @@ int SocketStream::DoWriteTunnelHeaders() { // HttpRequestInfo. // TODO(ukai): Add support other authentication scheme. if (auth_handler_.get() && auth_handler_->scheme() == "basic") { - std::string credentials = auth_handler_->GenerateCredentials( + std::string auth_token; + int rv = auth_handler_->GenerateAuthToken( auth_identity_.username, auth_identity_.password, NULL, - &proxy_info_); + &proxy_info_, + &auth_token); + // TODO(cbentzel): Should do something different if credentials + // can't be generated. In this case, only Basic is allowed which + // should only fail if Base64 encoding fails. + if (rv != OK) + auth_token = std::string(); authorization_headers.append( HttpAuth::GetAuthorizationHeaderName(HttpAuth::AUTH_PROXY) + - ": " + credentials + "\r\n"); + ": " + auth_token + "\r\n"); } tunnel_request_headers_->headers_ = StringPrintf( |