summaryrefslogtreecommitdiffstats
path: root/net/http/http_auth_sspi_win.cc
diff options
context:
space:
mode:
authorcbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-05 19:13:29 +0000
committercbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-05 19:13:29 +0000
commitac3fa8e2ef53e83b113d726209525f4af4aa46f1 (patch)
treecf3550a3155d263943062b68ea5b205035d22182 /net/http/http_auth_sspi_win.cc
parent5502208efd91894a34ef43a38d348b7f9acb3770 (diff)
downloadchromium_src-ac3fa8e2ef53e83b113d726209525f4af4aa46f1.zip
chromium_src-ac3fa8e2ef53e83b113d726209525f4af4aa46f1.tar.gz
chromium_src-ac3fa8e2ef53e83b113d726209525f4af4aa46f1.tar.bz2
Add Single Sign On support to HTTP Authentication handlers.
Currently this is implemented on Windows for the NTLM and Negotiate schemes. This CL does not introduce the hooks to actually use Single Sign On in response to a 401/407 request - that will come in a later CL. This behavior is disabled for now as well. BUG=29862 TEST=Ran unittests, and Chrome against a server with authentication challenges. Review URL: http://codereview.chromium.org/555174 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@38227 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/http/http_auth_sspi_win.cc')
-rw-r--r--net/http/http_auth_sspi_win.cc215
1 files changed, 147 insertions, 68 deletions
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