diff options
author | cbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-08 23:46:54 +0000 |
---|---|---|
committer | cbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-08 23:46:54 +0000 |
commit | c52e6087c9079a016fcf43ef2ba9ca64a0558488 (patch) | |
tree | 0c12400b20edc7f64b48452f82b0e0ceb23837d5 /net/http | |
parent | 28f964305c178006b7b73792b5f62ce16da24f10 (diff) | |
download | chromium_src-c52e6087c9079a016fcf43ef2ba9ca64a0558488.zip chromium_src-c52e6087c9079a016fcf43ef2ba9ca64a0558488.tar.gz chromium_src-c52e6087c9079a016fcf43ef2ba9ca64a0558488.tar.bz2 |
Improved error reporting for GSSAPI statuses.
Also, remove the OnFirstRound carried over from the SSPI implementation.
BUG=53850
TEST=None
Review URL: http://codereview.chromium.org/3345007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@58895 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/http')
-rw-r--r-- | net/http/http_auth_gssapi_posix.cc | 128 | ||||
-rw-r--r-- | net/http/http_auth_gssapi_posix.h | 4 | ||||
-rw-r--r-- | net/http/http_auth_handler_negotiate_unittest.cc | 20 | ||||
-rw-r--r-- | net/http/http_auth_sspi_win.cc | 8 |
4 files changed, 112 insertions, 48 deletions
diff --git a/net/http/http_auth_gssapi_posix.cc b/net/http/http_auth_gssapi_posix.cc index aeed731..2c605a0 100644 --- a/net/http/http_auth_gssapi_posix.cc +++ b/net/http/http_auth_gssapi_posix.cc @@ -731,13 +731,7 @@ int HttpAuthGSSAPI::GenerateAuthToken(const string16* username, const std::wstring& spn, std::string* auth_token) { DCHECK(auth_token); - DCHECK((username == NULL) == (password == NULL)); - - if (!IsFinalRound()) { - int rv = OnFirstRound(username, password); - if (rv != OK) - return rv; - } + DCHECK(username == NULL && password == NULL); gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; input_token.length = decoded_server_auth_token_.length(); @@ -755,24 +749,107 @@ int HttpAuthGSSAPI::GenerateAuthToken(const string16* username, std::string encode_input(static_cast<char*>(output_token.value), output_token.length); std::string encode_output; - bool ok = base::Base64Encode(encode_input, &encode_output); - if (!ok) - return ERR_UNEXPECTED; + bool base64_rv = base::Base64Encode(encode_input, &encode_output); + if (!base64_rv) { + LOG(ERROR) << "Base64 encoding of auth token failed."; + return ERR_ENCODING_CONVERSION_FAILED; + } *auth_token = scheme_ + " " + encode_output; return OK; } -int HttpAuthGSSAPI::OnFirstRound(const string16* username, - const string16* password) { - // TODO(cbentzel): Acquire credentials? - DCHECK((username == NULL) == (password == NULL)); - username_.clear(); - password_.clear(); - if (username) { - username_ = *username; - password_ = *password; + +namespace { + +// GSSAPI status codes consist of a calling error (essentially, a programmer +// bug), a routine error (defined by the RFC), and supplementary information, +// all bitwise-or'ed together in different regions of the 32 bit return value. +// This means a simple switch on the return codes is not sufficient. + +int MapImportNameStatusToError(OM_uint32 major_status) { + LOG(INFO) << "import_name returned 0x" << std::hex << major_status; + if (major_status == GSS_S_COMPLETE) + return OK; + if (GSS_CALLING_ERROR(major_status) != 0) + return ERR_UNEXPECTED; + OM_uint32 routine_error = GSS_ROUTINE_ERROR(major_status); + switch (routine_error) { + case GSS_S_FAILURE: + // Looking at the MIT Kerberos implementation, this typically is returned + // when memory allocation fails. However, the API does not guarantee + // that this is the case, so using ERR_UNEXPECTED rather than + // ERR_OUT_OF_MEMORY. + return ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS; + case GSS_S_BAD_NAME: + case GSS_S_BAD_NAMETYPE: + return ERR_MALFORMED_IDENTITY; + case GSS_S_DEFECTIVE_TOKEN: + // Not mentioned in the API, but part of code. + return ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS; + case GSS_S_BAD_MECH: + return ERR_UNSUPPORTED_AUTH_SCHEME; + default: + return ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS; } - return OK; +} + +int MapInitSecContextStatusToError(OM_uint32 major_status) { + LOG(INFO) << "init_sec_context returned 0x" << std::hex << major_status; + // Although GSS_S_CONTINUE_NEEDED is an additional bit, it seems like + // other code just checks if major_status is equivalent to it to indicate + // that there are no other errors included. + if (major_status == GSS_S_COMPLETE || major_status == GSS_S_CONTINUE_NEEDED) + return OK; + if (GSS_CALLING_ERROR(major_status) != 0) + return ERR_UNEXPECTED; + OM_uint32 routine_status = GSS_ROUTINE_ERROR(major_status); + switch (routine_status) { + case GSS_S_DEFECTIVE_TOKEN: + return ERR_INVALID_RESPONSE; + case GSS_S_DEFECTIVE_CREDENTIAL: + // Not expected since this implementation uses the default credential. + return ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS; + case GSS_S_BAD_SIG: + // Probably won't happen, but it's a bad response. + return ERR_INVALID_RESPONSE; + case GSS_S_NO_CRED: + return ERR_INVALID_AUTH_CREDENTIALS; + case GSS_S_CREDENTIALS_EXPIRED: + return ERR_INVALID_AUTH_CREDENTIALS; + case GSS_S_BAD_BINDINGS: + // This only happens with mutual authentication. + return ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS; + case GSS_S_NO_CONTEXT: + return ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS; + case GSS_S_BAD_NAMETYPE: + return ERR_UNSUPPORTED_AUTH_SCHEME; + case GSS_S_BAD_NAME: + return ERR_UNSUPPORTED_AUTH_SCHEME; + case GSS_S_BAD_MECH: + return ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS; + case GSS_S_FAILURE: + // This should be an "Unexpected Security Status" according to the + // GSSAPI documentation, but it's typically used to indicate that + // credentials are not correctly set up on a user machine, such + // as a missing credential cache or hitting this after calling + // kdestroy. + // TODO(cbentzel): Use minor code for even better mapping? + return ERR_MISSING_AUTH_CREDENTIALS; + default: + if (routine_status != 0) + return ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS; + break; + } + OM_uint32 supplemental_status = GSS_SUPPLEMENTARY_INFO(major_status); + // Replays could indicate an attack. + if (supplemental_status & (GSS_S_DUPLICATE_TOKEN | GSS_S_OLD_TOKEN | + GSS_S_UNSEQ_TOKEN | GSS_S_GAP_TOKEN)) + return ERR_INVALID_RESPONSE; + + // At this point, every documented status has been checked. + return ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS; +} + } int HttpAuthGSSAPI::GetNextSecurityToken(const std::wstring& spn, @@ -791,14 +868,15 @@ int HttpAuthGSSAPI::GetNextSecurityToken(const std::wstring& spn, &spn_buffer, CHROME_GSS_C_NT_HOSTBASED_SERVICE, &principal_name); - if (major_status != GSS_S_COMPLETE) { + int rv = MapImportNameStatusToError(major_status); + if (rv != OK) { LOG(ERROR) << "Problem importing name from " << "spn \"" << spn_principal << "\"" << std::endl << DisplayExtendedStatus(library_, major_status, minor_status); - return ERR_UNEXPECTED; + return rv; } ScopedName scoped_name(principal_name, library_); @@ -820,8 +898,8 @@ int HttpAuthGSSAPI::GetNextSecurityToken(const std::wstring& spn, out_token, NULL, // ret flags NULL); - if (major_status != GSS_S_COMPLETE && - major_status != GSS_S_CONTINUE_NEEDED) { + rv = MapInitSecContextStatusToError(major_status); + if (rv != OK) { LOG(ERROR) << "Problem initializing context. " << std::endl << DisplayExtendedStatus(library_, @@ -829,7 +907,7 @@ int HttpAuthGSSAPI::GetNextSecurityToken(const std::wstring& spn, minor_status) << std::endl << DescribeContext(library_, scoped_sec_context_.get()); - return ERR_MISSING_AUTH_CREDENTIALS; + return rv; } return OK; diff --git a/net/http/http_auth_gssapi_posix.h b/net/http/http_auth_gssapi_posix.h index 4dddddb..7f6610e 100644 --- a/net/http/http_auth_gssapi_posix.h +++ b/net/http/http_auth_gssapi_posix.h @@ -246,15 +246,11 @@ class HttpAuthGSSAPI { void Delegate(); private: - int OnFirstRound(const string16* username, - const string16* password); int GetNextSecurityToken(const std::wstring& spn, gss_buffer_t in_token, gss_buffer_t out_token); std::string scheme_; - string16 username_; - string16 password_; gss_OID gss_oid_; GSSAPILibrary* library_; std::string decoded_server_auth_token_; diff --git a/net/http/http_auth_handler_negotiate_unittest.cc b/net/http/http_auth_handler_negotiate_unittest.cc index 3d331fc..5c90b4f 100644 --- a/net/http/http_auth_handler_negotiate_unittest.cc +++ b/net/http/http_auth_handler_negotiate_unittest.cc @@ -227,9 +227,7 @@ TEST_F(HttpAuthHandlerNegotiateTest, DisableCname) { TestCompletionCallback callback; HttpRequestInfo request_info; std::string token; - string16 username = ASCIIToUTF16("foo"); - string16 password = ASCIIToUTF16("bar"); - EXPECT_EQ(OK, auth_handler->GenerateAuthToken(&username, &password, + EXPECT_EQ(OK, auth_handler->GenerateAuthToken(NULL, NULL, &request_info, &callback, &token)); #if defined(OS_WIN) @@ -248,9 +246,7 @@ TEST_F(HttpAuthHandlerNegotiateTest, DisableCnameStandardPort) { TestCompletionCallback callback; HttpRequestInfo request_info; std::string token; - string16 username = ASCIIToUTF16("foo"); - string16 password = ASCIIToUTF16("bar"); - EXPECT_EQ(OK, auth_handler->GenerateAuthToken(&username, &password, + EXPECT_EQ(OK, auth_handler->GenerateAuthToken(NULL, NULL, &request_info, &callback, &token)); #if defined(OS_WIN) @@ -269,9 +265,7 @@ TEST_F(HttpAuthHandlerNegotiateTest, DisableCnameNonstandardPort) { TestCompletionCallback callback; HttpRequestInfo request_info; std::string token; - string16 username = ASCIIToUTF16("foo"); - string16 password = ASCIIToUTF16("bar"); - EXPECT_EQ(OK, auth_handler->GenerateAuthToken(&username, &password, + EXPECT_EQ(OK, auth_handler->GenerateAuthToken(NULL, NULL, &request_info, &callback, &token)); #if defined(OS_WIN) @@ -290,9 +284,7 @@ TEST_F(HttpAuthHandlerNegotiateTest, CnameSync) { TestCompletionCallback callback; HttpRequestInfo request_info; std::string token; - string16 username = ASCIIToUTF16("foo"); - string16 password = ASCIIToUTF16("bar"); - EXPECT_EQ(OK, auth_handler->GenerateAuthToken(&username, &password, + EXPECT_EQ(OK, auth_handler->GenerateAuthToken(NULL, NULL, &request_info, &callback, &token)); #if defined(OS_WIN) @@ -311,10 +303,8 @@ TEST_F(HttpAuthHandlerNegotiateTest, CnameAsync) { TestCompletionCallback callback; HttpRequestInfo request_info; std::string token; - string16 username = ASCIIToUTF16("foo"); - string16 password = ASCIIToUTF16("bar"); EXPECT_EQ(ERR_IO_PENDING, auth_handler->GenerateAuthToken( - &username, &password, &request_info, &callback, &token)); + NULL, NULL, &request_info, &callback, &token)); EXPECT_EQ(OK, callback.WaitForResult()); #if defined(OS_WIN) EXPECT_EQ(L"HTTP/canonical.example.com", auth_handler->spn()); diff --git a/net/http/http_auth_sspi_win.cc b/net/http/http_auth_sspi_win.cc index a988e19..6ff9529 100644 --- a/net/http/http_auth_sspi_win.cc +++ b/net/http/http_auth_sspi_win.cc @@ -29,7 +29,7 @@ int MapAcquireCredentialsStatusToError(SECURITY_STATUS status, return ERR_OUT_OF_MEMORY; case SEC_E_INTERNAL_ERROR: LOG(ERROR) << "Unexpected SECURITY_STATUS " << status; - return ERR_UNEXPECTED_SSPI_STATUS; + return ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS; case SEC_E_NO_CREDENTIALS: case SEC_E_NOT_OWNER: case SEC_E_UNKNOWN_CREDENTIALS: @@ -40,7 +40,7 @@ int MapAcquireCredentialsStatusToError(SECURITY_STATUS status, return ERR_UNSUPPORTED_AUTH_SCHEME; default: LOG(ERROR) << "Undocumented SECURITY_STATUS " << status; - return ERR_UNDOCUMENTED_SSPI_STATUS; + return ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS; } } @@ -246,7 +246,7 @@ int MapInitializeSecurityContextStatusToError(SECURITY_STATUS status) { // but not expected by Chrome (for example, INCOMPLETE_CREDENTIALS // and INCOMPLETE_MESSAGE are intended for schannel). LOG(ERROR) << "Unexpected SECURITY_STATUS " << status; - return ERR_UNEXPECTED_SSPI_STATUS; + return ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS; case SEC_E_INSUFFICIENT_MEMORY: return ERR_OUT_OF_MEMORY; case SEC_E_UNSUPPORTED_FUNCTION: @@ -267,7 +267,7 @@ int MapInitializeSecurityContextStatusToError(SECURITY_STATUS status) { return ERR_MISCONFIGURED_AUTH_ENVIRONMENT; default: LOG(ERROR) << "Undocumented SECURITY_STATUS " << status; - return ERR_UNDOCUMENTED_SSPI_STATUS; + return ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS; } } |