// Copyright 2020 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/gaiacp/device_policies_manager.h"
#include <windows.h>
#include "base/strings/strcat_win.h"
#include "base/strings/string_number_conversions_win.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/credential_provider/gaiacp/gcpw_strings.h"
#include "chrome/credential_provider/gaiacp/reg_utils.h"
#include "chrome/credential_provider/test/gls_runner_test_base.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace credential_provider {
namespace testing {
class GcpDevicePoliciesBaseTest : public GlsRunnerTestBase {
protected:
void SetUp() override;
};
void GcpDevicePoliciesBaseTest::SetUp() {
GlsRunnerTestBase::SetUp();
// Remove the mdm_url value which exists by default as it's added in
// InitializeRegistryOverrideForTesting.
base::win::RegKey key;
EXPECT_EQ(ERROR_SUCCESS,
key.Open(HKEY_LOCAL_MACHINE, kGcpRootKeyName, KEY_WRITE));
EXPECT_EQ(ERROR_SUCCESS, key.DeleteValue(kRegMdmUrl));
FakesForTesting fakes;
fakes.fake_win_http_url_fetcher_creator =
fake_http_url_fetcher_factory()->GetCreatorCallback();
fakes.os_user_manager_for_testing = fake_os_user_manager();
UserPoliciesManager::Get()->SetFakesForTesting(&fakes);
}
TEST_F(GcpDevicePoliciesBaseTest, NewUserAssociationWithNoUserPoliciesPresent) {
FakeUserPoliciesManager fake_user_policies_manager(true);
// Create a few fake users associated to fake gaia ids.
std::vector<std::wstring> sids;
const size_t num_users_needed = 3;
for (size_t i = 0; i < num_users_needed; ++i) {
CComBSTR sid_str;
const std::wstring i_str = base::NumberToWString(i);
std::wstring username = L"new-user-" + i_str;
std::wstring gaia_id = L"gaia-id-" + i_str;
std::wstring email = base::StrCat({L"user_", i_str, L"@company.com"});
ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
username, L"password", L"Full Name", L"comment",
gaia_id, email, &sid_str));
sids.push_back(OLE2W(sid_str));
}
// Create an existing user association in registry but with an invalid sid.
base::win::RegKey key;
std::wstring key_name =
std::wstring(kGcpUsersRootKeyName) + L"\\non-existent-user-sid";
ASSERT_EQ(ERROR_SUCCESS,
key.Create(HKEY_LOCAL_MACHINE, key_name.c_str(), KEY_WRITE));
ASSERT_EQ(ERROR_SUCCESS,
key.WriteValue(L"email", L"[email protected]"));
// Add user cloud policies only for the first two users.
UserPolicies first_user_policy;
first_user_policy.enable_dm_enrollment = false;
first_user_policy.enable_gcpw_auto_update = false;
first_user_policy.enable_multi_user_login = false;
first_user_policy.gcpw_pinned_version = GcpwVersion("100.1.2.3");
fake_user_policies_manager.SetUserPolicies(sids[0], first_user_policy);
UserPolicies second_user_policy = first_user_policy;
second_user_policy.enable_dm_enrollment = true;
second_user_policy.gcpw_pinned_version = GcpwVersion("102.1.2.4");
fake_user_policies_manager.SetUserPolicies(sids[1], second_user_policy);
// Create a device policy by merging the two users with cloud policies.
DevicePolicies merged_device_policy =
DevicePolicies::FromUserPolicies(first_user_policy);
merged_device_policy.MergeWith(
DevicePolicies::FromUserPolicies(second_user_policy));
// Get the resolved device policy.
DevicePolicies device_policy;
DevicePoliciesManager::Get()->GetDevicePolicies(&device_policy);
// The resolved policy should reflect only the policies of the users with
// existing cloud policies.
ASSERT_EQ(merged_device_policy, device_policy);
}
// Tests that existing registry values that control device policies are honored
// correctly when present.
// Parameters are:
// 1. int 0: "enable_dm_enrollment" flag is set to 0.
// 1: "enable_dm_enrollment" flag is set to 1.
// 2: "enable_dm_enrollment" flag is not set.
// 2. int 0: "mdm" flag for MDM url is set to "".
// 1: "mdm" flag for MDM url is set to some valid value.
// 2: "mdm" flag for MDM url is not set.
// 3. int 0: "enable_multi_user_login" flag is set to 0.
// 1: "enable_multi_user_login" flag is set to 1.
// 2: "enable_multi_user_login" flag is not set.
class GcpDevicePoliciesRegistryTest
: public GcpDevicePoliciesBaseTest,
public ::testing::WithParamInterface<std::tuple<int, int, int>> {};
TEST_P(GcpDevicePoliciesRegistryTest, DefaultValues) {
int dm_enrollment_flag = std::get<0>(GetParam());
int mdm_url_flag = std::get<1>(GetParam());
int multi_user_login_flag = std::get<2>(GetParam());
if (dm_enrollment_flag < 2) {
ASSERT_EQ(S_OK, SetGlobalFlagForTesting(kRegEnableDmEnrollment,
dm_enrollment_flag ? 1 : 0));
}
if (mdm_url_flag == 1) {
ASSERT_EQ(S_OK, SetGlobalFlagForTesting(kRegMdmUrl, L"https://mdm.com"));
} else if (mdm_url_flag == 0) {
base::win::RegKey key;
ASSERT_EQ(ERROR_SUCCESS,
key.Open(HKEY_LOCAL_MACHINE, kGcpRootKeyName, KEY_WRITE));
ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kRegMdmUrl, L""));
}
if (multi_user_login_flag < 2) {
ASSERT_EQ(S_OK, SetGlobalFlagForTesting(kRegMdmSupportsMultiUser,
multi_user_login_flag ? 1 : 0));
}
DevicePolicies default_device_policies;
// Enabled unless explicitly forbidden through setting either registry flags.
bool enable_dm_enrollment = !(!dm_enrollment_flag || !mdm_url_flag);
ASSERT_EQ(enable_dm_enrollment, default_device_policies.enable_dm_enrollment);
ASSERT_EQ(multi_user_login_flag > 0,
default_device_policies.enable_multi_user_login);
}
INSTANTIATE_TEST_SUITE_P(All,
GcpDevicePoliciesRegistryTest,
::testing::Combine(::testing::Values(0, 1, 2),
::testing::Values(0, 1, 2),
::testing::Values(0, 1, 2)));
// Tests that the merging of two device policies does not lead to a more
// restrictive policy.
// Parameters are:
// 1. bool : Whether MDM enrollment is enabled.
// 2. bool : Whether GCPW auto update through Omaha is enabled.
// 3. bool : Whether multi user mode is enabled.
// 4. string : Version of GCPW to use.
class GcpDevicePoliciesMergeTest
: public GcpDevicePoliciesBaseTest,
public ::testing::WithParamInterface<
std::tuple<bool, bool, bool, const char*>> {};
TEST_P(GcpDevicePoliciesMergeTest, OtherUser) {
UserPolicies new_user_policy;
new_user_policy.enable_dm_enrollment = std::get<0>(GetParam());
new_user_policy.enable_gcpw_auto_update = std::get<1>(GetParam());
new_user_policy.enable_multi_user_login = std::get<2>(GetParam());
new_user_policy.gcpw_pinned_version = GcpwVersion(std::get<3>(GetParam()));
UserPolicies existing_user_policy;
existing_user_policy.enable_dm_enrollment = true;
existing_user_policy.enable_gcpw_auto_update = true;
existing_user_policy.enable_multi_user_login = true;
existing_user_policy.gcpw_pinned_version = GcpwVersion("100.1.2.3");
// Create a device policy by merging the two users policies.
DevicePolicies device_policy =
DevicePolicies::FromUserPolicies(existing_user_policy);
device_policy.MergeWith(DevicePolicies::FromUserPolicies(new_user_policy));
// The new policy should allow everything the existing user was able to do
// before.
ASSERT_EQ(existing_user_policy.enable_dm_enrollment,
device_policy.enable_dm_enrollment);
ASSERT_EQ(existing_user_policy.enable_gcpw_auto_update,
device_policy.enable_gcpw_auto_update);
ASSERT_EQ(existing_user_policy.enable_multi_user_login,
device_policy.enable_multi_user_login);
// The GCPW version should be the latest allowed.
GcpwVersion gcpw_version = std::max(existing_user_policy.gcpw_pinned_version,
new_user_policy.gcpw_pinned_version);
ASSERT_EQ(gcpw_version, device_policy.gcpw_pinned_version);
}
INSTANTIATE_TEST_SUITE_P(All,
GcpDevicePoliciesMergeTest,
::testing::Combine(::testing::Bool(),
::testing::Bool(),
::testing::Bool(),
::testing::Values("99.1.2.3",
"100.1.2.3",
"100.1.2.4")));
// Base test for testing allowed domains policy scenarios.
class GcpDevicePoliciesAllowedDomainsBaseTest
: public GcpDevicePoliciesBaseTest {
public:
void SetUp() override;
};
void GcpDevicePoliciesAllowedDomainsBaseTest::SetUp() {
GcpDevicePoliciesBaseTest::SetUp();
// Delete any existing registry entries. Setting to empty deletes them.
SetGlobalFlagForTesting(L"ed", L"");
SetGlobalFlagForTesting(L"domains_allowed_to_login", L"");
}
// Test that correct allowed domains policy is obtained whether they are set in
// the registry or through the cloud policy.
// Parameters are:
// 1. bool : Whether domains set through Omaha cloud policy.
// 2. int : 0 - Domains not set through registry.
// 1 - Domains set through deprecated "ed" registry entry.
// 2 - Domains set through "domains_allowed_to_login" registry entry.
// 3. string : List of domains from which users are allowed to login.
// 4. bool : Has existing user.
class GcpDevicePoliciesAllowedDomainsTest
: public GcpDevicePoliciesAllowedDomainsBaseTest,
public ::testing::WithParamInterface<
std::tuple<bool, int, const wchar_t*, bool>> {};
TEST_P(GcpDevicePoliciesAllowedDomainsTest, OmahaPolicyTest) {
bool has_omaha_domains_policy = std::get<0>(GetParam());
bool has_registry_domains_policy = std::get<1>(GetParam()) != 0;
bool use_old_domains_reg_key = std::get<1>(GetParam()) == 1;
std::wstring allowed_domains_str(std::get<2>(GetParam()));
bool has_existing_user = std::get<3>(GetParam());
std::vector<std::wstring> allowed_domains = base::SplitString(
allowed_domains_str, L",", base::WhitespaceHandling::TRIM_WHITESPACE,
base::SplitResult::SPLIT_WANT_NONEMPTY);
if (has_omaha_domains_policy) {
ASSERT_TRUE(
DevicePoliciesManager::Get()->SetAllowedDomainsOmahaPolicyForTesting(
allowed_domains));
}
if (has_registry_domains_policy) {
if (use_old_domains_reg_key) {
SetGlobalFlagForTesting(L"ed", allowed_domains_str);
} else {
SetGlobalFlagForTesting(L"domains_allowed_to_login", allowed_domains_str);
}
}
FakeUserPoliciesManager fake_user_policies_manager(true);
UserPolicies user_policy;
if (has_existing_user) {
CComBSTR sid;
ASSERT_EQ(S_OK,
fake_os_user_manager()->CreateTestOSUser(
kDefaultUsername, L"password", L"Full Name", L"comment",
base::UTF8ToWide(kDefaultGaiaId), std::wstring(), &sid));
// Add a random user policy.
user_policy.enable_dm_enrollment = false;
user_policy.enable_gcpw_auto_update = false;
user_policy.enable_multi_user_login = false;
user_policy.gcpw_pinned_version = GcpwVersion("100.1.2.3");
fake_user_policies_manager.SetUserPolicies(OLE2W(sid), user_policy);
}
DevicePolicies device_policies;
DevicePoliciesManager::Get()->GetDevicePolicies(&device_policies);
if (has_omaha_domains_policy || has_registry_domains_policy)
ASSERT_EQ(allowed_domains, device_policies.domains_allowed_to_login);
if (has_existing_user) {
ASSERT_EQ(user_policy.enable_dm_enrollment,
device_policies.enable_dm_enrollment);
ASSERT_EQ(user_policy.enable_gcpw_auto_update,
device_policies.enable_gcpw_auto_update);
ASSERT_EQ(user_policy.enable_multi_user_login,
device_policies.enable_multi_user_login);
ASSERT_EQ(user_policy.gcpw_pinned_version,
device_policies.gcpw_pinned_version);
}
}
INSTANTIATE_TEST_SUITE_P(
All,
GcpDevicePoliciesAllowedDomainsTest,
::testing::Combine(
::testing::Bool(),
::testing::Values(0, 1, 2),
::testing::Values(L"", L"acme.com", L"acme.com,acme.org"),
::testing::Bool()));
// Test to ensure Omaha policies override the existing registry settings for
// allowed domains policy.
// Parameters are:
// 1. bool : If true, deprecated "ed" registry entry is used. Otherwise
// "domains_allowed_to_login" is used.
// 2. string : List of allowed domains for GCPW specified through registry.
// 3. string : List of allowed domains for GCPW specified through a Omaha cloud
// policy.
class GcpDevicePoliciesOmahaDomainsWinTest
: public GcpDevicePoliciesAllowedDomainsBaseTest,
public ::testing::WithParamInterface<
std::tuple<bool, const wchar_t*, const wchar_t*>> {};
TEST_P(GcpDevicePoliciesOmahaDomainsWinTest, TestConflict) {
bool use_old_domains_reg_key = std::get<0>(GetParam());
std::wstring domains_registry_str(std::get<1>(GetParam()));
std::wstring domains_from_omaha_str(std::get<2>(GetParam()));
std::vector<std::wstring> allowed_domains_registry = base::SplitString(
domains_registry_str, L",", base::WhitespaceHandling::TRIM_WHITESPACE,
base::SplitResult::SPLIT_WANT_NONEMPTY);
std::vector<std::wstring> allowed_domains_omaha = base::SplitString(
domains_from_omaha_str, L",", base::WhitespaceHandling::TRIM_WHITESPACE,
base::SplitResult::SPLIT_WANT_NONEMPTY);
ASSERT_TRUE(
DevicePoliciesManager::Get()->SetAllowedDomainsOmahaPolicyForTesting(
allowed_domains_omaha));
if (use_old_domains_reg_key) {
SetGlobalFlagForTesting(L"ed", domains_registry_str);
} else {
SetGlobalFlagForTesting(L"domains_allowed_to_login", domains_registry_str);
}
DevicePolicies device_policies;
DevicePoliciesManager::Get()->GetDevicePolicies(&device_policies);
if (!allowed_domains_omaha.empty()) {
ASSERT_EQ(allowed_domains_omaha, device_policies.domains_allowed_to_login);
} else {
ASSERT_EQ(allowed_domains_registry,
device_policies.domains_allowed_to_login);
}
}
INSTANTIATE_TEST_SUITE_P(
All,
GcpDevicePoliciesOmahaDomainsWinTest,
::testing::Combine(
::testing::Bool(),
::testing::Values(L"", L"acme.com", L"acme.com,acme.org"),
::testing::Values(L"", L"company.com", L"company.com,company.org")));
} // namespace testing
} // namespace credential_provider