blob: 1e5da4ed6d8faac9154b853723ef3003a4bcc892 [file] [log] [blame]
// Copyright 2016 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 "chrome/browser/ash/arc/policy/arc_policy_bridge.h"
#include <memory>
#include <string>
#include <utility>
#include "ash/components/arc/arc_features.h"
#include "ash/components/arc/arc_prefs.h"
#include "ash/components/arc/enterprise/arc_data_snapshotd_manager.h"
#include "ash/components/arc/session/arc_bridge_service.h"
#include "ash/components/arc/session/arc_session_runner.h"
#include "ash/components/arc/test/connection_holder_util.h"
#include "ash/components/arc/test/fake_arc_session.h"
#include "ash/components/arc/test/fake_policy_instance.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/json/json_reader.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/strings/strcat.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/browser/ash/arc/enterprise/arc_data_snapshotd_delegate.h"
#include "chrome/browser/ash/arc/enterprise/cert_store/cert_store_service.h"
#include "chrome/browser/ash/arc/session/arc_session_manager.h"
#include "chrome/browser/ash/arc/test/test_arc_session_manager.h"
#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
#include "chrome/browser/policy/developer_tools_policy_handler.h"
#include "chrome/browser/supervised_user/supervised_user_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 "chromeos/dbus/concierge/concierge_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/upstart/fake_upstart_client.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/policy/core/common/mock_policy_service.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/core/common/policy_namespace.h"
#include "components/policy/core/common/policy_types.h"
#include "components/policy/core/common/remote_commands/remote_commands_queue.h"
#include "components/policy/policy_constants.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "components/user_manager/scoped_user_manager.h"
#include "content/public/test/browser_task_environment.h"
#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using testing::Mock;
using testing::ReturnRef;
namespace arc {
namespace {
constexpr char kFakeONC[] =
"{\"NetworkConfigurations\":["
"{\"GUID\":\"{485d6076-dd44-6b6d-69787465725f5040}\","
"\"Type\":\"WiFi\","
"\"Name\":\"My WiFi Network\","
"\"WiFi\":{"
"\"HexSSID\":\"737369642D6E6F6E65\"," // "ssid-none"
"\"Security\":\"None\"}"
"}"
"],"
"\"GlobalNetworkConfiguration\":{"
"\"AllowOnlyPolicyNetworksToAutoconnect\":true,"
"},"
"\"Certificates\":["
"{ \"GUID\":\"{f998f760-272b-6939-4c2beffe428697ac}\","
"\"PKCS12\":\"abc\","
"\"Type\":\"Client\"},"
"{\"Type\":\"Authority\","
"\"TrustBits\":[\"Web\"],"
"\"X509\":\"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ"
"1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpc"
"yBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCB"
"pbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZ"
"GdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4"
"=\","
"\"GUID\":\"{00f79111-51e0-e6e0-76b3b55450d80a1b}\"}"
"]}";
constexpr char kPolicyCompliantResponse[] = "{ \"policyCompliant\": true }";
constexpr char kFakeCertName[] = "cert_name";
constexpr char kRequiredKeyPairsEmpty[] = "\"requiredKeyPairs\":[]";
constexpr char kRequiredKeyPairsFormat[] =
"\"requiredKeyPairs\":[{\"alias\":\"%s\"}]";
constexpr char kChoosePrivateKeyRulesFormat[] =
"\"choosePrivateKeyRules\":["
"{\"packageNames\":[\"%s\"],"
"\"privateKeyAlias\":\"%s\"}]";
constexpr char kSupervisedUserPlayStoreModePolicySetting[] =
"\"playStoreMode\":\"SUPERVISED\"";
constexpr char kPlayStoreManagedRestriction[] =
"\"managedConfiguration\":{"
"\"allowed_accounts\":\"%s\"},";
constexpr char kApplicationsPolicy[] =
"\"applications\":["
"{"
"\"disabled\":false,"
"\"installType\":\"OPTIONAL\","
"%s"
"\"packageName\":\"com.android.vending\""
"},"
"{"
"\"disabled\":false,"
"\"installType\":\"OPTIONAL\","
"\"packageName\":\"com.a.b\""
"}]";
constexpr char kTestUserEmail[] = "user@gmail.com";
constexpr char kChromeAppId[] = "chromeappid";
constexpr char kAndroidAppId[] = "android.app.id";
std::string GetSupervisedUserPlayStoreApplicationPolicy(
bool include_playstore_restriction,
const std::string& user_email) {
std::string restriction_used =
include_playstore_restriction
? base::StringPrintf(kPlayStoreManagedRestriction, user_email.c_str())
: "";
return base::StringPrintf(kApplicationsPolicy, restriction_used.c_str());
}
void AddKeyPermissionForAppId(base::Value* key_permissions,
const std::string& app_id,
bool allowed) {
base::Value cert_key_permission(base::Value::Type::DICTIONARY);
cert_key_permission.SetKey("allowCorporateKeyUsage", base::Value(allowed));
key_permissions->SetKey(app_id, std::move(cert_key_permission));
}
MATCHER_P(ValueEquals, expected, "value matches") {
return *expected == *arg;
}
class MockArcPolicyBridgeObserver : public ArcPolicyBridge::Observer {
public:
MockArcPolicyBridgeObserver() = default;
MockArcPolicyBridgeObserver(const MockArcPolicyBridgeObserver&) = delete;
MockArcPolicyBridgeObserver& operator=(const MockArcPolicyBridgeObserver&) =
delete;
~MockArcPolicyBridgeObserver() override = default;
MOCK_METHOD1(OnPolicySent, void(const std::string&));
MOCK_METHOD1(OnComplianceReportReceived, void(const base::Value*));
};
// Helper class to define callbacks that verify that they were run.
// Wraps a bool initially set to |false| and verifies that it's been set to
// |true| before destruction.
class CheckedBoolean {
public:
CheckedBoolean() {}
CheckedBoolean(const CheckedBoolean&) = delete;
CheckedBoolean& operator=(const CheckedBoolean&) = delete;
~CheckedBoolean() { EXPECT_TRUE(value_); }
void set_value(bool value) { value_ = value; }
private:
bool value_ = false;
};
void ExpectString(std::unique_ptr<CheckedBoolean> was_run,
const std::string& expected,
const std::string& received) {
EXPECT_EQ(expected, received);
was_run->set_value(true);
}
void ExpectStringWithClosure(base::OnceClosure quit_closure,
std::unique_ptr<CheckedBoolean> was_run,
const std::string& expected,
const std::string& received) {
EXPECT_EQ(expected, received);
was_run->set_value(true);
std::move(quit_closure).Run();
}
arc::ArcPolicyBridge::GetPoliciesCallback PolicyStringCallback(
const std::string& expected) {
auto was_run = std::make_unique<CheckedBoolean>();
return base::BindOnce(&ExpectString, std::move(was_run), expected);
}
arc::ArcPolicyBridge::ReportComplianceCallback PolicyComplianceCallback(
base::OnceClosure quit_closure,
const std::string& expected) {
auto was_run = std::make_unique<CheckedBoolean>();
return base::BindOnce(&ExpectStringWithClosure, std::move(quit_closure),
std::move(was_run), expected);
}
} // namespace
class ArcPolicyBridgeTestBase {
public:
ArcPolicyBridgeTestBase() = default;
ArcPolicyBridgeTestBase(const ArcPolicyBridgeTestBase&) = delete;
ArcPolicyBridgeTestBase& operator=(const ArcPolicyBridgeTestBase&) = delete;
void DoSetUp(bool is_affiliated) {
bridge_service_ = std::make_unique<ArcBridgeService>();
EXPECT_CALL(policy_service_,
GetPolicies(policy::PolicyNamespace(
policy::POLICY_DOMAIN_CHROME, std::string())))
.WillRepeatedly(ReturnRef(policy_map_));
EXPECT_CALL(policy_service_, AddObserver(policy::POLICY_DOMAIN_CHROME, _))
.Times(1);
EXPECT_CALL(policy_service_,
RemoveObserver(policy::POLICY_DOMAIN_CHROME, _))
.Times(1);
// Setting up user profile for ReportCompliance() tests.
auto* const fake_user_manager = new ash::FakeChromeUserManager();
user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
base::WrapUnique(fake_user_manager));
const AccountId account_id(
AccountId::FromUserEmailGaiaId(kTestUserEmail, "1111111111"));
fake_user_manager->AddUserWithAffiliation(account_id, is_affiliated);
fake_user_manager->LoginUser(account_id);
testing_profile_manager_ = std::make_unique<TestingProfileManager>(
TestingBrowserProcess::GetGlobal());
ASSERT_TRUE(testing_profile_manager_->SetUp());
profile_ = testing_profile_manager_->CreateTestingProfile(kTestUserEmail);
ASSERT_TRUE(profile_);
cert_store_service_ = GetCertStoreService();
// TODO(hidehiko): Use Singleton instance tied to BrowserContext.
policy_bridge_ = std::make_unique<ArcPolicyBridge>(
profile_, bridge_service_.get(), &policy_service_);
policy_bridge_->OverrideIsManagedForTesting(true);
policy_bridge_->AddObserver(&observer_);
instance_guid_ = policy_bridge_->GetInstanceGuidForTesting();
policy_instance_ = std::make_unique<FakePolicyInstance>();
bridge_service_->policy()->SetInstance(policy_instance_.get());
WaitForInstanceReady(bridge_service_->policy());
}
void DoTearDown() {
bridge_service_->policy()->CloseInstance(policy_instance_.get());
policy_instance_.reset();
policy_bridge_->RemoveObserver(&observer_);
testing_profile_manager_.reset();
}
protected:
void GetPoliciesAndVerifyResult(const std::string& expected_policy_json) {
Mock::VerifyAndClearExpectations(&observer_);
EXPECT_CALL(observer_, OnPolicySent(expected_policy_json));
policy_bridge()->GetPolicies(PolicyStringCallback(expected_policy_json));
EXPECT_EQ(expected_policy_json,
policy_bridge()->get_arc_policy_for_reporting());
Mock::VerifyAndClearExpectations(&observer_);
}
void ReportComplianceAndVerifyObserverCallback(
const std::string& compliance_report) {
Mock::VerifyAndClearExpectations(&observer_);
std::unique_ptr<base::Value> compliance_report_value =
base::JSONReader::ReadDeprecated(compliance_report);
if (compliance_report_value && compliance_report_value->is_dict()) {
EXPECT_CALL(observer_, OnComplianceReportReceived(
ValueEquals(compliance_report_value.get())));
} else {
EXPECT_CALL(observer_, OnComplianceReportReceived(_)).Times(0);
}
policy_bridge()->ReportCompliance(
compliance_report, PolicyComplianceCallback(run_loop().QuitClosure(),
kPolicyCompliantResponse));
run_loop().Run();
Mock::VerifyAndClearExpectations(&observer_);
if (compliance_report_value) {
std::unique_ptr<base::Value> saved_compliance_report_value =
base::JSONReader::ReadDeprecated(
policy_bridge()->get_arc_policy_compliance_report());
ASSERT_TRUE(saved_compliance_report_value);
EXPECT_TRUE(
compliance_report_value->Equals(saved_compliance_report_value.get()));
} else {
EXPECT_TRUE(policy_bridge()->get_arc_policy_compliance_report().empty());
}
}
// Specifies a testing factory for CertStoreService and returns instance.
// Returns nullptr by default.
// Override if the test wants to use a real cert store service.
virtual CertStoreService* GetCertStoreService() {
return static_cast<CertStoreService*>(
CertStoreService::GetFactory()->SetTestingFactoryAndUse(
profile(),
base::BindRepeating(
[](content::BrowserContext* profile)
-> std::unique_ptr<KeyedService> { return nullptr; })));
}
ArcPolicyBridge* policy_bridge() { return policy_bridge_.get(); }
const std::string& instance_guid() { return instance_guid_; }
FakePolicyInstance* policy_instance() { return policy_instance_.get(); }
policy::PolicyMap& policy_map() { return policy_map_; }
base::RunLoop& run_loop() { return run_loop_; }
TestingProfile* profile() { return profile_; }
ArcBridgeService* bridge_service() { return bridge_service_.get(); }
CertStoreService* cert_store_service() { return cert_store_service_; }
private:
content::BrowserTaskEnvironment task_environment_;
data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
std::unique_ptr<TestingProfileManager> testing_profile_manager_;
base::RunLoop run_loop_;
TestingProfile* profile_;
std::unique_ptr<ArcBridgeService> bridge_service_;
CertStoreService* cert_store_service_; // Not owned.
std::unique_ptr<ArcPolicyBridge> policy_bridge_;
std::string instance_guid_;
MockArcPolicyBridgeObserver observer_;
// Always keep policy_instance_ below bridge_service_, so that
// policy_instance_ is destructed first. It needs to remove itself as
// observer.
std::unique_ptr<FakePolicyInstance> policy_instance_;
policy::PolicyMap policy_map_;
policy::MockPolicyService policy_service_;
};
class ArcPolicyBridgeTest : public ArcPolicyBridgeTestBase,
public testing::Test {
public:
void SetUp() override { DoSetUp(true /* affiliated */); }
void TearDown() override { DoTearDown(); }
};
class ArcPolicyBridgeAffiliatedTest : public ArcPolicyBridgeTestBase,
public testing::TestWithParam<bool> {
public:
ArcPolicyBridgeAffiliatedTest() : is_affiliated_(GetParam()) {}
void SetUp() override { DoSetUp(is_affiliated_); }
void TearDown() override { DoTearDown(); }
protected:
void GetPoliciesAndVerifyResultWithAffiliation(
const std::string& expected_policy_json_affiliated,
const std::string& expected_policy_json_not_affiliated) {
if (is_affiliated_)
GetPoliciesAndVerifyResult(expected_policy_json_affiliated);
else
GetPoliciesAndVerifyResult(expected_policy_json_not_affiliated);
}
const bool is_affiliated_;
};
// Tests required key pair policy.
class ArcPolicyBridgeCertStoreTest : public ArcPolicyBridgeTest {
protected:
CertStoreService* GetCertStoreService() override {
return static_cast<CertStoreService*>(
CertStoreService::GetFactory()->SetTestingFactoryAndUse(
profile(),
base::BindRepeating([](content::BrowserContext* profile)
-> std::unique_ptr<KeyedService> {
return std::make_unique<CertStoreService>(nullptr);
})));
}
};
TEST_F(ArcPolicyBridgeTest, UnmanagedTest) {
policy_bridge()->OverrideIsManagedForTesting(false);
GetPoliciesAndVerifyResult("");
}
TEST_F(ArcPolicyBridgeTest, EmptyPolicyTest) {
// No policy is set, result should be empty except for the instance GUID.
GetPoliciesAndVerifyResult("{\"apkCacheEnabled\":true,\"guid\":\"" +
instance_guid() + "\"}");
}
TEST_F(ArcPolicyBridgeTest, DISABLED_ArcPolicyTest) {
policy_map().Set(
policy::key::kArcPolicy, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
base::Value("{\"applications\":"
"[{\"packageName\":\"com.google.android.apps.youtube.kids\","
"\"installType\":\"REQUIRED\","
"\"lockTaskAllowed\":false,"
"\"permissionGrants\":[]"
"}],"
"\"defaultPermissionPolicy\":\"GRANT\""
"}"),
nullptr);
GetPoliciesAndVerifyResult(
"\"apkCacheEnabled\":true,"
"{\"applications\":"
"[{\"installType\":\"REQUIRED\","
"\"lockTaskAllowed\":false,"
"\"packageName\":\"com.google.android.apps.youtube.kids\","
"\"permissionGrants\":[]"
"}],"
"\"defaultPermissionPolicy\":\"GRANT\","
"\"guid\":\"" +
instance_guid() + "\"}");
}
TEST_F(ArcPolicyBridgeTest, HompageLocationTest) {
// This policy will not be passed on, result should be empty except for the
// instance GUID.
policy_map().Set(policy::key::kHomepageLocation,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD,
base::Value("http://chromium.org"), nullptr);
GetPoliciesAndVerifyResult("{\"apkCacheEnabled\":true,\"guid\":\"" +
instance_guid() + "\"}");
}
TEST_F(ArcPolicyBridgeTest, DisableScreenshotsTest) {
policy_map().Set(policy::key::kDisableScreenshots,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD, base::Value(true), nullptr);
GetPoliciesAndVerifyResult("{\"apkCacheEnabled\":true,\"guid\":\"" +
instance_guid() +
"\",\"screenCaptureDisabled\":true}");
}
TEST_F(ArcPolicyBridgeTest, DisablePrintingTest) {
policy_map().Set(policy::key::kPrintingEnabled,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD, base::Value(false), nullptr);
GetPoliciesAndVerifyResult("{\"apkCacheEnabled\":true,\"guid\":\"" +
instance_guid() + "\",\"printingDisabled\":true}");
}
TEST_F(ArcPolicyBridgeTest, VideoCaptureAllowedTest) {
policy_map().Set(policy::key::kVideoCaptureAllowed,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD, base::Value(false), nullptr);
GetPoliciesAndVerifyResult(
"{\"apkCacheEnabled\":true,\"cameraDisabled\":true,\"guid\":\"" +
instance_guid() + "\"}");
}
TEST_F(ArcPolicyBridgeTest, AudioCaptureAllowedTest) {
policy_map().Set(policy::key::kAudioCaptureAllowed,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD, base::Value(false), nullptr);
GetPoliciesAndVerifyResult("{\"apkCacheEnabled\":true,\"guid\":\"" +
instance_guid() +
"\",\"unmuteMicrophoneDisabled\":true}");
}
TEST_F(ArcPolicyBridgeTest, DefaultGeolocationSettingTest) {
policy_map().Set(policy::key::kDefaultGeolocationSetting,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD, base::Value(1), nullptr);
GetPoliciesAndVerifyResult("{\"apkCacheEnabled\":true,\"guid\":\"" +
instance_guid() +
"\",\"shareLocationDisabled\":false}");
policy_map().Set(policy::key::kDefaultGeolocationSetting,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD, base::Value(2), nullptr);
GetPoliciesAndVerifyResult("{\"apkCacheEnabled\":true,\"guid\":\"" +
instance_guid() +
"\",\"shareLocationDisabled\":true}");
policy_map().Set(policy::key::kDefaultGeolocationSetting,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD, base::Value(3), nullptr);
GetPoliciesAndVerifyResult("{\"apkCacheEnabled\":true,\"guid\":\"" +
instance_guid() +
"\",\"shareLocationDisabled\":false}");
}
TEST_F(ArcPolicyBridgeTest, ExternalStorageDisabledTest) {
policy_map().Set(policy::key::kExternalStorageDisabled,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD, base::Value(true), nullptr);
GetPoliciesAndVerifyResult("{\"apkCacheEnabled\":true,\"guid\":\"" +
instance_guid() +
"\",\"mountPhysicalMediaDisabled\":true}");
}
TEST_F(ArcPolicyBridgeTest, WallpaperImageSetTest) {
base::DictionaryValue dict;
dict.SetString("url", "https://example.com/wallpaper.jpg");
dict.SetString("hash", "somehash");
policy_map().Set(policy::key::kWallpaperImage, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
dict.Clone(), nullptr);
GetPoliciesAndVerifyResult("{\"apkCacheEnabled\":true,\"guid\":\"" +
instance_guid() +
"\",\"setWallpaperDisabled\":true}");
}
TEST_F(ArcPolicyBridgeTest, WallpaperImageSet_NotCompletePolicyTest) {
base::DictionaryValue dict;
dict.SetString("url", "https://example.com/wallpaper.jpg");
// "hash" attribute is missing, so the policy shouldn't be set
policy_map().Set(policy::key::kWallpaperImage, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
dict.Clone(), nullptr);
GetPoliciesAndVerifyResult("{\"apkCacheEnabled\":true,\"guid\":\"" +
instance_guid() + "\"}");
}
TEST_F(ArcPolicyBridgeTest, CaCertificateTest) {
// Enable CA certificates sync.
policy_map().Set(policy::key::kArcCertificatesSyncMode,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD,
base::Value(ArcCertsSyncMode::COPY_CA_CERTS), nullptr);
policy_map().Set(policy::key::kOpenNetworkConfiguration,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD, base::Value(kFakeONC), nullptr);
GetPoliciesAndVerifyResult(
"{\"apkCacheEnabled\":true,"
"\"caCerts\":"
"[{\"X509\":\"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24"
"sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGl"
"jaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGV"
"saWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Y"
"ga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCB"
"wbGVhc3VyZS4=\"}"
"],"
"\"credentialsConfigDisabled\":true,"
"\"guid\":\"" +
instance_guid() + "\"}");
// Disable CA certificates sync.
policy_map().Set(policy::key::kArcCertificatesSyncMode,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD,
base::Value(ArcCertsSyncMode::SYNC_DISABLED), nullptr);
GetPoliciesAndVerifyResult("{\"apkCacheEnabled\":true,\"guid\":\"" +
instance_guid() + "\"}");
}
TEST_F(ArcPolicyBridgeTest, DeveloperToolsPolicyAllowedTest) {
profile()->GetTestingPrefService()->SetManagedPref(
::prefs::kDevToolsAvailability,
std::make_unique<base::Value>(static_cast<int>(
policy::DeveloperToolsPolicyHandler::Availability::kAllowed)));
GetPoliciesAndVerifyResult(
"{\"apkCacheEnabled\":true,\"debuggingFeaturesDisabled\":false,\"guid\":"
"\"" +
instance_guid() + "\"}");
}
TEST_F(ArcPolicyBridgeTest,
DeveloperToolsPolicyDisallowedForForceInstalledExtensionsTest) {
profile()->GetTestingPrefService()->SetManagedPref(
::prefs::kDevToolsAvailability,
std::make_unique<base::Value>(
static_cast<int>(policy::DeveloperToolsPolicyHandler::Availability::
kDisallowedForForceInstalledExtensions)));
GetPoliciesAndVerifyResult(
"{\"apkCacheEnabled\":true,\"debuggingFeaturesDisabled\":false,\"guid\":"
"\"" +
instance_guid() + "\"}");
}
TEST_F(ArcPolicyBridgeTest, DeveloperToolsPolicyDisallowedTest) {
profile()->GetTestingPrefService()->SetManagedPref(
::prefs::kDevToolsAvailability,
std::make_unique<base::Value>(static_cast<int>(
policy::DeveloperToolsPolicyHandler::Availability::kDisallowed)));
GetPoliciesAndVerifyResult(
"{\"apkCacheEnabled\":true,\"debuggingFeaturesDisabled\":true,\"guid\":"
"\"" +
instance_guid() + "\"}");
}
TEST_F(ArcPolicyBridgeTest, MultiplePoliciesTest) {
policy_map().Set(
policy::key::kArcPolicy, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
base::Value("{\"applications\":"
"[{\"packageName\":\"com.google.android.apps.youtube.kids\","
"\"installType\":\"REQUIRED\","
"\"lockTaskAllowed\":false,"
"\"permissionGrants\":[]"
"}],"
"\"defaultPermissionPolicy\":\"GRANT\"}"),
nullptr);
policy_map().Set(policy::key::kHomepageLocation,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD,
base::Value("http://chromium.org"), nullptr);
policy_map().Set(policy::key::kVideoCaptureAllowed,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD, base::Value(false), nullptr);
GetPoliciesAndVerifyResult(
"{\"apkCacheEnabled\":true,\"applications\":"
"[{\"installType\":\"REQUIRED\","
"\"lockTaskAllowed\":false,"
"\"packageName\":\"com.google.android.apps.youtube.kids\","
"\"permissionGrants\":[]"
"}],"
"\"cameraDisabled\":true,"
"\"defaultPermissionPolicy\":\"GRANT\","
"\"guid\":\"" +
instance_guid() + "\"}");
}
TEST_F(ArcPolicyBridgeTest, EmptyReportComplianceTest) {
EXPECT_FALSE(
profile()->GetPrefs()->GetBoolean(prefs::kArcPolicyComplianceReported));
ReportComplianceAndVerifyObserverCallback("{}");
EXPECT_TRUE(
profile()->GetPrefs()->GetBoolean(prefs::kArcPolicyComplianceReported));
}
TEST_F(ArcPolicyBridgeTest, ParsableReportComplianceTest) {
EXPECT_FALSE(
profile()->GetPrefs()->GetBoolean(prefs::kArcPolicyComplianceReported));
ReportComplianceAndVerifyObserverCallback("{\"nonComplianceDetails\" : []}");
EXPECT_TRUE(
profile()->GetPrefs()->GetBoolean(prefs::kArcPolicyComplianceReported));
}
TEST_F(ArcPolicyBridgeTest, NonParsableReportComplianceTest) {
EXPECT_FALSE(
profile()->GetPrefs()->GetBoolean(prefs::kArcPolicyComplianceReported));
ReportComplianceAndVerifyObserverCallback("\"nonComplianceDetails\" : [}");
EXPECT_FALSE(
profile()->GetPrefs()->GetBoolean(prefs::kArcPolicyComplianceReported));
}
TEST_F(ArcPolicyBridgeTest, ReportComplianceTest_WithNonCompliantDetails) {
EXPECT_FALSE(
profile()->GetPrefs()->GetBoolean(prefs::kArcPolicyComplianceReported));
ReportComplianceAndVerifyObserverCallback(
"{\"nonComplianceDetails\" : "
"[{\"fieldPath\":\"\",\"nonComplianceReason\":0,\"packageName\":\"\","
"\"settingName\":\"someSetting\",\"cachedSize\":-1},"
"{\"cachedSize\":-1,\"fieldPath\":\"\",\"nonComplianceReason\":6,"
"\"packageName\":\"\",\"settingName\":\"guid\"}]}");
EXPECT_TRUE(
profile()->GetPrefs()->GetBoolean(prefs::kArcPolicyComplianceReported));
}
// This and the following test send the policies through a mojo connection
// between a PolicyInstance and the PolicyBridge.
TEST_F(ArcPolicyBridgeTest, PolicyInstanceUnmanagedTest) {
policy_bridge()->OverrideIsManagedForTesting(false);
GetPoliciesAndVerifyResult("");
}
TEST_F(ArcPolicyBridgeTest, PolicyInstanceManagedTest) {
GetPoliciesAndVerifyResult("{\"apkCacheEnabled\":true,\"guid\":\"" +
instance_guid() + "\"}");
}
TEST_F(ArcPolicyBridgeTest, VpnConfigAllowedTest) {
policy_map().Set(policy::key::kVpnConfigAllowed,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD, base::Value(false), nullptr);
GetPoliciesAndVerifyResult("{\"apkCacheEnabled\":true,\"guid\":\"" +
instance_guid() +
"\",\"vpnConfigDisabled\":true}");
}
TEST_F(ArcPolicyBridgeTest, ManualChildUserPoliciesSet) {
// Mark profile as supervised user.
profile()->SetSupervisedUserId(::supervised_users::kChildAccountSUID);
EXPECT_TRUE(profile()->IsChild());
policy_map().Set(policy::key::kArcPolicy, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
base::Value("{}"), /* external_data_fetcher */ nullptr);
// Applications policy is not present so only playStoreMode policy is set.
GetPoliciesAndVerifyResult(
base::StrCat({"{\"apkCacheEnabled\":true,\"guid\":\"", instance_guid(),
"\",", kSupervisedUserPlayStoreModePolicySetting, "}"}));
// ARC policy with applications policy:
// The managedConfiguration for Play Store should be set in this case.
// PlayStoreMode policy should also be set in this case.
const std::string arc_policy =
base::StrCat({"{",
GetSupervisedUserPlayStoreApplicationPolicy(
/* include_playstore_restriction */ false, ""),
"}"});
policy_map().Set(policy::key::kArcPolicy, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
base::Value(arc_policy),
/* external_data_fetcher */ nullptr);
const std::string expected_policy_result = base::StrCat(
{"{\"apkCacheEnabled\":true,",
GetSupervisedUserPlayStoreApplicationPolicy(
/* include_playstore_restriction */ true, kTestUserEmail),
",\"guid\":\"", instance_guid(), "\",",
kSupervisedUserPlayStoreModePolicySetting, "}"});
GetPoliciesAndVerifyResult(expected_policy_result);
}
// Test that required and force-installed apps get disabled during ARC data
// snapshot update.
TEST_F(ArcPolicyBridgeTest, DisableAppsInSnapshot) {
constexpr char kDisabledApplicationsPolicyFormat[] =
"\"applications\":["
"{"
"\"disabled\":%s,"
"\"installType\":\"REQUIRED\","
"\"packageName\":\"com.android.vending\""
"},"
"{"
"\"disabled\":%s,"
"\"installType\":\"FORCE_INSTALLED\","
"\"packageName\":\"com.force.installed\""
"},"
"{"
"\"disabled\":%s,"
"\"installType\":\"OPTIONAL\","
"\"packageName\":\"com.optional\""
"}],"
"\"defaultPermissionPolicy\":\"GRANT\"";
constexpr char kFalse[] = "false";
constexpr char kTrue[] = "true";
chromeos::DBusThreadManager::Initialize();
chromeos::ConciergeClient::InitializeFake(/*fake_cicerone_client=*/nullptr);
auto upstart_client = std::make_unique<chromeos::FakeUpstartClient>();
arc::prefs::RegisterLocalStatePrefs(
profile()->GetTestingPrefService()->registry());
auto arc_session_manager =
CreateTestArcSessionManager(std::make_unique<ArcSessionRunner>(
base::BindRepeating(FakeArcSession::Create)));
auto manager = std::make_unique<arc::data_snapshotd::ArcDataSnapshotdManager>(
profile()->GetTestingPrefService(),
std::make_unique<arc::data_snapshotd::ArcDataSnapshotdDelegate>(),
base::DoNothing());
EXPECT_TRUE(arc::data_snapshotd::ArcDataSnapshotdManager::Get());
manager->set_state_for_testing(
arc::data_snapshotd::ArcDataSnapshotdManager::State::kMgsLaunched);
EXPECT_TRUE(manager->IsSnapshotInProgress());
policy_map().Set(policy::key::kArcPolicy, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
base::Value(base::StrCat(
{"{",
base::StringPrintf(kDisabledApplicationsPolicyFormat,
kFalse, kFalse, kFalse),
"}"})),
nullptr);
GetPoliciesAndVerifyResult(base::StrCat(
{"{\"apkCacheEnabled\":true,",
base::StringPrintf(kDisabledApplicationsPolicyFormat, kTrue, kTrue,
kFalse),
",\"guid\":\"", instance_guid(), "\",\"resetAndroidIdEnabled\":true}"}));
manager.reset();
upstart_client.reset();
arc_session_manager.reset();
chromeos::ConciergeClient::Shutdown();
chromeos::DBusThreadManager::Shutdown();
}
TEST_P(ArcPolicyBridgeAffiliatedTest, ApkCacheEnabledTest) {
const std::string expected_apk_cache_enabled_result(
"{\"apkCacheEnabled\":true,\"guid\":\"" + instance_guid() + "\"}");
const std::string expected_apk_cache_disabled_result(
"{\"apkCacheEnabled\":false,\"guid\":\"" + instance_guid() + "\"}");
const std::string arc_apk_cache_enabled_policy("{\"apkCacheEnabled\":true}");
policy_map().Set(policy::key::kArcPolicy, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
base::Value(arc_apk_cache_enabled_policy), nullptr);
GetPoliciesAndVerifyResultWithAffiliation(
/* expected_policy_json_affiliated */ expected_apk_cache_enabled_result,
/* expected_policy_json_not_affiliated */
expected_apk_cache_disabled_result);
const std::string arc_apk_cache_disabled_policy(
"{\"apkCacheEnabled\":false}");
policy_map().Set(policy::key::kArcPolicy, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
base::Value(arc_apk_cache_disabled_policy), nullptr);
GetPoliciesAndVerifyResultWithAffiliation(
/* expected_policy_json_affiliated */ expected_apk_cache_enabled_result,
/* expected_policy_json_not_affiliated */
expected_apk_cache_disabled_result);
const std::string arc_apk_cache_no_policy("{}");
policy_map().Set(policy::key::kArcPolicy, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
base::Value(arc_apk_cache_no_policy), nullptr);
GetPoliciesAndVerifyResultWithAffiliation(
/* expected_policy_json_affiliated */ expected_apk_cache_enabled_result,
/* expected_policy_json_not_affiliated */
expected_apk_cache_disabled_result);
}
// Boolean parameter means if user is affiliated on the device. Affiliated
// users belong to the domain that owns the device.
// Affiliated user should always have enabled APK cache; not affiliated user
// should always have it disabled.
INSTANTIATE_TEST_SUITE_P(ArcPolicyBridgeAffiliatedTestInstance,
ArcPolicyBridgeAffiliatedTest,
testing::Bool());
// Tests that if cert store service is non-null, the required key pair policy is
// set to the required certificate list.
TEST_F(ArcPolicyBridgeCertStoreTest, RequiredKeyPairsBasicTest) {
// One certificate is required to be installed.
cert_store_service()->set_required_cert_names_for_testing({kFakeCertName});
GetPoliciesAndVerifyResult(base::StrCat(
{"{\"apkCacheEnabled\":true,\"guid\":\"", instance_guid(), "\",",
base::StringPrintf(kRequiredKeyPairsFormat, kFakeCertName), "}"}));
// An empty list is required to be installed.
cert_store_service()->set_required_cert_names_for_testing({});
GetPoliciesAndVerifyResult(
base::StrCat({"{\"apkCacheEnabled\":true,\"guid\":\"", instance_guid(),
"\",", kRequiredKeyPairsEmpty, "}"}));
}
// Tests that if cert store service is non-null, corporate usage key exists and
// available to ARC app, ChoosePrivateKeyRules policy is propagated correctly.
TEST_F(ArcPolicyBridgeCertStoreTest, KeyPermissionsBasicTest) {
EXPECT_TRUE(cert_store_service());
// One certificate is required to be installed.
cert_store_service()->set_required_cert_names_for_testing({kFakeCertName});
base::Value key_permissions(base::Value::Type::DICTIONARY);
AddKeyPermissionForAppId(&key_permissions, kAndroidAppId, true /* allowed */);
AddKeyPermissionForAppId(&key_permissions, kChromeAppId, true /* allowed */);
policy_map().Set(policy::key::kKeyPermissions, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
std::move(key_permissions),
/* external_data_fetcher */ nullptr);
GetPoliciesAndVerifyResult(base::StrCat(
{"{\"apkCacheEnabled\":true,",
base::StringPrintf(kChoosePrivateKeyRulesFormat, kAndroidAppId,
kFakeCertName),
",\"guid\":\"", instance_guid(),
"\",\"privateKeySelectionEnabled\":true,",
base::StringPrintf(kRequiredKeyPairsFormat, kFakeCertName), "}"}));
}
// Tests that if cert store service is non-null, corporate usage key exists and
// not to any ARC apps, ChoosePrivateKeyRules policy is not set.
TEST_F(ArcPolicyBridgeCertStoreTest, KeyPermissionsEmptyTest) {
base::Value key_permissions(base::Value::Type::DICTIONARY);
AddKeyPermissionForAppId(&key_permissions, kAndroidAppId,
false /* allowed */);
AddKeyPermissionForAppId(&key_permissions, kChromeAppId, true /* allowed */);
// One certificate is required to be installed.
cert_store_service()->set_required_cert_names_for_testing({kFakeCertName});
policy_map().Set(policy::key::kKeyPermissions, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
std::move(key_permissions),
/* external_data_fetcher */ nullptr);
GetPoliciesAndVerifyResult(base::StrCat(
{"{\"apkCacheEnabled\":true,\"guid\":\"", instance_guid(), "\",",
base::StringPrintf(kRequiredKeyPairsFormat, kFakeCertName), "}"}));
}
// Tests that if cert store service is non-null, corporate usage keys do not
// exist, but in theory are available to ARC apps, ChoosePrivateKeyRules policy
// is not set.
TEST_F(ArcPolicyBridgeCertStoreTest, KeyPermissionsNoCertsTest) {
base::Value key_permissions(base::Value::Type::DICTIONARY);
AddKeyPermissionForAppId(&key_permissions, kAndroidAppId, true /* allowed */);
AddKeyPermissionForAppId(&key_permissions, kChromeAppId, true /* allowed */);
cert_store_service()->set_required_cert_names_for_testing({});
policy_map().Set(policy::key::kKeyPermissions, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
std::move(key_permissions),
/* external_data_fetcher */ nullptr);
GetPoliciesAndVerifyResult(
base::StrCat({"{\"apkCacheEnabled\":true,\"guid\":\"", instance_guid(),
"\",", kRequiredKeyPairsEmpty, "}"}));
}
} // namespace arc