chromium/chrome/credential_provider/test/com_fakes.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/credential_provider/test/com_fakes.h"

#include <sddl.h>  // For ConvertSidToStringSid()

#include "base/check.h"
#include "chrome/credential_provider/gaiacp/gaia_credential.h"
#include "chrome/credential_provider/gaiacp/gaia_credential_other_user.h"
#include "chrome/credential_provider/gaiacp/os_user_manager.h"
#include "chrome/credential_provider/gaiacp/reauth_credential.h"
#include "chrome/credential_provider/gaiacp/stdafx.h"
#include "chrome/credential_provider/test/test_credential.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace credential_provider {

namespace testing {

// This class is used to implement a test credential based off a
// CGaiaCredential.
class ATL_NO_VTABLE CTestGaiaCredential
    : public CTestCredentialBase<CGaiaCredential> {
 public:
  DECLARE_NO_REGISTRY()

  CTestGaiaCredential();
  ~CTestGaiaCredential();

 private:
  BEGIN_COM_MAP(CTestGaiaCredential)
  COM_INTERFACE_ENTRY(IGaiaCredential)
  COM_INTERFACE_ENTRY(ICredentialProviderCredential)
  COM_INTERFACE_ENTRY(ITestCredential)
  END_COM_MAP()
};

CTestGaiaCredential::CTestGaiaCredential() = default;

CTestGaiaCredential::~CTestGaiaCredential() = default;

// This class is used to implement a test credential based off a
// COtherUserGaiaCredential.
class ATL_NO_VTABLE CTestOtherUserGaiaCredential
    : public CTestCredentialBase<COtherUserGaiaCredential> {
 public:
  DECLARE_NO_REGISTRY()

  CTestOtherUserGaiaCredential();
  ~CTestOtherUserGaiaCredential();

 private:
  BEGIN_COM_MAP(CTestOtherUserGaiaCredential)
  COM_INTERFACE_ENTRY(IGaiaCredential)
  COM_INTERFACE_ENTRY(ICredentialProviderCredential)
  COM_INTERFACE_ENTRY(ICredentialProviderCredential2)
  COM_INTERFACE_ENTRY(ITestCredential)
  END_COM_MAP()
};

CTestOtherUserGaiaCredential::CTestOtherUserGaiaCredential() = default;

CTestOtherUserGaiaCredential::~CTestOtherUserGaiaCredential() = default;

#define IMPL_IUNKOWN_NOQI_WITH_REF(cls)                               \
  IFACEMETHODIMP cls::QueryInterface(REFIID riid, void** ppv) {       \
    return E_NOTIMPL;                                                 \
  }                                                                   \
  ULONG cls::AddRef() { return ::InterlockedIncrement(&ref_count_); } \
  ULONG cls::Release(void) {                                          \
    DCHECK(ref_count_ > 0);                                           \
    return ::InterlockedDecrement(&ref_count_);                       \
  }

///////////////////////////////////////////////////////////////////////////////

FakeCredentialProviderUser::FakeCredentialProviderUser(const wchar_t* sid,
                                                       const wchar_t* username)
    : sid_(sid), username_(username) {}

FakeCredentialProviderUser::~FakeCredentialProviderUser() {
  EXPECT_EQ(ref_count_, 1u);
}

HRESULT FakeCredentialProviderUser::GetSid(wchar_t** sid) {
  DWORD length = sid_.length() + 1;
  *sid = static_cast<wchar_t*>(::CoTaskMemAlloc(length * sizeof(wchar_t)));
  EXPECT_EQ(0, wcscpy_s(*sid, length, sid_.c_str()));
  return S_OK;
}

HRESULT FakeCredentialProviderUser::GetProviderID(GUID* providerID) {
  return E_NOTIMPL;
}

HRESULT FakeCredentialProviderUser::GetStringValue(REFPROPERTYKEY key,
                                                   wchar_t** value) {
  if (key != PKEY_Identity_UserName)
    return E_INVALIDARG;

  DWORD length = username_.length() + 1;
  *value = static_cast<wchar_t*>(::CoTaskMemAlloc(length * sizeof(wchar_t)));
  EXPECT_EQ(0, wcscpy_s(*value, length, username_.c_str()));
  return S_OK;
}

HRESULT FakeCredentialProviderUser::GetValue(REFPROPERTYKEY key,
                                             PROPVARIANT* value) {
  return E_NOTIMPL;
}

IMPL_IUNKOWN_NOQI_WITH_REF(FakeCredentialProviderUser)

///////////////////////////////////////////////////////////////////////////////

FakeCredentialProviderUserArray::FakeCredentialProviderUserArray() {}

FakeCredentialProviderUserArray::~FakeCredentialProviderUserArray() {
  EXPECT_EQ(ref_count_, 1u);
}

HRESULT FakeCredentialProviderUserArray::SetProviderFilter(
    REFGUID guidProviderToFilterTo) {
  return S_OK;
}

HRESULT FakeCredentialProviderUserArray::GetAccountOptions(
    CREDENTIAL_PROVIDER_ACCOUNT_OPTIONS* cpao) {
  DCHECK(cpao);
  *cpao = cpao_;
  return S_OK;
}

HRESULT FakeCredentialProviderUserArray::GetCount(DWORD* count) {
  *count = users_.size();
  return S_OK;
}

HRESULT FakeCredentialProviderUserArray::GetAt(DWORD index,
                                               ICredentialProviderUser** user) {
  EXPECT_LT(index, users_.size());
  *user = &users_[index];
  (*user)->AddRef();
  return S_OK;
}

IMPL_IUNKOWN_NOQI_WITH_REF(FakeCredentialProviderUserArray)

///////////////////////////////////////////////////////////////////////////////

FakeCredentialProviderEvents::FakeCredentialProviderEvents() {}

FakeCredentialProviderEvents::~FakeCredentialProviderEvents() {
  EXPECT_EQ(ref_count_, 1u);
}

HRESULT FakeCredentialProviderEvents::CredentialsChanged(
    UINT_PTR upAdviseContext) {
  did_change_ = true;
  return S_OK;
}

IMPL_IUNKOWN_NOQI_WITH_REF(FakeCredentialProviderEvents)

///////////////////////////////////////////////////////////////////////////////

FakeCredentialProviderCredentialEvents::
    FakeCredentialProviderCredentialEvents() {}

FakeCredentialProviderCredentialEvents::
    ~FakeCredentialProviderCredentialEvents() {}

HRESULT FakeCredentialProviderCredentialEvents::AppendFieldComboBoxItem(
    ICredentialProviderCredential* pcpc,
    DWORD dwFieldID,
    LPCWSTR pszItem) {
  return S_OK;
}

HRESULT FakeCredentialProviderCredentialEvents::DeleteFieldComboBoxItem(
    ICredentialProviderCredential* pcpc,
    DWORD dwFieldID,
    DWORD dwItem) {
  return S_OK;
}

HRESULT FakeCredentialProviderCredentialEvents::OnCreatingWindow(
    HWND* phwndOwner) {
  return S_OK;
}

HRESULT FakeCredentialProviderCredentialEvents::SetFieldBitmap(
    ICredentialProviderCredential* pcpc,
    DWORD dwFieldID,
    HBITMAP hbmp) {
  return S_OK;
}

HRESULT FakeCredentialProviderCredentialEvents::SetFieldCheckbox(
    ICredentialProviderCredential* pcpc,
    DWORD dwFieldID,
    BOOL bChecked,
    LPCWSTR pszLabel) {
  return S_OK;
}

HRESULT FakeCredentialProviderCredentialEvents::SetFieldComboBoxSelectedItem(
    ICredentialProviderCredential* pcpc,
    DWORD dwFieldID,
    DWORD dwSelectedItem) {
  return S_OK;
}

HRESULT FakeCredentialProviderCredentialEvents::SetFieldInteractiveState(
    ICredentialProviderCredential* pcpc,
    DWORD dwFieldID,
    CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE cpfis) {
  return S_OK;
}

HRESULT FakeCredentialProviderCredentialEvents::SetFieldState(
    ICredentialProviderCredential* pcpc,
    DWORD dwFieldID,
    CREDENTIAL_PROVIDER_FIELD_STATE cpfs) {
  field_states_[pcpc][dwFieldID] = cpfs;
  return S_OK;
}

HRESULT FakeCredentialProviderCredentialEvents::SetFieldString(
    ICredentialProviderCredential* pcpc,
    DWORD dwFieldID,
    LPCWSTR psz) {
  if (psz != nullptr) {
    std::wstring copy_wchart(psz);
    field_string_[pcpc][dwFieldID] = copy_wchart;
  }
  return S_OK;
}

HRESULT FakeCredentialProviderCredentialEvents::SetFieldSubmitButton(
    ICredentialProviderCredential* pcpc,
    DWORD dwFieldID,
    DWORD dwAdjacentTo) {
  return S_OK;
}

CREDENTIAL_PROVIDER_FIELD_STATE
FakeCredentialProviderCredentialEvents::GetFieldState(
    ICredentialProviderCredential* pcpc,
    DWORD dwFieldID) {
  DCHECK(field_states_.count(pcpc));
  DCHECK(field_states_[pcpc].count(dwFieldID));

  return field_states_[pcpc][dwFieldID];
}

LPCWSTR FakeCredentialProviderCredentialEvents::GetFieldString(
    ICredentialProviderCredential* pcpc,
    DWORD dwFieldID) {
  DCHECK(field_string_.count(pcpc));
  DCHECK(field_string_[pcpc].count(dwFieldID));

  return field_string_[pcpc][dwFieldID].c_str();
}

IMPL_IUNKOWN_NOQI_WITH_REF(FakeCredentialProviderCredentialEvents)

///////////////////////////////////////////////////////////////////////////////

CTestGaiaCredentialProvider::CTestGaiaCredentialProvider() {
  // Set functions for creating test credentials of all types.
  SetCredentialCreatorFunctionsForTesting(
      [](CGaiaCredentialProvider::GaiaCredentialComPtrStorage*
             cred_ptr_storage) {
        return CComCreator<CComObject<CTestGaiaCredential>>::CreateInstance(
            nullptr, IID_PPV_ARGS(&cred_ptr_storage->gaia_cred));
      },
      [](CGaiaCredentialProvider::GaiaCredentialComPtrStorage*
             cred_ptr_storage) {
        return CComCreator<CComObject<CTestOtherUserGaiaCredential>>::
            CreateInstance(nullptr, IID_PPV_ARGS(&cred_ptr_storage->gaia_cred));
      },
      [](CGaiaCredentialProvider::GaiaCredentialComPtrStorage*
             cred_ptr_storage) {
        return CComCreator<CComObject<testing::CTestCredentialForInherited<
            CReauthCredential, IReauthCredential>>>::
            CreateInstance(nullptr, IID_PPV_ARGS(&cred_ptr_storage->gaia_cred));
      });
}

CTestGaiaCredentialProvider::~CTestGaiaCredentialProvider() {}

const CComBSTR& CTestGaiaCredentialProvider::username() const {
  return username_;
}

const CComBSTR& CTestGaiaCredentialProvider::password() const {
  return password_;
}

const CComBSTR& CTestGaiaCredentialProvider::sid() const {
  return sid_;
}

bool CTestGaiaCredentialProvider::credentials_changed_fired() const {
  return credentials_changed_fired_;
}

void CTestGaiaCredentialProvider::ResetCredentialsChangedFired() {
  credentials_changed_fired_ = FALSE;
}

HRESULT CTestGaiaCredentialProvider::OnUserAuthenticatedImpl(
    IUnknown* credential,
    BSTR username,
    BSTR password,
    BSTR sid,
    BOOL fire_credentials_changed) {
  username_ = username;
  password_ = password;
  sid_ = sid;
  credentials_changed_fired_ = fire_credentials_changed;
  return CGaiaCredentialProvider::OnUserAuthenticatedImpl(
      credential, username, password, sid, fire_credentials_changed);
}

}  // namespace testing

}  // namespace credential_provider