blob: 7c913f07a5a54dd2f5cb9fa9460d70f9a01a00c4 [file] [log] [blame]
// Copyright 2019 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 "components/enterprise/browser/reporting/profile_report_generator.h"
#include <string>
#include "base/feature_list.h"
#include "base/json/json_reader.h"
#include "base/json/values_util.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/profiles/profile_attributes_init_params.h"
#include "chrome/browser/profiles/profile_attributes_storage.h"
#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "components/account_id/account_id.h"
#include "components/enterprise/browser/reporting/report_type.h"
#include "components/policy/core/common/mock_policy_service.h"
#include "components/policy/core/common/policy_map.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
#include "content/public/test/browser_task_environment.h"
#include "extensions/browser/pref_names.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_ANDROID)
#include "chrome/browser/enterprise/reporting/reporting_delegate_factory_android.h"
#else
#include "chrome/browser/enterprise/reporting/reporting_delegate_factory_desktop.h"
#endif // defined(OS_ANDROID)
using ::testing::NiceMock;
namespace em = enterprise_management;
namespace enterprise_reporting {
namespace {
constexpr char kProfile[] = "Default";
constexpr char16_t kProfile16[] = u"Profile";
constexpr char kIdleProfile[] = "IdleProfile";
constexpr char16_t kIdleProfile16[] = u"IdleProfile";
#if !defined(OS_ANDROID)
const int kMaxNumberOfExtensionRequest = 1000;
constexpr char kExtensionId[] = "abcdefghijklmnopabcdefghijklmnop";
constexpr char kExtensionId2[] = "abcdefghijklmnopabcdefghijklmnpo";
constexpr int kFakeTime = 123456;
constexpr char kJustification[] = "I really need to change my boring cursor.";
constexpr char kAllowedExtensionSettings[] = R"({
"abcdefghijklmnopabcdefghijklmnop" : {
"installation_mode": "allowed"
}
})";
constexpr char kBlockedExtensionSettings[] = R"({
"abcdefghijklmnopabcdefghijklmnop" : {
"installation_mode": "blocked"
}
})";
#endif // !defined(OS_ANDROID)
} // namespace
#if defined(OS_ANDROID)
typedef ReportingDelegateFactoryAndroid PlatformReportingDelegateFactory;
#else
typedef ReportingDelegateFactoryDesktop PlatformReportingDelegateFactory;
#endif // defined(OS_ANDROID)
class ProfileReportGeneratorTest : public ::testing::Test {
public:
ProfileReportGeneratorTest()
: generator_(&reporting_delegate_factory_),
profile_manager_(TestingBrowserProcess::GetGlobal()) {}
ProfileReportGeneratorTest(const ProfileReportGeneratorTest&) = delete;
ProfileReportGeneratorTest& operator=(const ProfileReportGeneratorTest&) =
delete;
~ProfileReportGeneratorTest() override = default;
void SetUp() override {
ASSERT_TRUE(profile_manager_.SetUp());
InitMockPolicyService();
InitPolicyMap();
profile_ = profile_manager_.CreateTestingProfile(
kProfile, {}, kProfile16, 0, {},
IdentityTestEnvironmentProfileAdaptor::
GetIdentityTestEnvironmentFactories(),
absl::nullopt, std::move(policy_service_));
}
void InitMockPolicyService() {
policy_service_ = std::make_unique<NiceMock<policy::MockPolicyService>>();
ON_CALL(*policy_service_.get(),
GetPolicies(::testing::Eq(policy::PolicyNamespace(
policy::POLICY_DOMAIN_CHROME, std::string()))))
.WillByDefault(::testing::ReturnRef(policy_map_));
}
void InitPolicyMap() {
policy_map_.Set("kPolicyName1", policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
base::Value(std::vector<base::Value>()), nullptr);
policy_map_.Set("kPolicyName2", policy::POLICY_LEVEL_RECOMMENDED,
policy::POLICY_SCOPE_MACHINE, policy::POLICY_SOURCE_MERGED,
base::Value(true), nullptr);
}
std::unique_ptr<em::ChromeUserProfileInfo> GenerateReport(
const base::FilePath& path,
const std::string& name) {
std::unique_ptr<em::ChromeUserProfileInfo> report =
generator_.MaybeGenerate(path, name, ReportType::kFull);
return report;
}
std::unique_ptr<em::ChromeUserProfileInfo> GenerateReport() {
auto report =
GenerateReport(profile()->GetPath(), profile()->GetProfileUserName());
EXPECT_TRUE(report);
EXPECT_EQ(profile()->GetProfileUserName(), report->name());
EXPECT_EQ(profile()->GetPath().AsUTF8Unsafe(), report->id());
EXPECT_TRUE(report->is_detail_available());
return report;
}
#if !defined(OS_ANDROID)
void SetExtensionToPendingList(const std::vector<std::string>& ids) {
std::unique_ptr<base::Value> id_values =
std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
for (const auto& id : ids) {
base::Value request_data(base::Value::Type::DICTIONARY);
request_data.SetKey(
extension_misc::kExtensionRequestTimestamp,
::base::TimeToValue(base::Time::FromJavaTime(kFakeTime)));
if (base::FeatureList::IsEnabled(
features::kExtensionWorkflowJustification)) {
request_data.SetKey(extension_misc::kExtensionWorkflowJustification,
base::Value(kJustification));
}
id_values->SetKey(id, std::move(request_data));
}
profile()->GetTestingPrefService()->SetUserPref(
prefs::kCloudExtensionRequestIds, std::move(id_values));
}
void SetExtensionSettings(const std::string& settings_string) {
absl::optional<base::Value> settings =
base::JSONReader::Read(settings_string);
ASSERT_TRUE(settings.has_value());
profile()->GetTestingPrefService()->SetManagedPref(
extensions::pref_names::kExtensionManagement,
base::Value::ToUniquePtrValue(std::move(*settings)));
}
#endif // !defined(OS_ANDROID)
TestingProfile* profile() { return profile_; }
TestingProfileManager* profile_manager() { return &profile_manager_; }
PlatformReportingDelegateFactory reporting_delegate_factory_;
ProfileReportGenerator generator_;
base::test::ScopedFeatureList feature_list_;
private:
content::BrowserTaskEnvironment task_environment_;
TestingProfileManager profile_manager_;
raw_ptr<TestingProfile> profile_;
std::unique_ptr<NiceMock<policy::MockPolicyService>> policy_service_;
policy::PolicyMap policy_map_;
};
TEST_F(ProfileReportGeneratorTest, ProfileNotActivated) {
const base::FilePath profile_path =
profile_manager()->profiles_dir().AppendASCII(kIdleProfile);
ProfileAttributesInitParams params;
params.profile_path = profile_path;
params.profile_name = kIdleProfile16;
profile_manager()->profile_attributes_storage()->AddProfile(
std::move(params));
std::unique_ptr<em::ChromeUserProfileInfo> response =
generator_.MaybeGenerate(profile_path, kIdleProfile, ReportType::kFull);
ASSERT_FALSE(response.get());
}
TEST_F(ProfileReportGeneratorTest, UnsignedInProfile) {
auto report = GenerateReport();
EXPECT_FALSE(report->has_chrome_signed_in_user());
}
TEST_F(ProfileReportGeneratorTest, SignedInProfile) {
IdentityTestEnvironmentProfileAdaptor identity_test_env_adaptor(profile());
auto expected_info =
identity_test_env_adaptor.identity_test_env()->SetPrimaryAccount(
"test@mail.com", signin::ConsentLevel::kSync);
auto report = GenerateReport();
EXPECT_TRUE(report->has_chrome_signed_in_user());
EXPECT_EQ(expected_info.email, report->chrome_signed_in_user().email());
EXPECT_EQ(expected_info.gaia,
report->chrome_signed_in_user().obfuscated_gaia_id());
}
TEST_F(ProfileReportGeneratorTest, ProfileIdObfuscate) {
auto report = generator_.MaybeGenerate(profile()->GetPath(),
profile()->GetProfileUserName(),
ReportType::kProfileReport);
ASSERT_TRUE(report);
EXPECT_EQ(profile()->GetProfileUserName(), report->name());
EXPECT_NE(profile()->GetPath().AsUTF8Unsafe(), report->id());
EXPECT_TRUE(report->is_detail_available());
auto report2 = generator_.MaybeGenerate(profile()->GetPath(),
profile()->GetProfileUserName(),
ReportType::kProfileReport);
// Profile id is obfuscated with `kProfileReport` type, but the obfuscated
// result is consistent.
EXPECT_EQ(report->id(), report2->id());
TestingProfile* another_profile =
profile_manager()->CreateTestingProfile("another_profile");
auto report3 = generator_.MaybeGenerate(another_profile->GetPath(),
another_profile->GetProfileUserName(),
ReportType::kProfileReport);
// Different profiles' id will be different even after obfuscation.
EXPECT_NE(report->id(), report3->id());
}
#if !defined(OS_ANDROID)
TEST_F(ProfileReportGeneratorTest, PoliciesDisabled) {
// Users' profile info is collected by default.
std::unique_ptr<em::ChromeUserProfileInfo> report = GenerateReport();
EXPECT_EQ(2, report->chrome_policies_size());
// Stop to collect profile info after |set_policies_enabled| is set as false.
generator_.set_policies_enabled(false);
report = GenerateReport();
EXPECT_EQ(0, report->chrome_policies_size());
// Start to collect profile info again after |set_policies_enabled| is set as
// true.
generator_.set_policies_enabled(true);
report = GenerateReport();
EXPECT_EQ(2, report->chrome_policies_size());
}
TEST_F(ProfileReportGeneratorTest, PendingRequest) {
profile()->GetTestingPrefService()->SetManagedPref(
prefs::kCloudExtensionRequestEnabled,
std::make_unique<base::Value>(true));
std::vector<std::string> ids = {kExtensionId};
SetExtensionToPendingList(ids);
auto report = GenerateReport();
ASSERT_EQ(1, report->extension_requests_size());
EXPECT_EQ(kExtensionId, report->extension_requests(0).id());
EXPECT_EQ(kFakeTime, report->extension_requests(0).request_timestamp());
EXPECT_EQ(std::string(), report->extension_requests(0).justification());
}
TEST_F(ProfileReportGeneratorTest, PendingRequest_Justification) {
feature_list_.InitAndEnableFeature(features::kExtensionWorkflowJustification);
profile()->GetTestingPrefService()->SetManagedPref(
prefs::kCloudExtensionRequestEnabled,
std::make_unique<base::Value>(true));
std::vector<std::string> ids = {kExtensionId};
SetExtensionToPendingList(ids);
auto report = GenerateReport();
ASSERT_EQ(1, report->extension_requests_size());
EXPECT_EQ(kExtensionId, report->extension_requests(0).id());
EXPECT_EQ(kFakeTime, report->extension_requests(0).request_timestamp());
EXPECT_EQ(kJustification, report->extension_requests(0).justification());
}
TEST_F(ProfileReportGeneratorTest, NoPendingRequestWhenItsDisabled) {
profile()->GetTestingPrefService()->SetManagedPref(
prefs::kCloudExtensionRequestEnabled,
std::make_unique<base::Value>(false));
std::vector<std::string> ids = {kExtensionId};
SetExtensionToPendingList(ids);
auto report = GenerateReport();
EXPECT_EQ(0, report->extension_requests_size());
}
TEST_F(ProfileReportGeneratorTest, FilterOutApprovedPendingRequest) {
profile()->GetTestingPrefService()->SetManagedPref(
prefs::kCloudExtensionRequestEnabled,
std::make_unique<base::Value>(true));
SetExtensionSettings(kAllowedExtensionSettings);
std::vector<std::string> ids = {kExtensionId, kExtensionId2};
SetExtensionToPendingList(ids);
auto report = GenerateReport();
ASSERT_EQ(1, report->extension_requests_size());
EXPECT_EQ(kExtensionId2, report->extension_requests(0).id());
}
TEST_F(ProfileReportGeneratorTest, FilterOutBlockedPendingRequest) {
profile()->GetTestingPrefService()->SetManagedPref(
prefs::kCloudExtensionRequestEnabled,
std::make_unique<base::Value>(true));
SetExtensionSettings(kBlockedExtensionSettings);
std::vector<std::string> ids = {kExtensionId, kExtensionId2};
SetExtensionToPendingList(ids);
auto report = GenerateReport();
ASSERT_EQ(1, report->extension_requests_size());
EXPECT_EQ(kExtensionId2, report->extension_requests(0).id());
}
TEST_F(ProfileReportGeneratorTest, TooManyRequests) {
profile()->GetTestingPrefService()->SetManagedPref(
prefs::kCloudExtensionRequestEnabled,
std::make_unique<base::Value>(true));
const int extension_request_count = kMaxNumberOfExtensionRequest;
std::vector<std::string> ids(extension_request_count);
for (int extension_id = 0; extension_id < extension_request_count;
extension_id += 1) {
ids[extension_id] = base::NumberToString(extension_id);
}
SetExtensionToPendingList(ids);
auto report = GenerateReport();
// At most 1000 requests will be uploaded.
EXPECT_EQ(kMaxNumberOfExtensionRequest, report->extension_requests_size());
// And the filter is stable.
auto report2 = GenerateReport();
for (int id = 0; id < kMaxNumberOfExtensionRequest; id += 1)
EXPECT_EQ(report->extension_requests(id).id(),
report2->extension_requests(id).id());
}
#endif // !defined(OS_ANDROID)
} // namespace enterprise_reporting