123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- // 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/mock_sspi_library_win.h"
- #include <algorithm>
- #include <cstring>
- #include <memory>
- #include <string>
- #include "base/check_op.h"
- #include "base/memory/raw_ptr.h"
- #include "base/strings/string_util_win.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 {
- std::u16string source_principal;
- std::u16string 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 {
- raw_ptr<MockCredential> credential = nullptr;
- std::u16string 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(const wchar_t* package)
- : SSPILibrary(package) {}
- 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(
- LPWSTR pszPrincipal,
- unsigned long fCredentialUse,
- void* pvLogonId,
- void* pvAuthData,
- SEC_GET_KEY_FN pGetKeyFn,
- void* pvGetKeyArgument,
- PCredHandle phCredential,
- PTimeStamp ptsExpiry) {
- DCHECK(!SecIsValidHandle(phCredential));
- auto* credential = new MockCredential;
- credential->source_principal =
- pszPrincipal ? base::as_u16cstr(pszPrincipal) : u"<Default>";
- credential->package = base::as_u16cstr(package_name_.c_str());
- credential->has_explicit_credentials = !!pvAuthData;
- credential->StoreInHandle(phCredential);
- if (ptsExpiry) {
- ptsExpiry->LowPart = 0xBAA5B780;
- ptsExpiry->HighPart = 0x01D54E17;
- }
- active_credentials_.insert(*phCredential);
- return SEC_E_OK;
- }
- SECURITY_STATUS MockSSPILibrary::InitializeSecurityContext(
- PCredHandle phCredential,
- PCtxtHandle phContext,
- SEC_WCHAR* pszTargetName,
- unsigned long fContextReq,
- unsigned long Reserved1,
- unsigned long TargetDataRep,
- PSecBufferDesc pInput,
- unsigned long Reserved2,
- PCtxtHandle phNewContext,
- PSecBufferDesc pOutput,
- unsigned long* contextAttr,
- PTimeStamp ptsExpiry) {
- 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 = 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(
- PSecPkgInfoW* pkgInfo) {
- if (expected_package_queries_.empty()) {
- static SecPkgInfoW kDefaultPkgInfo{
- 0, 0, 0, kDefaultMaxTokenLength, nullptr, nullptr};
- *pkgInfo = &kDefaultPkgInfo;
- expected_freed_packages_.insert(&kDefaultPkgInfo);
- return SEC_E_OK;
- }
- PackageQuery package_query = expected_package_queries_.front();
- expected_package_queries_.pop_front();
- *pkgInfo = package_query.package_info;
- if (package_query.response_code == SEC_E_OK)
- expected_freed_packages_.insert(package_query.package_info);
- return package_query.response_code;
- }
- SECURITY_STATUS MockSSPILibrary::FreeCredentialsHandle(
- PCredHandle phCredential) {
- 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) {
- std::unique_ptr<MockContext> context{MockContext::FromHandle(phContext)};
- EXPECT_EQ(1u, active_contexts_.erase(*phContext));
- SecInvalidateHandle(phContext);
- return SEC_E_OK;
- }
- SECURITY_STATUS MockSSPILibrary::FreeContextBuffer(PVOID pvContextBuffer) {
- PSecPkgInfoW package_info = static_cast<PSecPkgInfoW>(pvContextBuffer);
- std::set<PSecPkgInfoW>::iterator it = expected_freed_packages_.find(
- package_info);
- EXPECT_TRUE(it != expected_freed_packages_.end());
- expected_freed_packages_.erase(it);
- return SEC_E_OK;
- }
- void MockSSPILibrary::ExpectQuerySecurityPackageInfo(
- SECURITY_STATUS response_code,
- PSecPkgInfoW package_info) {
- expected_package_queries_.emplace_back(
- PackageQuery{response_code, package_info});
- }
- } // namespace net
|