diff options
Diffstat (limited to 'chromium/net/http/mock_sspi_library_win.cc')
-rw-r--r-- | chromium/net/http/mock_sspi_library_win.cc | 206 |
1 files changed, 191 insertions, 15 deletions
diff --git a/chromium/net/http/mock_sspi_library_win.cc b/chromium/net/http/mock_sspi_library_win.cc index 1d3379cd278..95a3deb27f4 100644 --- a/chromium/net/http/mock_sspi_library_win.cc +++ b/chromium/net/http/mock_sspi_library_win.cc @@ -4,16 +4,108 @@ #include "net/http/mock_sspi_library_win.h" +#include <algorithm> +#include <cstring> +#include <memory> + +#include "base/logging.h" +#include "base/strings/string16.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "base/time/time.h" #include "testing/gtest/include/gtest/gtest.h" +// Comparator so we can use CredHandle and CtxtHandle with std::set. Both of +// those classes are typedefs for _SecHandle. +bool operator<(const _SecHandle left, const _SecHandle right) { + return left.dwUpper < right.dwUpper || left.dwLower < right.dwLower; +} + namespace net { +namespace { + +int uniquifier_ = 0; + +struct MockCredential { + base::string16 source_principal; + base::string16 package; + bool has_explicit_credentials = false; + int uniquifier = ++uniquifier_; + + // CredHandle and CtxtHandle both shared the following definition: + // + // typedef struct _SecHandle { + // ULONG_PTR dwLower; + // ULONG_PTR dwUpper; + // } SecHandle, * PSecHandle; + // + // ULONG_PTR type can hold a pointer. This function stuffs |this| into dwUpper + // and adds a uniquifier to dwLower. This ensures that all PCredHandles issued + // by this method during the lifetime of this process is unique. + void StoreInHandle(PCredHandle handle) { + DCHECK(uniquifier > 0); + EXPECT_FALSE(SecIsValidHandle(handle)); + + handle->dwLower = uniquifier; + handle->dwUpper = reinterpret_cast<ULONG_PTR>(this); + + DCHECK(SecIsValidHandle(handle)); + } + + static MockCredential* FromHandle(PCredHandle handle) { + return reinterpret_cast<MockCredential*>(handle->dwUpper); + } +}; + +struct MockContext { + MockCredential* credential = nullptr; + base::string16 target_principal; + int uniquifier = ++uniquifier_; + int rounds = 0; + + // CredHandle and CtxtHandle both shared the following definition: + // + // typedef struct _SecHandle { + // ULONG_PTR dwLower; + // ULONG_PTR dwUpper; + // } SecHandle, * PSecHandle; + // + // ULONG_PTR type can hold a pointer. This function stuffs |this| into dwUpper + // and adds a uniquifier to dwLower. This ensures that all PCredHandles issued + // by this method during the lifetime of this process is unique. + void StoreInHandle(PCtxtHandle handle) { + EXPECT_FALSE(SecIsValidHandle(handle)); + DCHECK(uniquifier > 0); + + handle->dwLower = uniquifier; + handle->dwUpper = reinterpret_cast<ULONG_PTR>(this); + + DCHECK(SecIsValidHandle(handle)); + } + + std::string ToString() const { + return base::StringPrintf( + "%s's token #%d for %S", + base::UTF16ToUTF8(credential->source_principal).c_str(), rounds + 1, + base::as_wcstr(target_principal)); + } + + static MockContext* FromHandle(PCtxtHandle handle) { + return reinterpret_cast<MockContext*>(handle->dwUpper); + } +}; + +} // namespace + MockSSPILibrary::MockSSPILibrary() { } MockSSPILibrary::~MockSSPILibrary() { EXPECT_TRUE(expected_package_queries_.empty()); EXPECT_TRUE(expected_freed_packages_.empty()); + EXPECT_TRUE(active_credentials_.empty()); + EXPECT_TRUE(active_contexts_.empty()); } SECURITY_STATUS MockSSPILibrary::AcquireCredentialsHandle( @@ -26,8 +118,21 @@ SECURITY_STATUS MockSSPILibrary::AcquireCredentialsHandle( void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry) { - // Fill in phCredential with arbitrary value. - phCredential->dwLower = phCredential->dwUpper = ((ULONG_PTR) ((INT_PTR)0)); + DCHECK(!SecIsValidHandle(phCredential)); + auto* credential = new MockCredential; + credential->source_principal = pszPrincipal ? base::as_u16cstr(pszPrincipal) + : STRING16_LITERAL("<Default>"); + credential->package = base::as_u16cstr(pszPackage); + credential->has_explicit_credentials = !!pvAuthData; + + credential->StoreInHandle(phCredential); + + if (ptsExpiry) { + ptsExpiry->LowPart = 0xBAA5B780; + ptsExpiry->HighPart = 0x01D54E17; + } + + active_credentials_.insert(*phCredential); return SEC_E_OK; } @@ -44,19 +149,88 @@ SECURITY_STATUS MockSSPILibrary::InitializeSecurityContext( PSecBufferDesc pOutput, unsigned long* contextAttr, PTimeStamp ptsExpiry) { - // Fill in the outbound buffer with garbage data. + MockContext* new_context = new MockContext; + new_context->credential = MockCredential::FromHandle(phCredential); + new_context->target_principal = base::as_u16cstr(pszTargetName); + new_context->rounds = 0; + + // Always rotate contexts. That way tests will fail if the caller's context + // management is broken. + if (phContext && SecIsValidHandle(phContext)) { + std::unique_ptr<MockContext> old_context{ + MockContext::FromHandle(phContext)}; + EXPECT_EQ(old_context->credential, new_context->credential); + EXPECT_EQ(1u, active_contexts_.erase(*phContext)); + + new_context->rounds = old_context->rounds + 1; + SecInvalidateHandle(phContext); + } + + new_context->StoreInHandle(phNewContext); + active_contexts_.insert(*phNewContext); + + auto token = new_context->ToString(); PSecBuffer out_buffer = pOutput->pBuffers; - out_buffer->cbBuffer = 2; - uint8_t* buf = reinterpret_cast<uint8_t*>(out_buffer->pvBuffer); - buf[0] = 0xAB; - buf[1] = 0xBA; - - // Fill in phNewContext with arbitrary value if it's invalid. - if (phNewContext != phContext) - phNewContext->dwLower = phNewContext->dwUpper = ((ULONG_PTR) ((INT_PTR)0)); + out_buffer->cbBuffer = std::min<ULONG>(out_buffer->cbBuffer, token.size()); + std::memcpy(out_buffer->pvBuffer, token.data(), out_buffer->cbBuffer); + + if (ptsExpiry) { + ptsExpiry->LowPart = 0xBAA5B780; + ptsExpiry->HighPart = 0x01D54E15; + } return SEC_E_OK; } +SECURITY_STATUS MockSSPILibrary::QueryContextAttributesEx(PCtxtHandle phContext, + ULONG ulAttribute, + PVOID pBuffer, + ULONG cbBuffer) { + static const SecPkgInfoW kNegotiatedPackage = { + 0, + 0, + 0, + 0, + const_cast<SEC_WCHAR*>(L"Itsa me Kerberos!!"), + const_cast<SEC_WCHAR*>(L"I like turtles")}; + + auto* context = MockContext::FromHandle(phContext); + + switch (ulAttribute) { + case SECPKG_ATTR_NATIVE_NAMES: { + auto* native_names = + reinterpret_cast<SecPkgContext_NativeNames*>(pBuffer); + DCHECK_EQ(sizeof(*native_names), cbBuffer); + native_names->sClientName = + base::as_writable_wcstr(context->credential->source_principal); + native_names->sServerName = + base::as_writable_wcstr(context->target_principal); + return SEC_E_OK; + } + + case SECPKG_ATTR_NEGOTIATION_INFO: { + auto* negotiation_info = + reinterpret_cast<SecPkgContext_NegotiationInfo*>(pBuffer); + DCHECK_EQ(sizeof(*negotiation_info), cbBuffer); + negotiation_info->PackageInfo = + const_cast<SecPkgInfoW*>(&kNegotiatedPackage); + negotiation_info->NegotiationState = (context->rounds == 1) + ? SECPKG_NEGOTIATION_COMPLETE + : SECPKG_NEGOTIATION_IN_PROGRESS; + return SEC_E_OK; + } + + case SECPKG_ATTR_AUTHORITY: { + auto* authority = reinterpret_cast<SecPkgContext_Authority*>(pBuffer); + DCHECK_EQ(sizeof(*authority), cbBuffer); + authority->sAuthorityName = const_cast<SEC_WCHAR*>(L"Dodgy Server"); + return SEC_E_OK; + } + + default: + return SEC_E_UNSUPPORTED_FUNCTION; + } +} + SECURITY_STATUS MockSSPILibrary::QuerySecurityPackageInfo( LPWSTR pszPackageName, PSecPkgInfoW *pkgInfo) { EXPECT_TRUE(!expected_package_queries_.empty()); @@ -72,15 +246,17 @@ SECURITY_STATUS MockSSPILibrary::QuerySecurityPackageInfo( SECURITY_STATUS MockSSPILibrary::FreeCredentialsHandle( PCredHandle phCredential) { - EXPECT_TRUE(phCredential->dwLower == ((ULONG_PTR) ((INT_PTR) 0))); - EXPECT_TRUE(phCredential->dwUpper == ((ULONG_PTR) ((INT_PTR) 0))); + DCHECK(SecIsValidHandle(phCredential)); + EXPECT_EQ(1u, active_credentials_.erase(*phCredential)); + std::unique_ptr<MockCredential> owned{ + MockCredential::FromHandle(phCredential)}; SecInvalidateHandle(phCredential); return SEC_E_OK; } SECURITY_STATUS MockSSPILibrary::DeleteSecurityContext(PCtxtHandle phContext) { - EXPECT_TRUE(phContext->dwLower == ((ULONG_PTR) ((INT_PTR) 0))); - EXPECT_TRUE(phContext->dwUpper == ((ULONG_PTR) ((INT_PTR) 0))); + std::unique_ptr<MockContext> context{MockContext::FromHandle(phContext)}; + EXPECT_EQ(1u, active_contexts_.erase(*phContext)); SecInvalidateHandle(phContext); return SEC_E_OK; } |