summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorcbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-21 21:38:05 +0000
committercbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-21 21:38:05 +0000
commit4fd4a6da1114c4df949d0bf0281b4ecbfbb73534 (patch)
tree0367c2b9f0a2f7f22185fbc69f2df6ccbee5f6e9 /net
parent7106ae5055a009e1ca53f0fc5ee6bb6b0c925c9f (diff)
downloadchromium_src-4fd4a6da1114c4df949d0bf0281b4ecbfbb73534.zip
chromium_src-4fd4a6da1114c4df949d0bf0281b4ecbfbb73534.tar.gz
chromium_src-4fd4a6da1114c4df949d0bf0281b4ecbfbb73534.tar.bz2
Added WWW-Authenticate Negotate support using shared HttpAuthSspi.
BUG=29862 TEST=None Review URL: http://codereview.chromium.org/551015 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36785 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/http/http_auth.cc3
-rw-r--r--net/http/http_auth_handler_negotiate.h53
-rwxr-xr-xnet/http/http_auth_handler_negotiate_posix.cc45
-rw-r--r--net/http/http_auth_handler_negotiate_win.cc57
-rwxr-xr-x[-rw-r--r--]net/http/http_auth_handler_ntlm.cc20
-rw-r--r--net/http/http_auth_handler_ntlm.h9
-rw-r--r--net/http/http_auth_handler_ntlm_win.cc121
-rw-r--r--[-rwxr-xr-x]net/http/http_auth_sspi_win.cc209
-rwxr-xr-xnet/http/http_auth_sspi_win.h47
-rw-r--r--[-rwxr-xr-x]net/http/http_auth_sspi_win_unittest.cc0
-rwxr-xr-x[-rw-r--r--]net/net.gyp3
11 files changed, 441 insertions, 126 deletions
diff --git a/net/http/http_auth.cc b/net/http/http_auth.cc
index ba9b1ea..aa97640 100644
--- a/net/http/http_auth.cc
+++ b/net/http/http_auth.cc
@@ -10,6 +10,7 @@
#include "base/string_util.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"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
@@ -67,6 +68,8 @@ void HttpAuth::CreateAuthHandler(const std::string& challenge,
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();
}
diff --git a/net/http/http_auth_handler_negotiate.h b/net/http/http_auth_handler_negotiate.h
new file mode 100644
index 0000000..eb4d11f
--- /dev/null
+++ b/net/http/http_auth_handler_negotiate.h
@@ -0,0 +1,53 @@
+// 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_NEGOTIATE_H_
+#define NET_HTTP_HTTP_AUTH_HANDLER_NEGOTIATE_H_
+
+#include "build/build_config.h"
+
+#include <string>
+
+#include "net/http/http_auth_handler.h"
+
+#if defined(OS_WIN)
+#include "net/http/http_auth_sspi_win.h"
+#endif
+
+namespace net {
+
+// Handler for WWW-Authenticate: Negotiate protocol.
+//
+// See http://tools.ietf.org/html/rfc4178 and http://tools.ietf.org/html/rfc4559
+// for more information about the protocol.
+
+class HttpAuthHandlerNegotiate : public HttpAuthHandler {
+ public:
+ HttpAuthHandlerNegotiate();
+
+ virtual bool NeedsIdentity();
+
+ virtual bool IsFinalRound();
+
+ virtual std::string GenerateCredentials(const std::wstring& username,
+ const std::wstring& password,
+ const HttpRequestInfo* request,
+ const ProxyInfo* proxy);
+
+
+ protected:
+ virtual bool Init(std::string::const_iterator challenge_begin,
+ std::string::const_iterator challenge_end);
+
+ private:
+ ~HttpAuthHandlerNegotiate();
+
+#if defined(OS_WIN)
+ HttpAuthSSPI auth_sspi_;
+#endif
+};
+
+} // namespace net
+
+#endif // NET_HTTP_HTTP_AUTH_HANDLER_NEGOTIATE_H_
diff --git a/net/http/http_auth_handler_negotiate_posix.cc b/net/http/http_auth_handler_negotiate_posix.cc
new file mode 100755
index 0000000..169689d
--- /dev/null
+++ b/net/http/http_auth_handler_negotiate_posix.cc
@@ -0,0 +1,45 @@
+// 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"
+
+#include "base/logging.h"
+
+namespace net {
+
+// TODO(cbentzel): Negotiate authentication protocol is not supported on Posix
+// systems currently. These stubs make the main HTTP Authentication code bypass
+// Negotiate without requiring conditional compilation.
+
+HttpAuthHandlerNegotiate::HttpAuthHandlerNegotiate() {
+}
+
+HttpAuthHandlerNegotiate::~HttpAuthHandlerNegotiate() {
+}
+
+bool HttpAuthHandlerNegotiate::NeedsIdentity() {
+ NOTREACHED();
+ return false;
+}
+
+bool HttpAuthHandlerNegotiate::IsFinalRound() {
+ NOTREACHED();
+ return false;
+}
+
+bool HttpAuthHandlerNegotiate::Init(std::string::const_iterator challenge_begin,
+ std::string::const_iterator challenge_end) {
+ return false;
+}
+
+std::string HttpAuthHandlerNegotiate::GenerateCredentials(
+ const std::wstring& username,
+ const std::wstring& password,
+ const HttpRequestInfo* request,
+ const ProxyInfo* proxy) {
+ NOTREACHED();
+ return std::string();
+}
+
+} // namespace net
diff --git a/net/http/http_auth_handler_negotiate_win.cc b/net/http/http_auth_handler_negotiate_win.cc
new file mode 100644
index 0000000..782cb5c
--- /dev/null
+++ b/net/http/http_auth_handler_negotiate_win.cc
@@ -0,0 +1,57 @@
+// 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"
+
+#include "net/base/net_errors.h"
+
+namespace net {
+
+HttpAuthHandlerNegotiate::HttpAuthHandlerNegotiate() :
+ auth_sspi_("Negotiate", NEGOSSP_NAME) {
+}
+
+HttpAuthHandlerNegotiate::~HttpAuthHandlerNegotiate() {
+}
+
+std::string HttpAuthHandlerNegotiate::GenerateCredentials(
+ 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,
+ origin_,
+ request,
+ proxy,
+ &auth_credentials);
+ if (rv == OK)
+ return auth_credentials;
+ return std::string();
+}
+
+// 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) {
+ scheme_ = "negotiate";
+ score_ = 4;
+ properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED;
+ return auth_sspi_.ParseChallenge(challenge_begin, challenge_end);
+}
+
+// Require identity on first pass instead of second.
+bool HttpAuthHandlerNegotiate::NeedsIdentity() {
+ return auth_sspi_.NeedsIdentity();
+}
+
+bool HttpAuthHandlerNegotiate::IsFinalRound() {
+ return auth_sspi_.IsFinalRound();
+}
+
+} // namespace net
diff --git a/net/http/http_auth_handler_ntlm.cc b/net/http/http_auth_handler_ntlm.cc
index 3dcf9b4..6e10e79 100644..100755
--- a/net/http/http_auth_handler_ntlm.cc
+++ b/net/http/http_auth_handler_ntlm.cc
@@ -15,6 +15,20 @@ std::string HttpAuthHandlerNTLM::GenerateCredentials(
const std::wstring& password,
const HttpRequestInfo* request,
const ProxyInfo* proxy) {
+#if defined(NTLM_SSPI)
+ std::string auth_credentials;
+
+ int rv = auth_sspi_.GenerateCredentials(
+ username,
+ password,
+ origin_,
+ request,
+ proxy,
+ &auth_credentials);
+ if (rv == OK)
+ return auth_credentials;
+ return std::string();
+#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,
// GenerateType1Msg, and GenerateType3Msg, and perhaps further.
@@ -76,6 +90,7 @@ std::string HttpAuthHandlerNTLM::GenerateCredentials(
if (!ok)
return std::string();
return std::string("NTLM ") + encode_output;
+#endif
}
// The NTLM challenge header looks like:
@@ -86,6 +101,10 @@ bool HttpAuthHandlerNTLM::ParseChallenge(
scheme_ = "ntlm";
score_ = 3;
properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED;
+
+#if defined(NTLM_SSPI)
+ return auth_sspi_.ParseChallenge(challenge_begin, challenge_end);
+#else
auth_data_.clear();
// Verify the challenge's auth-scheme.
@@ -103,6 +122,7 @@ bool HttpAuthHandlerNTLM::ParseChallenge(
auth_data_.assign(challenge_begin, challenge_end);
return true;
+#endif
}
} // namespace net
diff --git a/net/http/http_auth_handler_ntlm.h b/net/http/http_auth_handler_ntlm.h
index ca2b234..c3bda62 100644
--- a/net/http/http_auth_handler_ntlm.h
+++ b/net/http/http_auth_handler_ntlm.h
@@ -19,6 +19,7 @@
#define SECURITY_WIN32 1
#include <windows.h>
#include <security.h>
+#include "net/http/http_auth_sspi_win.h"
#endif
#include <string>
@@ -105,7 +106,7 @@ class HttpAuthHandlerNTLM : public HttpAuthHandler {
uint32* out_token_len);
#if defined(NTLM_SSPI)
- void ResetSecurityContext();
+ HttpAuthSSPI auth_sspi_;
#endif
#if defined(NTLM_PORTABLE)
@@ -120,12 +121,6 @@ class HttpAuthHandlerNTLM : public HttpAuthHandler {
// The base64-encoded string following "NTLM" in the "WWW-Authenticate" or
// "Proxy-Authenticate" response header.
std::string auth_data_;
-
-#if defined(NTLM_SSPI)
- ULONG max_token_len_;
- CredHandle cred_;
- CtxtHandle ctxt_;
-#endif
};
} // namespace net
diff --git a/net/http/http_auth_handler_ntlm_win.cc b/net/http/http_auth_handler_ntlm_win.cc
index 0f40236..fba9c1b 100644
--- a/net/http/http_auth_handler_ntlm_win.cc
+++ b/net/http/http_auth_handler_ntlm_win.cc
@@ -17,138 +17,23 @@
#pragma comment(lib, "secur32.lib")
-namespace {
-
-void ZapString(string16* s) {
- memset(&(*s)[0], 0, s->length() * 2);
-}
-
-} // namespace
-
namespace net {
-HttpAuthHandlerNTLM::HttpAuthHandlerNTLM() : max_token_len_(0) {
- SecInvalidateHandle(&cred_);
- SecInvalidateHandle(&ctxt_);
+HttpAuthHandlerNTLM::HttpAuthHandlerNTLM() : auth_sspi_("NTLM", NTLMSP_NAME) {
}
HttpAuthHandlerNTLM::~HttpAuthHandlerNTLM() {
- ResetSecurityContext();
- if (SecIsValidHandle(&cred_)) {
- FreeCredentialsHandle(&cred_);
- SecInvalidateHandle(&cred_);
- }
- ZapString(&password_);
-}
-
-int HttpAuthHandlerNTLM::InitializeBeforeFirstChallenge() {
- DCHECK_EQ("ntlm", scheme_) << "This is not ntlm scheme";
-
- int rv = DetermineMaxTokenLength(NTLMSP_NAME, &max_token_len_);
- if (rv != OK) {
- return rv;
- }
- rv = AcquireCredentials(NTLMSP_NAME, domain_, username_, password_, &cred_);
- return rv;
-}
-
-int HttpAuthHandlerNTLM::GetNextToken(const void* in_token,
- uint32 in_token_len,
- void** out_token,
- uint32* out_token_len) {
- SECURITY_STATUS status;
- TimeStamp expiry;
-
- DWORD ctxt_attr;
- CtxtHandle* ctxt_ptr;
- SecBufferDesc in_buffer_desc, out_buffer_desc;
- SecBufferDesc* in_buffer_desc_ptr;
- SecBuffer in_buffer, out_buffer;
-
- if (in_token) {
- // Prepare input buffer.
- in_buffer_desc.ulVersion = SECBUFFER_VERSION;
- in_buffer_desc.cBuffers = 1;
- in_buffer_desc.pBuffers = &in_buffer;
- in_buffer.BufferType = SECBUFFER_TOKEN;
- in_buffer.cbBuffer = in_token_len;
- in_buffer.pvBuffer = const_cast<void*>(in_token);
- ctxt_ptr = &ctxt_;
- in_buffer_desc_ptr = &in_buffer_desc;
- } else {
- // If there is no input token, then we are starting a new authentication
- // sequence. If we have already initialized our security context, then
- // we're incorrectly reusing the auth handler for a new sequence.
- if (SecIsValidHandle(&ctxt_)) {
- LOG(ERROR) << "Cannot restart authentication sequence";
- return ERR_UNEXPECTED;
- }
- ctxt_ptr = NULL;
- in_buffer_desc_ptr = NULL;
- }
-
- // Prepare output buffer.
- out_buffer_desc.ulVersion = SECBUFFER_VERSION;
- out_buffer_desc.cBuffers = 1;
- out_buffer_desc.pBuffers = &out_buffer;
- out_buffer.BufferType = SECBUFFER_TOKEN;
- out_buffer.cbBuffer = max_token_len_;
- out_buffer.pvBuffer = malloc(out_buffer.cbBuffer);
- if (!out_buffer.pvBuffer)
- return ERR_OUT_OF_MEMORY;
-
- // The service principal name of the destination server. See
- // http://msdn.microsoft.com/en-us/library/ms677949%28VS.85%29.aspx
- std::wstring target(L"HTTP/");
- target.append(ASCIIToWide(GetHostAndPort(origin_)));
- wchar_t* target_name = const_cast<wchar_t*>(target.c_str());
-
- // This returns a token that is passed to the remote server.
- status = InitializeSecurityContext(&cred_, // phCredential
- ctxt_ptr, // phContext
- target_name, // pszTargetName
- 0, // fContextReq
- 0, // Reserved1 (must be 0)
- SECURITY_NATIVE_DREP, // TargetDataRep
- in_buffer_desc_ptr, // pInput
- 0, // Reserved2 (must be 0)
- &ctxt_, // phNewContext
- &out_buffer_desc, // pOutput
- &ctxt_attr, // pfContextAttr
- &expiry); // ptsExpiry
- // On success, the function returns SEC_I_CONTINUE_NEEDED on the first call
- // 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;
- ResetSecurityContext();
- free(out_buffer.pvBuffer);
- return ERR_UNEXPECTED; // TODO(wtc): map error code.
- }
- if (!out_buffer.cbBuffer) {
- free(out_buffer.pvBuffer);
- out_buffer.pvBuffer = NULL;
- }
- *out_token = out_buffer.pvBuffer;
- *out_token_len = out_buffer.cbBuffer;
- return OK;
}
// Require identity on first pass instead of second.
bool HttpAuthHandlerNTLM::NeedsIdentity() {
- return auth_data_.empty();
+ return auth_sspi_.NeedsIdentity();
}
bool HttpAuthHandlerNTLM::IsFinalRound() {
- return !auth_data_.empty();
+ return auth_sspi_.IsFinalRound();
}
-void HttpAuthHandlerNTLM::ResetSecurityContext() {
- if (SecIsValidHandle(&ctxt_)) {
- DeleteSecurityContext(&ctxt_);
- SecInvalidateHandle(&ctxt_);
- }
-}
} // namespace net
diff --git a/net/http/http_auth_sspi_win.cc b/net/http/http_auth_sspi_win.cc
index ff3ec82..00861e5 100755..100644
--- a/net/http/http_auth_sspi_win.cc
+++ b/net/http/http_auth_sspi_win.cc
@@ -2,13 +2,222 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// See "SSPI Sample Application" at
+// http://msdn.microsoft.com/en-us/library/aa918273.aspx
+
#include "net/http/http_auth_sspi_win.h"
+#include "base/base64.h"
#include "base/logging.h"
+#include "base/string_util.h"
#include "net/base/net_errors.h"
+#include "net/base/net_util.h"
+#include "net/http/http_auth.h"
namespace net {
+HttpAuthSSPI::HttpAuthSSPI(const std::string& scheme,
+ SEC_WCHAR* security_package)
+ : scheme_(scheme),
+ security_package_(security_package),
+ max_token_length_(0) {
+ SecInvalidateHandle(&cred_);
+ SecInvalidateHandle(&ctxt_);
+}
+
+HttpAuthSSPI::~HttpAuthSSPI() {
+ ResetSecurityContext();
+ if (SecIsValidHandle(&cred_)) {
+ FreeCredentialsHandle(&cred_);
+ SecInvalidateHandle(&cred_);
+ }
+}
+
+bool HttpAuthSSPI::NeedsIdentity() const {
+ return decoded_server_auth_token_.empty();
+}
+
+bool HttpAuthSSPI::IsFinalRound() const {
+ return !decoded_server_auth_token_.empty();
+}
+
+void HttpAuthSSPI::ResetSecurityContext() {
+ if (SecIsValidHandle(&ctxt_)) {
+ DeleteSecurityContext(&ctxt_);
+ SecInvalidateHandle(&ctxt_);
+ }
+}
+
+bool HttpAuthSSPI::ParseChallenge(std::string::const_iterator challenge_begin,
+ std::string::const_iterator challenge_end) {
+ // 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()))
+ 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);
+
+ std::string decoded_auth_token;
+ bool rv = base::Base64Decode(encoded_auth_token, &decoded_auth_token);
+ if (rv) {
+ decoded_server_auth_token_ = decoded_auth_token;
+ }
+ return rv;
+}
+
+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);
+
+ // Initial challenge.
+ if (!IsFinalRound()) {
+ int rv = OnFirstRound(domain, user, password);
+ if (rv != OK)
+ return rv;
+ }
+
+ void* out_buf;
+ int out_buf_len;
+ int rv = GetNextSecurityToken(
+ origin,
+ static_cast<void *>(const_cast<char *>(
+ decoded_server_auth_token_.c_str())),
+ decoded_server_auth_token_.length(),
+ &out_buf,
+ &out_buf_len);
+ if (rv != OK)
+ return rv;
+
+ // 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);
+ // OK, we are done with |out_buf|
+ free(out_buf);
+ if (!ok)
+ return rv;
+ *out_credentials = scheme_ + " " + encode_output;
+ return OK;
+}
+
+int HttpAuthSSPI::OnFirstRound(const std::wstring& domain,
+ const std::wstring& user,
+ const std::wstring& password) {
+ int rv = DetermineMaxTokenLength(security_package_, &max_token_length_);
+ if (rv != OK) {
+ return rv;
+ }
+ rv = AcquireCredentials(security_package_, domain, user, password, &cred_);
+ return rv;
+}
+
+int HttpAuthSSPI::GetNextSecurityToken(
+ const GURL& origin,
+ const void * in_token,
+ int in_token_len,
+ void** out_token,
+ int* out_token_len) {
+ SECURITY_STATUS status;
+ TimeStamp expiry;
+
+ DWORD ctxt_attr;
+ CtxtHandle* ctxt_ptr;
+ SecBufferDesc in_buffer_desc, out_buffer_desc;
+ SecBufferDesc* in_buffer_desc_ptr;
+ SecBuffer in_buffer, out_buffer;
+
+ if (in_token_len > 0) {
+ // Prepare input buffer.
+ in_buffer_desc.ulVersion = SECBUFFER_VERSION;
+ in_buffer_desc.cBuffers = 1;
+ in_buffer_desc.pBuffers = &in_buffer;
+ in_buffer.BufferType = SECBUFFER_TOKEN;
+ in_buffer.cbBuffer = in_token_len;
+ in_buffer.pvBuffer = const_cast<void*>(in_token);
+ ctxt_ptr = &ctxt_;
+ in_buffer_desc_ptr = &in_buffer_desc;
+ } else {
+ // If there is no input token, then we are starting a new authentication
+ // sequence. If we have already initialized our security context, then
+ // we're incorrectly reusing the auth handler for a new sequence.
+ if (SecIsValidHandle(&ctxt_)) {
+ LOG(ERROR) << "Cannot restart authentication sequence";
+ return ERR_UNEXPECTED;
+ }
+ ctxt_ptr = NULL;
+ in_buffer_desc_ptr = NULL;
+ }
+
+ // Prepare output buffer.
+ out_buffer_desc.ulVersion = SECBUFFER_VERSION;
+ out_buffer_desc.cBuffers = 1;
+ out_buffer_desc.pBuffers = &out_buffer;
+ out_buffer.BufferType = SECBUFFER_TOKEN;
+ out_buffer.cbBuffer = max_token_length_;
+ out_buffer.pvBuffer = malloc(out_buffer.cbBuffer);
+ if (!out_buffer.pvBuffer)
+ return ERR_OUT_OF_MEMORY;
+
+ // The service principal name of the destination server. See
+ // http://msdn.microsoft.com/en-us/library/ms677949%28VS.85%29.aspx
+ std::wstring target(L"HTTP/");
+ target.append(ASCIIToWide(GetHostAndPort(origin)));
+ wchar_t* target_name = const_cast<wchar_t*>(target.c_str());
+
+ // This returns a token that is passed to the remote server.
+ status = InitializeSecurityContext(&cred_, // phCredential
+ ctxt_ptr, // phContext
+ target_name, // pszTargetName
+ 0, // fContextReq
+ 0, // Reserved1 (must be 0)
+ SECURITY_NATIVE_DREP, // TargetDataRep
+ in_buffer_desc_ptr, // pInput
+ 0, // Reserved2 (must be 0)
+ &ctxt_, // phNewContext
+ &out_buffer_desc, // pOutput
+ &ctxt_attr, // pfContextAttr
+ &expiry); // ptsExpiry
+ // On success, the function returns SEC_I_CONTINUE_NEEDED on the first call
+ // 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;
+ ResetSecurityContext();
+ free(out_buffer.pvBuffer);
+ return ERR_UNEXPECTED; // TODO(wtc): map error code.
+ }
+ if (!out_buffer.cbBuffer) {
+ free(out_buffer.pvBuffer);
+ out_buffer.pvBuffer = NULL;
+ }
+ *out_token = out_buffer.pvBuffer;
+ *out_token_len = out_buffer.cbBuffer;
+ return OK;
+}
+
void SplitDomainAndUser(const std::wstring& combined,
std::wstring* domain,
std::wstring* user) {
diff --git a/net/http/http_auth_sspi_win.h b/net/http/http_auth_sspi_win.h
index d58678b..4d340aa 100755
--- a/net/http/http_auth_sspi_win.h
+++ b/net/http/http_auth_sspi_win.h
@@ -16,8 +16,53 @@
#include <string>
+class GURL;
+
namespace net {
+class HttpRequestInfo;
+class ProxyInfo;
+
+class HttpAuthSSPI {
+ public:
+ HttpAuthSSPI(const std::string& scheme,
+ SEC_WCHAR* security_package);
+ ~HttpAuthSSPI();
+
+ bool NeedsIdentity() const;
+ bool IsFinalRound() const;
+
+ 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);
+
+ private:
+ int OnFirstRound(const std::wstring& domain,
+ const std::wstring& user,
+ const std::wstring& password);
+
+ int GetNextSecurityToken(
+ const GURL& origin,
+ const void* in_token,
+ int in_token_len,
+ void** out_token,
+ int* out_token_len);
+
+ void ResetSecurityContext();
+ std::string scheme_;
+ SEC_WCHAR* security_package_;
+ std::string decoded_server_auth_token_;
+ ULONG max_token_length_;
+ CredHandle cred_;
+ CtxtHandle ctxt_;
+};
+
// Splits |combined| into domain and username.
// If |combined| is of form "FOO\bar", |domain| will contain "FOO" and |user|
// will contain "bar".
@@ -41,7 +86,7 @@ int AcquireCredentials(const SEC_WCHAR* package,
const std::wstring& user,
const std::wstring& password,
CredHandle* cred);
-} // namespace net
+} // namespace net
#endif // NET_HTTP_HTTP_AUTH_SSPI_WIN_H_
diff --git a/net/http/http_auth_sspi_win_unittest.cc b/net/http/http_auth_sspi_win_unittest.cc
index b421ca9..b421ca9 100755..100644
--- a/net/http/http_auth_sspi_win_unittest.cc
+++ b/net/http/http_auth_sspi_win_unittest.cc
diff --git a/net/net.gyp b/net/net.gyp
index 3812e11..f16ebab 100644..100755
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -336,6 +336,9 @@
'http/http_auth_handler_basic.h',
'http/http_auth_handler_digest.cc',
'http/http_auth_handler_digest.h',
+ 'http/http_auth_handler_negotiate.h',
+ 'http/http_auth_handler_negotiate_posix.cc',
+ 'http/http_auth_handler_negotiate_win.cc',
'http/http_auth_handler_ntlm.cc',
'http/http_auth_handler_ntlm.h',
'http/http_auth_handler_ntlm_portable.cc',