| // Copyright 2017 The Chromium OS 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 <string> |
| |
| #include <base/files/file_path.h> |
| #include <base/files/file_util.h> |
| #include <base/macros.h> |
| #include <base/strings/stringprintf.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "authpolicy/policy/policy_encoder_helper.h" |
| #include "authpolicy/policy/preg_policy_encoder.h" |
| #include "authpolicy/policy/preg_policy_writer.h" |
| #include "bindings/authpolicy_containers.pb.h" |
| #include "bindings/chrome_device_policy.pb.h" |
| #include "bindings/cloud_policy.pb.h" |
| #include "bindings/policy_constants.h" |
| |
| namespace em = enterprise_management; |
| |
| namespace { |
| |
| constexpr char kPreg1Filename[] = "registry1.pol"; |
| constexpr char kPreg2Filename[] = "registry2.pol"; |
| |
| // Some constants for policy testing. |
| const bool kPolicyBool = true; |
| const bool kOtherPolicyBool = false; |
| |
| const int kPolicyInt = 321; |
| const int kOtherPolicyInt = 234; |
| |
| constexpr char kPolicyStr[] = "Str"; |
| constexpr char kOtherPolicyStr[] = "OtherStr"; |
| |
| constexpr char kExtensionId[] = "abcdeFGHabcdefghAbcdefGhabcdEfgh"; |
| constexpr char kOtherExtensionId[] = "ababababcdcdcdcdefefefefghghghgh"; |
| constexpr char kInvalidExtensionId[] = "abcdeFGHabcdefgh"; |
| |
| constexpr char kExtensionPolicy1[] = "Policy1"; |
| constexpr char kExtensionPolicy2[] = "Policy2"; |
| constexpr char kExtensionPolicy3[] = "Policy3"; |
| constexpr char kExtensionPolicy4[] = "Policy4"; |
| |
| } // namespace |
| |
| namespace policy { |
| |
| // Tests basic preg-to-policy encoding and the promises |
| // ParsePRegFilesIntoUserPolicy and ParsePRegFilesIntoDevicePolicy make. |
| class PregPolicyEncoderTest : public ::testing::Test { |
| public: |
| PregPolicyEncoderTest() = default; |
| |
| void SetUp() override { |
| // Create temp directory for policy files. |
| CHECK(base::CreateNewTempDirectory("" /* prefix (ignored) */, &base_path_)); |
| |
| preg_1_path_ = base_path_.Append(kPreg1Filename); |
| preg_2_path_ = base_path_.Append(kPreg2Filename); |
| } |
| |
| void TearDown() override { |
| // Don't not leave no mess behind. |
| base::DeleteFile(base_path_, true /* recursive */); |
| } |
| |
| protected: |
| // Whether policies from the first or the second file win. |
| enum WhoWins { FIRST_WINS, SECOND_WINS }; |
| |
| // Writes two files with policies, encodes them and tests whether policies |
| // from the first of the second file 'won' (prevailed). |level1| and |level2| |
| // are the policy levels for the two files. |
| void TestUserPolicyFileOverride(PolicyLevel level1, |
| PolicyLevel level2, |
| WhoWins who_wins) { |
| // Write file 1 with some interesting data. Set policy level to level1. |
| PRegUserDevicePolicyWriter writer1; |
| writer1.AppendBoolean(key::kSearchSuggestEnabled, kOtherPolicyBool, level1); |
| writer1.AppendInteger(key::kPolicyRefreshRate, kPolicyInt, level1); |
| writer1.AppendString(key::kHomepageLocation, kPolicyStr, level1); |
| const std::vector<std::string> apps1 = {"App1", "App2", "App3"}; |
| writer1.AppendStringList(key::kPinnedLauncherApps, apps1, level1); |
| writer1.WriteToFile(preg_1_path_); |
| |
| // Write file 2 with the same policies, but different values. Set policy |
| // level to level2. |
| PRegUserDevicePolicyWriter writer2; |
| writer2.AppendBoolean(key::kSearchSuggestEnabled, kPolicyBool, level2); |
| writer2.AppendInteger(key::kPolicyRefreshRate, kOtherPolicyInt, level2); |
| writer2.AppendString(key::kHomepageLocation, kOtherPolicyStr, level2); |
| const std::vector<std::string> apps2 = {"App4", "App5"}; |
| writer2.AppendStringList(key::kPinnedLauncherApps, apps2, level2); |
| writer2.WriteToFile(preg_2_path_); |
| |
| // Encode to policy. |
| em::CloudPolicySettings policy; |
| EXPECT_TRUE(ParsePRegFilesIntoUserPolicy( |
| {preg_1_path_, preg_2_path_}, &policy, false /* log_policy_values */)); |
| |
| bool win_bool = (who_wins == FIRST_WINS ? kOtherPolicyBool : kPolicyBool); |
| int win_int = (who_wins == FIRST_WINS ? kPolicyInt : kOtherPolicyInt); |
| const std::string& win_string = |
| (who_wins == FIRST_WINS ? kPolicyStr : kOtherPolicyStr); |
| const auto& win_string_list = (who_wins == FIRST_WINS ? apps1 : apps2); |
| PolicyLevel win_level = (who_wins == FIRST_WINS ? level1 : level2); |
| em::PolicyOptions::PolicyMode win_mode = |
| win_level == POLICY_LEVEL_MANDATORY ? em::PolicyOptions::MANDATORY |
| : em::PolicyOptions::RECOMMENDED; |
| |
| // Check that the expected values prevail. |
| EXPECT_TRUE(policy.searchsuggestenabled().has_policy_options()); |
| EXPECT_EQ(win_mode, policy.searchsuggestenabled().policy_options().mode()); |
| EXPECT_TRUE(policy.searchsuggestenabled().has_value()); |
| EXPECT_EQ(win_bool, policy.searchsuggestenabled().value()); |
| |
| EXPECT_TRUE(policy.policyrefreshrate().has_policy_options()); |
| EXPECT_EQ(win_mode, policy.policyrefreshrate().policy_options().mode()); |
| EXPECT_TRUE(policy.policyrefreshrate().has_value()); |
| EXPECT_EQ(win_int, policy.policyrefreshrate().value()); |
| |
| EXPECT_TRUE(policy.homepagelocation().has_policy_options()); |
| EXPECT_EQ(win_mode, policy.homepagelocation().policy_options().mode()); |
| EXPECT_TRUE(policy.homepagelocation().has_value()); |
| EXPECT_EQ(win_string, policy.homepagelocation().value()); |
| |
| EXPECT_TRUE(policy.homepagelocation().has_policy_options()); |
| EXPECT_EQ(win_mode, policy.pinnedlauncherapps().policy_options().mode()); |
| EXPECT_TRUE(policy.pinnedlauncherapps().has_value()); |
| const em::StringList& apps_proto = policy.pinnedlauncherapps().value(); |
| EXPECT_EQ(apps_proto.entries_size(), |
| static_cast<int>(win_string_list.size())); |
| for (int n = 0; n < apps_proto.entries_size(); ++n) |
| EXPECT_EQ(apps_proto.entries(n), win_string_list.at(n)); |
| } |
| |
| base::FilePath base_path_; |
| base::FilePath preg_1_path_; |
| base::FilePath preg_2_path_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(PregPolicyEncoderTest); |
| }; |
| |
| // Encodes user policies of different types. |
| TEST_F(PregPolicyEncoderTest, UserPolicyEncodingWorks) { |
| // Create a preg file with some interesting data. |
| PRegUserDevicePolicyWriter writer; |
| writer.AppendBoolean(key::kSearchSuggestEnabled, kPolicyBool); |
| writer.AppendInteger(key::kPolicyRefreshRate, kPolicyInt); |
| writer.AppendString(key::kHomepageLocation, kPolicyStr); |
| const std::vector<std::string> apps = {"App1", "App2"}; |
| writer.AppendStringList(key::kPinnedLauncherApps, apps); |
| writer.WriteToFile(preg_1_path_); |
| |
| // Encode preg file into policy. |
| em::CloudPolicySettings policy; |
| EXPECT_TRUE(ParsePRegFilesIntoUserPolicy({preg_1_path_}, &policy, |
| false /* log_policy_values */)); |
| |
| // Check that policy has the same values as we wrote to the file. |
| EXPECT_EQ(kPolicyBool, policy.searchsuggestenabled().value()); |
| EXPECT_EQ(kPolicyInt, policy.policyrefreshrate().value()); |
| EXPECT_EQ(kPolicyStr, policy.homepagelocation().value()); |
| const em::StringList& apps_proto = policy.pinnedlauncherapps().value(); |
| EXPECT_EQ(apps_proto.entries_size(), static_cast<int>(apps.size())); |
| for (int n = 0; n < apps_proto.entries_size(); ++n) |
| EXPECT_EQ(apps_proto.entries(n), apps.at(n)); |
| } |
| |
| // Checks that a user GPO later in the list overrides prior GPOs for recommended |
| // policies. |
| TEST_F(PregPolicyEncoderTest, UserPolicyRecommendedOverridesRecommended) { |
| TestUserPolicyFileOverride(POLICY_LEVEL_RECOMMENDED, POLICY_LEVEL_RECOMMENDED, |
| SECOND_WINS); |
| } |
| |
| // Checks that a user GPO later in the list overrides prior GPOs for mandatory |
| // policies. |
| TEST_F(PregPolicyEncoderTest, UserPolicyMandatoryOverridesMandatory) { |
| TestUserPolicyFileOverride(POLICY_LEVEL_MANDATORY, POLICY_LEVEL_MANDATORY, |
| SECOND_WINS); |
| } |
| |
| // Verifies that a mandatory policy is not overridden by a recommended policy. |
| TEST_F(PregPolicyEncoderTest, UserPolicyRecommendedDoesNotOverrideMandatory) { |
| TestUserPolicyFileOverride(POLICY_LEVEL_MANDATORY, POLICY_LEVEL_RECOMMENDED, |
| FIRST_WINS); |
| } |
| |
| // Verifies that a mandatory policy overrides a recommended policy. |
| TEST_F(PregPolicyEncoderTest, UserPolicyMandatoryOverridesRecommended) { |
| TestUserPolicyFileOverride(POLICY_LEVEL_RECOMMENDED, POLICY_LEVEL_MANDATORY, |
| SECOND_WINS); |
| } |
| |
| // Encodes device policies of different types. |
| TEST_F(PregPolicyEncoderTest, DevicePolicyEncodingWorks) { |
| // Create a preg file with some interesting data. |
| PRegUserDevicePolicyWriter writer; |
| writer.AppendBoolean(key::kDeviceGuestModeEnabled, kPolicyBool); |
| writer.AppendInteger(key::kDevicePolicyRefreshRate, kPolicyInt); |
| writer.AppendString(key::kSystemTimezone, kPolicyStr); |
| const std::vector<std::string> flags = {"flag1", "flag2"}; |
| writer.AppendStringList(key::kDeviceStartUpFlags, flags); |
| writer.WriteToFile(preg_1_path_); |
| |
| // Encode preg file into policy. |
| em::ChromeDeviceSettingsProto policy; |
| EXPECT_TRUE(ParsePRegFilesIntoDevicePolicy({preg_1_path_}, &policy, |
| false /* log_policy_values */)); |
| |
| // Check that policy has the same values as we wrote to the file. |
| EXPECT_EQ(kPolicyBool, policy.guest_mode_enabled().guest_mode_enabled()); |
| EXPECT_EQ(kPolicyInt, |
| policy.device_policy_refresh_rate().device_policy_refresh_rate()); |
| EXPECT_EQ(kPolicyStr, policy.system_timezone().timezone()); |
| const em::StartUpFlagsProto& flags_proto = policy.start_up_flags(); |
| EXPECT_EQ(flags_proto.flags_size(), static_cast<int>(flags.size())); |
| for (int n = 0; n < flags_proto.flags_size(); ++n) |
| EXPECT_EQ(flags_proto.flags(n), flags.at(n)); |
| } |
| |
| // Checks that a device GPO later in the list overrides prior GPOs. |
| TEST_F(PregPolicyEncoderTest, DevicePolicyFileOverride) { |
| // Write file 1 with some interesting data. Note that device policy doesn't |
| // support mandatory/recommended policies. |
| PRegUserDevicePolicyWriter writer1; |
| writer1.AppendBoolean(key::kDeviceGuestModeEnabled, kOtherPolicyBool); |
| writer1.AppendInteger(key::kDevicePolicyRefreshRate, kPolicyInt); |
| writer1.AppendString(key::kSystemTimezone, kPolicyStr); |
| const std::vector<std::string> flags1 = {"flag1", "flag2", "flag3"}; |
| writer1.AppendStringList(key::kDeviceStartUpFlags, flags1); |
| writer1.WriteToFile(preg_1_path_); |
| |
| // Write file 2 with the same policies, but different values. |
| PRegUserDevicePolicyWriter writer2; |
| writer2.AppendBoolean(key::kDeviceGuestModeEnabled, kPolicyBool); |
| writer2.AppendInteger(key::kDevicePolicyRefreshRate, kOtherPolicyInt); |
| writer2.AppendString(key::kSystemTimezone, kOtherPolicyStr); |
| const std::vector<std::string> flags2 = {"flag4", "flag5"}; |
| writer2.AppendStringList(key::kDeviceStartUpFlags, flags2); |
| writer2.WriteToFile(preg_2_path_); |
| |
| // Encode to policy. |
| em::ChromeDeviceSettingsProto policy; |
| EXPECT_TRUE(ParsePRegFilesIntoDevicePolicy( |
| {preg_1_path_, preg_2_path_}, &policy, false /* log_policy_values */)); |
| |
| // Check that the values from file 2 prevailed. |
| EXPECT_EQ(kPolicyBool, policy.guest_mode_enabled().guest_mode_enabled()); |
| EXPECT_EQ(kOtherPolicyInt, |
| policy.device_policy_refresh_rate().device_policy_refresh_rate()); |
| EXPECT_EQ(kOtherPolicyStr, policy.system_timezone().timezone()); |
| const em::StartUpFlagsProto& flags_proto = policy.start_up_flags(); |
| EXPECT_EQ(flags_proto.flags_size(), static_cast<int>(flags2.size())); |
| for (int n = 0; n < flags_proto.flags_size(); ++n) |
| EXPECT_EQ(flags_proto.flags(n), flags2.at(n)); |
| } |
| |
| // Encodes extension policies of different types. |
| TEST_F(PregPolicyEncoderTest, ExtensionPolicyEncodingWorks) { |
| // Create a preg file with some interesting data. |
| PRegExtensionPolicyWriter writer(kExtensionId); |
| writer.AppendBoolean(kExtensionPolicy1, kPolicyBool); |
| writer.AppendInteger(kExtensionPolicy2, kPolicyInt); |
| writer.AppendString(kExtensionPolicy3, kPolicyStr); |
| const std::vector<std::string> str_list = {"str1", "str2"}; |
| writer.AppendStringList(kExtensionPolicy4, str_list); |
| writer.WriteToFile(preg_1_path_); |
| |
| // Encode preg file into policy. |
| ExtensionPolicies policies; |
| EXPECT_TRUE(ParsePRegFilesIntoExtensionPolicy({preg_1_path_}, &policies, |
| false /* log_policy_values */)); |
| |
| const std::string expected_json = base::StringPrintf( |
| "{\"%s\":{\"%s\":1,\"%s\":%i,\"%s\":" |
| "\"%s\",\"%s\":{\"1\":\"%s\",\"2\":\"%s\"}}}", |
| kKeyMandatoryExtension, kExtensionPolicy1, kExtensionPolicy2, kPolicyInt, |
| kExtensionPolicy3, kPolicyStr, kExtensionPolicy4, str_list[0].c_str(), |
| str_list[1].c_str()); |
| |
| // Check that policy has the same values as we wrote to the file. |
| ASSERT_EQ(1, policies.size()); |
| EXPECT_EQ(kExtensionId, policies[0].id()); |
| EXPECT_EQ(expected_json, policies[0].json_data()); |
| } |
| |
| // Make sure invalid extension IDs are ignored. |
| TEST_F(PregPolicyEncoderTest, ExtensionPolicyIgnoresInvalidIds) { |
| // Create a preg file with several valid and invalid extension ids. |
| PRegExtensionPolicyWriter writer(kExtensionId); |
| writer.AppendBoolean(kExtensionPolicy1, kPolicyBool); |
| writer.SetExtensionId(kInvalidExtensionId); |
| writer.AppendBoolean(kExtensionPolicy1, kPolicyBool); |
| writer.SetExtensionId(kOtherExtensionId); |
| writer.AppendBoolean(kExtensionPolicy1, kPolicyBool); |
| writer.WriteToFile(preg_1_path_); |
| |
| // Encode preg file into policy. |
| ExtensionPolicies policies; |
| EXPECT_TRUE(ParsePRegFilesIntoExtensionPolicy({preg_1_path_}, &policies, |
| false /* log_policy_values */)); |
| |
| // Extensions with IDs kExtensionId and kOtherExtensionId should be in the |
| // output, kInvalidExtensionId shouldn't. |
| const std::string expected_json_0 = base::StringPrintf( |
| "{\"%s\":{\"%s\":1}}", kKeyMandatoryExtension, kExtensionPolicy1); |
| const std::string expected_json_1 = base::StringPrintf( |
| "{\"%s\":{\"%s\":1}}", kKeyMandatoryExtension, kExtensionPolicy1); |
| |
| ASSERT_EQ(2, policies.size()); |
| EXPECT_EQ(kOtherExtensionId, policies[0].id()); |
| EXPECT_EQ(expected_json_0, policies[0].json_data()); |
| EXPECT_EQ(kExtensionId, policies[1].id()); |
| EXPECT_EQ(expected_json_1, policies[1].json_data()); |
| } |
| |
| // Verify that recommended and mandatory policies get encoded separately. |
| TEST_F(PregPolicyEncoderTest, ExtensionPolicyRecommendedAndMandatory) { |
| // Create a preg file with several valid and invalid extension ids. |
| PRegExtensionPolicyWriter writer(kExtensionId); |
| writer.AppendBoolean(kExtensionPolicy1, kPolicyBool); |
| writer.AppendInteger(kExtensionPolicy2, kPolicyInt, POLICY_LEVEL_RECOMMENDED); |
| writer.WriteToFile(preg_1_path_); |
| |
| // Encode preg file into policy. |
| ExtensionPolicies policies; |
| EXPECT_TRUE(ParsePRegFilesIntoExtensionPolicy({preg_1_path_}, &policies, |
| false /* log_policy_values */)); |
| |
| // Extensions with IDs kExtensionId and kOtherExtensionId should be in the |
| // output, kInvalidExtensionId shouldn't. |
| const std::string expected_json = base::StringPrintf( |
| "{\"%s\":{\"%s\":1},\"%s\":{\"%s\":%i}}", kKeyMandatoryExtension, |
| kExtensionPolicy1, kKeyRecommended, kExtensionPolicy2, kPolicyInt); |
| |
| ASSERT_EQ(1, policies.size()); |
| EXPECT_EQ(kExtensionId, policies[0].id()); |
| EXPECT_EQ(expected_json, policies[0].json_data()); |
| } |
| |
| } // namespace policy |