// 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 "gls_runner_test_base.h"
#include <memory>
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/json/json_writer.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/multiprocess_test.h"
#include "chrome/credential_provider/gaiacp/gaia_credential_provider_filter.h"
#include "chrome/credential_provider/gaiacp/scoped_lsa_policy.h"
#include "chrome/credential_provider/test/test_credential.h"
#include "testing/multiprocess_func_list.h"
namespace credential_provider {
namespace switches {
constexpr char kDefaultExitCode[] = "default-exit-code";
constexpr char kIgnoreExpectedGaiaId[] = "ignore-expected-gaia-id";
constexpr char kGlsUserEmail[] = "gls-user-email";
constexpr char kStartGlsEventName[] = "start-gls-event-name";
constexpr char kOverrideGaiaId[] = "override-gaia-id";
constexpr char kOverrideGaiaPassword[] = "override-gaia-password";
constexpr char kOverrideFullName[] = "override-full-name";
} // namespace switches
namespace testing {
// Corresponding default email and username for tests that don't override them.
const char kDefaultEmail[] = "[email protected]";
const char kDefaultGaiaId[] = "test-gaia-id";
const wchar_t kDefaultUsername[] = L"foo";
const char kDefaultInvalidTokenHandleResponse[] = "{}";
const char kDefaultValidTokenHandleResponse[] = "{\"expires_in\":1}";
namespace {
// Generates a common signin result given an email pass through the command
// line and writes this result to stdout. This is used as a fake GLS process
// for testing.
MULTIPROCESS_TEST_MAIN(gls_main) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
// If a start event name is specified, the process waits for an event from the
// tester telling it that it can start running.
if (command_line->HasSwitch(switches::kStartGlsEventName)) {
std::wstring start_event_name =
command_line->GetSwitchValueNative(switches::kStartGlsEventName);
if (!start_event_name.empty()) {
base::win::ScopedHandle start_event_handle(
::CreateEvent(nullptr, false, false, start_event_name.c_str()));
if (start_event_handle.IsValid()) {
base::WaitableEvent start_event(std::move(start_event_handle));
start_event.Wait();
}
}
}
int default_exit_code = kUiecSuccess;
EXPECT_TRUE(base::StringToInt(
command_line->GetSwitchValueASCII(switches::kDefaultExitCode),
&default_exit_code));
std::string gls_email =
command_line->GetSwitchValueASCII(switches::kGlsUserEmail);
std::string gaia_id_override =
command_line->GetSwitchValueASCII(switches::kOverrideGaiaId);
std::string gaia_password =
command_line->GetSwitchValueASCII(switches::kOverrideGaiaPassword);
std::string full_name =
command_line->GetSwitchValueASCII(switches::kOverrideFullName);
std::string expected_gaia_id =
command_line->GetSwitchValueASCII(kGaiaIdSwitch);
std::string expected_email =
command_line->GetSwitchValueASCII(kPrefillEmailSwitch);
if (expected_email.empty()) {
expected_email = gls_email;
} else {
EXPECT_EQ(gls_email, std::string());
}
if (expected_gaia_id.empty())
expected_gaia_id = kDefaultGaiaId;
if (gaia_password.empty())
gaia_password = "password";
if (full_name.empty())
full_name = "Full Name";
if (command_line->HasSwitch(switches::kIgnoreExpectedGaiaId)) {
DCHECK(!gaia_id_override.empty());
expected_gaia_id = gaia_id_override;
}
base::Value::Dict dict;
if (!gaia_id_override.empty() && gaia_id_override != expected_gaia_id) {
dict.Set(kKeyExitCode, kUiecEMailMissmatch);
} else {
dict.Set(kKeyExitCode, static_cast<UiExitCodes>(default_exit_code));
dict.Set(kKeyEmail, expected_email);
dict.Set(kKeyFullname, full_name);
dict.Set(kKeyId, expected_gaia_id);
dict.Set(kKeyAccessToken, "at-123456");
dict.Set(kKeyMdmIdToken, "idt-123456");
dict.Set(kKeyPassword, gaia_password);
dict.Set(kKeyRefreshToken, "rt-123456");
dict.Set(kKeyTokenHandle, "th-123456");
}
std::string json;
if (!base::JSONWriter::Write(dict, &json))
return -1;
HANDLE hstdout = ::GetStdHandle(STD_OUTPUT_HANDLE);
DWORD written;
if (::WriteFile(hstdout, json.c_str(), json.length(), &written, nullptr)) {
return 0;
}
return -1;
}
} // namespace
GlsRunnerTestBase::GlsRunnerTestBase()
: cpus_(CPUS_LOGON),
default_token_handle_response_(kDefaultValidTokenHandleResponse) {}
GlsRunnerTestBase::~GlsRunnerTestBase() = default;
void GlsRunnerTestBase::SetUp() {
// Create the special gaia account used to run GLS and save its password.
BSTR sid;
DWORD error;
EXPECT_EQ(S_OK, fake_os_user_manager()->AddUser(
kDefaultGaiaAccountName, L"password", L"fullname",
L"comment", true, &sid, &error));
auto policy = ScopedLsaPolicy::Create(POLICY_ALL_ACCESS);
EXPECT_EQ(S_OK, policy->StorePrivateData(kLsaKeyGaiaUsername,
kDefaultGaiaAccountName));
EXPECT_EQ(S_OK, policy->StorePrivateData(kLsaKeyGaiaPassword, L"password"));
// Make sure not to read random GCPW settings from the machine that is running
// the tests.
InitializeRegistryOverrideForTesting(®istry_override_);
// Override location of "Program Files" system folder and its x86 version so
// we don't modify local machine settings.
ASSERT_TRUE(scoped_temp_program_files_dir_.CreateUniqueTempDir());
program_files_override_ = std::make_unique<base::ScopedPathOverride>(
base::DIR_PROGRAM_FILES, scoped_temp_program_files_dir_.GetPath());
ASSERT_TRUE(scoped_temp_program_files_x86_dir_.CreateUniqueTempDir());
program_files_x86_override_ = std::make_unique<base::ScopedPathOverride>(
base::DIR_PROGRAM_FILESX86, scoped_temp_program_files_x86_dir_.GetPath());
// Also override location of "ProgramData" system folder as we store user
// policies there.
ASSERT_TRUE(scoped_temp_progdata_dir_.CreateUniqueTempDir());
programdata_override_ = std::make_unique<base::ScopedPathOverride>(
base::DIR_COMMON_APP_DATA, scoped_temp_progdata_dir_.GetPath());
}
void GlsRunnerTestBase::TearDown() {
// If credential has not been explicitly completed and the logon process
// was started, then complete here under the assumption that it will
// complete successfully.
ASSERT_EQ(S_OK, FinishLogonProcess(true, true, 0));
ASSERT_EQ(S_OK, ReleaseProvider());
}
HRESULT GlsRunnerTestBase::ReleaseProvider() {
if (!gaia_provider_)
return S_OK;
// If any logon are still pending, they are about to be killed now.
logon_process_started_successfully_ = false;
HRESULT hr = S_OK;
// Complete the release of the provider.
// Unadvise all the credentials.
DWORD count;
DWORD default_index;
BOOL autologon;
HRESULT get_count_hr =
gaia_provider_->GetCredentialCount(&count, &default_index, &autologon);
if (SUCCEEDED(get_count_hr)) {
for (DWORD i = 0; i < count; ++i) {
Microsoft::WRL::ComPtr<ICredentialProviderCredential> credential;
HRESULT get_hr = gaia_provider_->GetCredentialAt(i, &credential);
EXPECT_EQ(get_hr, S_OK);
if (SUCCEEDED(get_hr)) {
get_hr = credential->UnAdvise();
if (FAILED(get_hr))
hr = get_hr;
} else {
hr = get_hr;
}
}
} else {
hr = get_count_hr;
}
// Unadvise the provider.
HRESULT unadvise_hr = gaia_provider_->UnAdvise();
if (FAILED(unadvise_hr))
hr = unadvise_hr;
gaia_provider_.Reset();
return hr;
}
HRESULT
GlsRunnerTestBase::InitializeProviderWithCredentials(
DWORD* credential_count,
ICredentialProvider** provider) {
HRESULT hr = InternalInitializeProvider(nullptr, credential_count);
if (FAILED(hr))
return hr;
return gaia_provider_.CopyTo(IID_PPV_ARGS(provider));
}
HRESULT GlsRunnerTestBase::InitializeProviderWithRemoteCredentials(
const CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs_in,
ICredentialProvider** provider) {
HRESULT hr = InternalInitializeProvider(pcpcs_in, nullptr);
if (FAILED(hr))
return hr;
return gaia_provider_.CopyTo(IID_PPV_ARGS(provider));
}
HRESULT GlsRunnerTestBase::InitializeProviderAndGetCredential(
DWORD index,
ICredentialProviderCredential** credential) {
DCHECK(credential);
*credential = nullptr;
DWORD count = 0;
HRESULT hr = InternalInitializeProvider(nullptr, &count);
if (FAILED(hr))
return hr;
if (index >= count)
return E_FAIL;
// Reference specific credential that was requested.
hr = gaia_provider_->GetCredentialAt(index, &testing_cred_);
if (FAILED(hr))
return hr;
EXPECT_EQ(S_OK, testing_cred_.CopyTo(IID_PPV_ARGS(credential)));
return S_OK;
}
HRESULT GlsRunnerTestBase::InternalInitializeProvider(
const CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs_in,
DWORD* count) {
if (count)
*count = 0;
Microsoft::WRL::ComPtr<ICredentialProvider> provider;
HRESULT hr =
CComCreator<CComObject<CTestGaiaCredentialProvider>>::CreateInstance(
nullptr, IID_PPV_ARGS(&provider));
if (FAILED(hr))
return hr;
// Apply the filter and get remote credentials as needed.
{
CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION remote_credentials;
HRESULT update_remote_credentials_hr;
hr = ApplyProviderFilter(provider, pcpcs_in, &remote_credentials,
&update_remote_credentials_hr);
if (FAILED(hr))
return hr;
// Start process for logon screen.
hr = provider->SetUsageScenario(cpus_, 0);
if (FAILED(hr))
return hr;
if (SUCCEEDED(update_remote_credentials_hr) &&
remote_credentials.rgbSerialization) {
// Apply remote credentials if any.
if (remote_credentials.clsidCredentialProvider ==
CLSID_GaiaCredentialProvider) {
provider->SetSerialization(&remote_credentials);
}
::CoTaskMemFree(remote_credentials.rgbSerialization);
}
}
// Give list of users visible on welcome screen.
Microsoft::WRL::ComPtr<ICredentialProviderSetUserArray> provider_user_array;
hr = provider.As(&provider_user_array);
if (FAILED(hr))
return hr;
// All users are shown if the usage is not for unlocking the workstation.
bool all_users_shown = cpus_ != CPUS_UNLOCK_WORKSTATION;
CREDENTIAL_PROVIDER_ACCOUNT_OPTIONS cpao;
ICredentialProviderUserArray* user_array = fake_user_array();
hr = user_array->GetAccountOptions(&cpao);
if (FAILED(hr))
return hr;
bool other_user_tile_available = cpao == CPAO_EMPTY_LOCAL;
for (auto& sid_and_username : fake_os_user_manager_.GetUsers()) {
// If not all the users are shown, the user that locked the system is
// the only one that is in the user array (if the other user tile is
// not available).
if (!all_users_shown &&
((!sid_locking_workstation_.empty() &&
sid_locking_workstation_ != sid_and_username.first) ||
other_user_tile_available)) {
continue;
}
// Don't add the gaia special account into the fake user array.
if (sid_and_username.second == kDefaultGaiaAccountName)
continue;
fake_user_array_.AddUser(sid_and_username.first.c_str(),
sid_and_username.second.c_str());
}
hr = provider_user_array->SetUserArray(&fake_user_array_);
if (FAILED(hr))
return hr;
// Activate the CP.
hr = provider->Advise(fake_provider_events(), 0);
if (FAILED(hr))
return hr;
// This class can now take ownership of the provider so that it can
// be correctly uninitialized later.
gaia_provider_ = provider;
// GetCredentialCount must be called to initialize the credentials (if
// desired).
if (count) {
DWORD default_index;
BOOL autologon;
hr = gaia_provider_->GetCredentialCount(count, &default_index, &autologon);
if (FAILED(hr))
return hr;
EXPECT_EQ(CREDENTIAL_PROVIDER_NO_DEFAULT, default_index);
EXPECT_FALSE(autologon);
// Advise all the credentials
for (DWORD i = 0; i < *count; ++i) {
Microsoft::WRL::ComPtr<ICredentialProviderCredential> current_credential;
hr = gaia_provider_->GetCredentialAt(i, ¤t_credential);
if (FAILED(hr))
return hr;
hr = current_credential->Advise(
fake_credential_provider_credential_events());
if (FAILED(hr))
return hr;
}
}
// Verify fields.
DWORD field_count;
hr = gaia_provider_->GetFieldDescriptorCount(&field_count);
if (FAILED(hr))
return hr;
for (DWORD i = 0; i < field_count; ++i) {
CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR* ppcpfd;
hr = gaia_provider_->GetFieldDescriptorAt(i, &ppcpfd);
if (FAILED(hr))
return hr;
}
// Initialize the default field states by calling GetFieldState of
// ICredentialProviderCredential.
for (DWORD i = 0; count && i < *count; ++i) {
Microsoft::WRL::ComPtr<ICredentialProviderCredential> current_credential;
hr = gaia_provider_->GetCredentialAt(i, ¤t_credential);
if (FAILED(hr))
return hr;
for (DWORD fieldID = 0; fieldID < field_count; fieldID++) {
CREDENTIAL_PROVIDER_FIELD_STATE cpfs;
CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE cpfis;
hr = current_credential->GetFieldState(fieldID, &cpfs, &cpfis);
if (FAILED(hr))
return hr;
hr = fake_credential_provider_credential_events()->SetFieldState(
current_credential.Get(), fieldID, cpfs);
if (FAILED(hr))
return hr;
}
}
return S_OK;
}
HRESULT GlsRunnerTestBase::ApplyProviderFilter(
const Microsoft::WRL::ComPtr<ICredentialProvider>& provider,
const CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs_in,
CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs_out,
HRESULT* update_remote_credentials_hr) {
if (update_remote_credentials_hr)
*update_remote_credentials_hr = E_NOTIMPL;
// Filter only lives long enough to apply filter and get serialization
// credentials.
Microsoft::WRL::ComPtr<ICredentialProviderFilter> filter;
HRESULT hr =
CComCreator<CComObject<CGaiaCredentialProviderFilter>>::CreateInstance(
nullptr, IID_ICredentialProviderFilter, (void**)&filter);
if (FAILED(hr))
return hr;
// Set token fetch result before starting the filter.
fake_http_url_fetcher_factory_.SetFakeResponse(
GURL(AssociatedUserValidator::kTokenInfoUrl),
FakeWinHttpUrlFetcher::Headers(), default_token_handle_response_);
// Start initial refresh of token handles. The filter will apply user access
// restrictions as needed.
fake_associated_user_validator_.StartRefreshingTokenHandleValidity();
// Perform initial filter code.
GUID CLSID_SystemCredProvider1 = {
0x11111111,
0x2222,
0x3333,
{0x44, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}};
GUID CLSID_SystemCredProvider2 = {
0x11111211,
0x2122,
0x3333,
{0x44, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}};
GUID provider_guids[] = {CLSID_GaiaCredentialProvider,
CLSID_SystemCredProvider1,
CLSID_SystemCredProvider2};
BOOL provider_allow[] = {TRUE, TRUE, TRUE};
DWORD provider_count = 3;
hr = filter->Filter(cpus_, 0, provider_guids, provider_allow, provider_count);
// None of the system CLSID should be filtered out.
EXPECT_EQ(TRUE, provider_allow[1]);
EXPECT_EQ(TRUE, provider_allow[2]);
BOOL all_providers_allowed =
provider_allow[0] && provider_allow[1] && provider_allow[2];
if (FAILED(hr))
return hr;
else if (!all_providers_allowed)
return E_FAIL;
// Apply remote credentials if any.
if (pcpcs_in && pcpcs_out && update_remote_credentials_hr)
*update_remote_credentials_hr =
filter->UpdateRemoteCredential(pcpcs_in, pcpcs_out);
return S_OK;
}
HRESULT GlsRunnerTestBase::StartLogonProcess(bool succeeds) {
return StartLogonProcess(succeeds, 0);
}
HRESULT GlsRunnerTestBase::StartLogonProcess(bool succeeds,
int expected_error_message) {
DCHECK(testing_cred_);
DCHECK(!logon_process_started_successfully_);
BOOL auto_login;
EXPECT_EQ(S_OK, testing_cred_->SetSelected(&auto_login));
// Logging on is an async process, so the call to GetSerialization() starts
// the process, but when it returns it has not completed.
CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE cpgsr;
CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION cpcs;
CREDENTIAL_PROVIDER_STATUS_ICON status_icon;
wchar_t* status_text;
EXPECT_EQ(S_OK, testing_cred_->GetSerialization(&cpgsr, &cpcs, &status_text,
&status_icon));
EXPECT_EQ(CPSI_NONE, status_icon);
if (succeeds) {
EXPECT_EQ(nullptr, status_text);
EXPECT_EQ(CPGSR_NO_CREDENTIAL_NOT_FINISHED, cpgsr);
logon_process_started_successfully_ = true;
} else {
EXPECT_NE(nullptr, status_text);
EXPECT_EQ(CPGSR_NO_CREDENTIAL_FINISHED, cpgsr);
}
if (expected_error_message != 0) {
EXPECT_STREQ(status_text,
GetStringResource(expected_error_message).c_str());
}
return S_OK;
}
HRESULT GlsRunnerTestBase::WaitForLogonProcess() {
Microsoft::WRL::ComPtr<testing::ITestCredential> test;
HRESULT hr = testing_cred_.As(&test);
if (FAILED(hr))
return hr;
return test->WaitForGls();
}
HRESULT GlsRunnerTestBase::StartLogonProcessAndWait() {
HRESULT hr = StartLogonProcess(/*succeeds=*/true);
if (FAILED(hr))
return hr;
return WaitForLogonProcess();
}
// static
HRESULT GlsRunnerTestBase::GetFakeGlsCommandline(
UiExitCodes default_exit_code,
const std::string& gls_email,
const std::string& gaia_id_override,
const std::string& gaia_password,
const std::string& full_name_override,
const std::wstring& start_gls_event_name,
bool ignore_expected_gaia_id,
base::CommandLine* command_line) {
*command_line = base::GetMultiProcessTestChildBaseCommandLine();
command_line->AppendSwitchASCII(::switches::kTestChildProcess, "gls_main");
command_line->AppendSwitchASCII(switches::kGlsUserEmail, gls_email);
command_line->AppendSwitchNative(switches::kDefaultExitCode,
base::NumberToWString(default_exit_code));
if (ignore_expected_gaia_id)
command_line->AppendSwitch(switches::kIgnoreExpectedGaiaId);
if (!gaia_id_override.empty()) {
command_line->AppendSwitchASCII(switches::kOverrideGaiaId,
gaia_id_override);
}
if (!gaia_password.empty()) {
command_line->AppendSwitchASCII(switches::kOverrideGaiaPassword,
gaia_password);
}
if (!start_gls_event_name.empty()) {
command_line->AppendSwitchNative(switches::kStartGlsEventName,
start_gls_event_name);
}
if (!full_name_override.empty()) {
command_line->AppendSwitchASCII(switches::kOverrideFullName,
full_name_override);
}
return S_OK;
}
HRESULT GlsRunnerTestBase::FinishLogonProcess(
bool expected_success,
bool expected_credentials_change_fired,
int expected_error_message) {
return FinishLogonProcess(
expected_success, expected_credentials_change_fired,
expected_error_message ? GetStringResource(expected_error_message) : L"");
}
HRESULT GlsRunnerTestBase::FinishLogonProcess(
bool expected_success,
bool expected_credentials_change_fired,
const std::wstring& expected_error_message) {
// If no logon process was started, there is nothing to finish.
if (!logon_process_started_successfully_)
return S_OK;
Microsoft::WRL::ComPtr<ICredentialProviderCredential> local_testing_cred =
testing_cred_;
// Release ownership on the testing_cred_ which should be finishing.
testing_cred_.Reset();
HRESULT hr = FinishLogonProcessWithCred(
expected_success, expected_credentials_change_fired,
expected_error_message, local_testing_cred);
if (!fake_os_user_manager()->DoesOperationFail(
FAILEDOPERATIONS::CHANGE_PASSWORD)) {
EXPECT_EQ(hr, S_OK);
}
if (FAILED(hr))
return hr;
if (expected_credentials_change_fired) {
hr = ReportLogonProcessResult(local_testing_cred);
EXPECT_EQ(hr, S_OK);
return hr;
}
return S_OK;
}
HRESULT GlsRunnerTestBase::FinishLogonProcessWithCred(
bool expected_success,
bool expected_credentials_change_fired,
int expected_error_message,
const Microsoft::WRL::ComPtr<ICredentialProviderCredential>&
local_testing_cred) {
return FinishLogonProcessWithCred(
expected_success, expected_credentials_change_fired,
expected_error_message ? GetStringResource(expected_error_message) : L"",
local_testing_cred);
}
HRESULT GlsRunnerTestBase::FinishLogonProcessWithCred(
bool expected_success,
bool expected_credentials_change_fired,
const std::wstring& expected_error_message,
const Microsoft::WRL::ComPtr<ICredentialProviderCredential>&
local_testing_cred) {
// If no logon process was started, there is nothing to finish.
if (!logon_process_started_successfully_)
return S_OK;
logon_process_started_successfully_ = false;
DCHECK(gaia_provider_);
Microsoft::WRL::ComPtr<ITestCredential> test_cred;
HRESULT hr = local_testing_cred.As(&test_cred);
if (FAILED(hr))
return hr;
Microsoft::WRL::ComPtr<ITestCredentialProvider> test_provider;
hr = gaia_provider_.As(&test_provider);
if (FAILED(hr))
return hr;
EXPECT_EQ(test_provider->credentials_changed_fired(),
expected_success && expected_credentials_change_fired);
if (!expected_success) {
// Check that values were not propagated to the provider.
EXPECT_EQ(0u, test_provider->username().Length());
EXPECT_EQ(0u, test_provider->password().Length());
EXPECT_EQ(0u, test_provider->sid().Length());
if (!expected_error_message.empty()) {
EXPECT_STREQ(test_cred->GetErrorText(), expected_error_message.c_str());
} else {
EXPECT_EQ(test_cred->GetErrorText(), nullptr);
}
return S_OK;
} else {
// Also extract other registration related fields and verify if those are
// non-empty.
EXPECT_TRUE(test_cred->ContainsIsAdJoinedUser());
}
// Call final GetSerialization and expect it to be finished.
CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE cpgsr;
CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION cpcs;
wchar_t* status_text;
CREDENTIAL_PROVIDER_STATUS_ICON status_icon;
hr = local_testing_cred->GetSerialization(&cpgsr, &cpcs, &status_text,
&status_icon);
if (FAILED(hr))
return hr;
// Credentials not valid, login doesn't go through.
if (test_cred->AreCredentialsValid()) {
EXPECT_EQ(nullptr, status_text);
EXPECT_EQ(CPSI_SUCCESS, status_icon);
EXPECT_EQ(CPGSR_RETURN_CREDENTIAL_FINISHED, cpgsr);
EXPECT_LT(0u, cpcs.cbSerialization);
EXPECT_NE(nullptr, cpcs.rgbSerialization);
} else {
EXPECT_EQ(CPSI_ERROR, status_icon);
EXPECT_EQ(CPGSR_RETURN_NO_CREDENTIAL_FINISHED, cpgsr);
// The credential provider has not serialized a credential,
// but has completed its work. This will force the logon UI to
// return, which will call UnAdvise for all the credential providers.
return E_FAIL;
}
// Check that values were propagated to the provider.
if (expected_credentials_change_fired) {
EXPECT_NE(0u, test_provider->username().Length());
EXPECT_NE(0u, test_provider->password().Length());
EXPECT_NE(0u, test_provider->sid().Length());
}
EXPECT_EQ(test_cred->GetErrorText(), nullptr);
return S_OK;
}
HRESULT GlsRunnerTestBase::ReportLogonProcessResult(
const Microsoft::WRL::ComPtr<ICredentialProviderCredential>&
local_testing_cred) {
Microsoft::WRL::ComPtr<ITestCredential> test_cred;
HRESULT hr = local_testing_cred.As(&test_cred);
if (FAILED(hr))
return hr;
// State was not reset.
EXPECT_TRUE(test_cred->AreCredentialsValid());
wchar_t* report_status_text = nullptr;
CREDENTIAL_PROVIDER_STATUS_ICON report_icon;
hr =
local_testing_cred->ReportResult(0, 0, &report_status_text, &report_icon);
if (FAILED(hr))
return hr;
// State was reset.
EXPECT_FALSE(test_cred->AreCredentialsValid());
return S_OK;
}
} // namespace testing
} // namespace credential_provider