summaryrefslogtreecommitdiffstats
path: root/net/http
diff options
context:
space:
mode:
authorcbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-08 23:46:54 +0000
committercbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-08 23:46:54 +0000
commitc52e6087c9079a016fcf43ef2ba9ca64a0558488 (patch)
tree0c12400b20edc7f64b48452f82b0e0ceb23837d5 /net/http
parent28f964305c178006b7b73792b5f62ce16da24f10 (diff)
downloadchromium_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.cc128
-rw-r--r--net/http/http_auth_gssapi_posix.h4
-rw-r--r--net/http/http_auth_handler_negotiate_unittest.cc20
-rw-r--r--net/http/http_auth_sspi_win.cc8
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;
}
}