Commit 9eedf374 authored by James Cook's avatar James Cook Committed by Commit Bot

Support SyncTypesListDisabled policy for Chrome OS sync data types

SyncTypesListDisabled allows admins to disable individual sync
"user selectable types" by name.

Extend it to work for OS types ("osApps", "osPreferences", and
"wifiConfigurations") as well. Add migration support. While we are
rolling out SplitSettingsSync the existing browser data types names
"apps" and "preferences" will control the migrated types.

Add unit tests for SyncTypesListDisabled to SyncPolicyHandler, for
both the existing behavior and the new behavior.

      disable "apps", "bookmarks" and "preferences". Verify that
      without the SplitSettingsSync flag those data type toggles
      are disabled in browser sync settings. Verify that with
      the SplitSettingsSync flag those toggles are disabled in
      OS settings (for apps and preferences) and in browser
      settings (for bookmarks).

Bug: 1058853
Test: Use test DM server to add SyncTypesListDisabled policy to
Test: added to components_unittests
Change-Id: Id3427b6611007f1d1a0701f4b2eeceff607c06b7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2090205
Commit-Queue: James Cook <jamescook@chromium.org>
Reviewed-by: default avatarMarc Treib <treib@chromium.org>
Cr-Commit-Position: refs/heads/master@{#748323}
parent c00d0991
...@@ -125,21 +125,6 @@ void RegisterObsoleteUserTypePrefs(user_prefs::PrefRegistrySyncable* registry) { ...@@ -125,21 +125,6 @@ void RegisterObsoleteUserTypePrefs(user_prefs::PrefRegistrySyncable* registry) {
} }
} }
#if defined(OS_CHROMEOS)
const char* GetPrefNameForOsType(UserSelectableOsType type) {
switch (type) {
case UserSelectableOsType::kOsApps:
return prefs::kSyncOsApps;
case UserSelectableOsType::kOsPreferences:
return prefs::kSyncOsPreferences;
case UserSelectableOsType::kWifiConfigurations:
return prefs::kSyncWifiConfigurations;
}
NOTREACHED();
return nullptr;
}
#endif // defined(OS_CHROMEOS)
// Gets an offset to add noise to the birth year. If not present in prefs, the // Gets an offset to add noise to the birth year. If not present in prefs, the
// offset will be randomly generated within the offset range and cached in // offset will be randomly generated within the offset range and cached in
// syncable prefs. // syncable prefs.
...@@ -536,6 +521,20 @@ void SyncPrefs::SetOsSyncFeatureEnabled(bool enabled) { ...@@ -536,6 +521,20 @@ void SyncPrefs::SetOsSyncFeatureEnabled(bool enabled) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
pref_service_->SetBoolean(prefs::kOsSyncFeatureEnabled, enabled); pref_service_->SetBoolean(prefs::kOsSyncFeatureEnabled, enabled);
} }
// static
const char* SyncPrefs::GetPrefNameForOsType(UserSelectableOsType type) {
switch (type) {
case UserSelectableOsType::kOsApps:
return prefs::kSyncOsApps;
case UserSelectableOsType::kOsPreferences:
return prefs::kSyncOsPreferences;
case UserSelectableOsType::kWifiConfigurations:
return prefs::kSyncWifiConfigurations;
}
NOTREACHED();
return nullptr;
}
#endif // defined(OS_CHROMEOS) #endif // defined(OS_CHROMEOS)
bool SyncPrefs::IsManaged() const { bool SyncPrefs::IsManaged() const {
......
...@@ -128,6 +128,10 @@ class SyncPrefs : public CryptoSyncPrefs, ...@@ -128,6 +128,10 @@ class SyncPrefs : public CryptoSyncPrefs,
UserSelectableOsTypeSet selected_types); UserSelectableOsTypeSet selected_types);
bool IsOsSyncFeatureEnabled() const; bool IsOsSyncFeatureEnabled() const;
void SetOsSyncFeatureEnabled(bool enabled); void SetOsSyncFeatureEnabled(bool enabled);
// Maps |type| to its corresponding preference name. Returns nullptr if |type|
// isn't an OS type.
static const char* GetPrefNameForOsType(UserSelectableOsType type);
#endif #endif
// Whether Sync is forced off by enterprise policy. Note that this only covers // Whether Sync is forced off by enterprise policy. Note that this only covers
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <type_traits> #include <type_traits>
#include "base/logging.h" #include "base/logging.h"
#include "base/optional.h"
#include "components/sync/base/model_type.h" #include "components/sync/base/model_type.h"
#include "components/sync/base/pref_names.h" #include "components/sync/base/pref_names.h"
...@@ -95,23 +96,29 @@ UserSelectableTypeInfo GetUserSelectableTypeInfo(UserSelectableType type) { ...@@ -95,23 +96,29 @@ UserSelectableTypeInfo GetUserSelectableTypeInfo(UserSelectableType type) {
} }
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
constexpr char kOsAppsTypeName[] = "osApps";
constexpr char kOsPreferencesTypeName[] = "osPreferences";
constexpr char kWifiConfigurationsTypeName[] = "wifiConfigurations";
UserSelectableTypeInfo GetUserSelectableOsTypeInfo(UserSelectableOsType type) { UserSelectableTypeInfo GetUserSelectableOsTypeInfo(UserSelectableOsType type) {
// UserSelectableTypeInfo::type_name is used in js code and shouldn't be // UserSelectableTypeInfo::type_name is used in js code and shouldn't be
// changed without updating js part. // changed without updating js part.
switch (type) { switch (type) {
case UserSelectableOsType::kOsApps: case UserSelectableOsType::kOsApps:
return {"osApps", return {kOsAppsTypeName,
APPS, APPS,
{APP_LIST, APPS, APP_SETTINGS, ARC_PACKAGE, WEB_APPS}}; {APP_LIST, APPS, APP_SETTINGS, ARC_PACKAGE, WEB_APPS}};
case UserSelectableOsType::kOsPreferences: case UserSelectableOsType::kOsPreferences:
return {"osPreferences", return {kOsPreferencesTypeName,
OS_PREFERENCES, OS_PREFERENCES,
{OS_PREFERENCES, OS_PRIORITY_PREFERENCES, PRINTERS}}; {OS_PREFERENCES, OS_PRIORITY_PREFERENCES, PRINTERS}};
case UserSelectableOsType::kWifiConfigurations: case UserSelectableOsType::kWifiConfigurations:
return {"wifiConfigurations", WIFI_CONFIGURATIONS, {WIFI_CONFIGURATIONS}}; return {kWifiConfigurationsTypeName,
WIFI_CONFIGURATIONS,
{WIFI_CONFIGURATIONS}};
} }
} }
#endif #endif // defined(OS_CHROMEOS)
} // namespace } // namespace
...@@ -119,7 +126,8 @@ const char* GetUserSelectableTypeName(UserSelectableType type) { ...@@ -119,7 +126,8 @@ const char* GetUserSelectableTypeName(UserSelectableType type) {
return GetUserSelectableTypeInfo(type).type_name; return GetUserSelectableTypeInfo(type).type_name;
} }
UserSelectableType GetUserSelectableTypeFromString(const std::string& type) { base::Optional<UserSelectableType> GetUserSelectableTypeFromString(
const std::string& type) {
if (type == kBookmarksTypeName) { if (type == kBookmarksTypeName) {
return UserSelectableType::kBookmarks; return UserSelectableType::kBookmarks;
} }
...@@ -150,8 +158,7 @@ UserSelectableType GetUserSelectableTypeFromString(const std::string& type) { ...@@ -150,8 +158,7 @@ UserSelectableType GetUserSelectableTypeFromString(const std::string& type) {
if (type == kTabsTypeName) { if (type == kTabsTypeName) {
return UserSelectableType::kTabs; return UserSelectableType::kTabs;
} }
NOTREACHED(); return base::nullopt;
return UserSelectableType::kLastType;
} }
std::string UserSelectableTypeSetToString(UserSelectableTypeSet types) { std::string UserSelectableTypeSetToString(UserSelectableTypeSet types) {
...@@ -185,6 +192,32 @@ const char* GetUserSelectableOsTypeName(UserSelectableOsType type) { ...@@ -185,6 +192,32 @@ const char* GetUserSelectableOsTypeName(UserSelectableOsType type) {
return GetUserSelectableOsTypeInfo(type).type_name; return GetUserSelectableOsTypeInfo(type).type_name;
} }
base::Optional<UserSelectableOsType> GetUserSelectableOsTypeFromString(
const std::string& type) {
if (type == kOsAppsTypeName) {
return UserSelectableOsType::kOsApps;
}
if (type == kOsPreferencesTypeName) {
return UserSelectableOsType::kOsPreferences;
}
if (type == kWifiConfigurationsTypeName) {
return UserSelectableOsType::kWifiConfigurations;
}
// Some pref types migrated from browser prefs to OS prefs. Map the browser
// type name to the OS type so that enterprise policy SyncTypesListDisabled
// still applies to the migrated names during SplitSettingsSync roll-out.
// TODO(https://crbug.com/1059309): Rename "osApps" to "apps" after
// SplitSettingsSync is the default, and remove the mapping for "preferences".
if (type == kAppsTypeName) {
return UserSelectableOsType::kOsApps;
}
if (type == kPreferencesTypeName) {
return UserSelectableOsType::kOsPreferences;
}
return base::nullopt;
}
ModelTypeSet UserSelectableOsTypeToAllModelTypes(UserSelectableOsType type) { ModelTypeSet UserSelectableOsTypeToAllModelTypes(UserSelectableOsType type) {
return GetUserSelectableOsTypeInfo(type).model_type_group; return GetUserSelectableOsTypeInfo(type).model_type_group;
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <string> #include <string>
#include "base/optional.h"
#include "components/sync/base/enum_set.h" #include "components/sync/base/enum_set.h"
#include "components/sync/base/model_type.h" #include "components/sync/base/model_type.h"
...@@ -33,7 +34,9 @@ using UserSelectableTypeSet = EnumSet<UserSelectableType, ...@@ -33,7 +34,9 @@ using UserSelectableTypeSet = EnumSet<UserSelectableType,
UserSelectableType::kLastType>; UserSelectableType::kLastType>;
const char* GetUserSelectableTypeName(UserSelectableType type); const char* GetUserSelectableTypeName(UserSelectableType type);
UserSelectableType GetUserSelectableTypeFromString(const std::string& type); // Returns the type if the string matches a known type.
base::Optional<UserSelectableType> GetUserSelectableTypeFromString(
const std::string& type);
std::string UserSelectableTypeSetToString(UserSelectableTypeSet types); std::string UserSelectableTypeSetToString(UserSelectableTypeSet types);
ModelTypeSet UserSelectableTypeToAllModelTypes(UserSelectableType type); ModelTypeSet UserSelectableTypeToAllModelTypes(UserSelectableType type);
...@@ -65,6 +68,10 @@ using UserSelectableOsTypeSet = EnumSet<UserSelectableOsType, ...@@ -65,6 +68,10 @@ using UserSelectableOsTypeSet = EnumSet<UserSelectableOsType,
const char* GetUserSelectableOsTypeName(UserSelectableOsType type); const char* GetUserSelectableOsTypeName(UserSelectableOsType type);
ModelTypeSet UserSelectableOsTypeToAllModelTypes(UserSelectableOsType type); ModelTypeSet UserSelectableOsTypeToAllModelTypes(UserSelectableOsType type);
ModelType UserSelectableOsTypeToCanonicalModelType(UserSelectableOsType type); ModelType UserSelectableOsTypeToCanonicalModelType(UserSelectableOsType type);
// Returns the type if the string matches a known OS type.
base::Optional<UserSelectableOsType> GetUserSelectableOsTypeFromString(
const std::string& type);
#endif // defined(OS_CHROMEOS) #endif // defined(OS_CHROMEOS)
} // namespace syncer } // namespace syncer
......
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
#include "components/sync/driver/sync_policy_handler.h" #include "components/sync/driver/sync_policy_handler.h"
#include <string>
#include "base/optional.h"
#include "base/values.h" #include "base/values.h"
#include "components/policy/core/common/policy_map.h" #include "components/policy/core/common/policy_map.h"
#include "components/policy/policy_constants.h" #include "components/policy/policy_constants.h"
...@@ -12,13 +15,44 @@ ...@@ -12,13 +15,44 @@
#include "components/sync/base/sync_prefs.h" #include "components/sync/base/sync_prefs.h"
#include "components/sync/base/user_selectable_type.h" #include "components/sync/base/user_selectable_type.h"
#if defined(OS_CHROMEOS)
#include "chromeos/constants/chromeos_features.h"
#endif // defined(OS_CHROMEOS)
namespace syncer { namespace syncer {
namespace {
void DisableSyncType(const std::string& type_name, PrefValueMap* prefs) {
base::Optional<UserSelectableType> type =
GetUserSelectableTypeFromString(type_name);
if (type.has_value()) {
const char* pref = SyncPrefs::GetPrefNameForType(*type);
if (pref)
prefs->SetValue(pref, base::Value(false));
}
#if defined(OS_CHROMEOS)
if (chromeos::features::IsSplitSettingsSyncEnabled()) {
// Check for OS types. This includes types that used to be browser types,
// like "apps" and "preferences".
base::Optional<UserSelectableOsType> os_type =
GetUserSelectableOsTypeFromString(type_name);
if (os_type.has_value()) {
const char* os_pref = SyncPrefs::GetPrefNameForOsType(*os_type);
if (os_pref)
prefs->SetValue(os_pref, base::Value(false));
}
}
#endif // defined(OS_CHROMEOS)
}
} // namespace
SyncPolicyHandler::SyncPolicyHandler() SyncPolicyHandler::SyncPolicyHandler()
: policy::TypeCheckingPolicyHandler(policy::key::kSyncDisabled, : policy::TypeCheckingPolicyHandler(policy::key::kSyncDisabled,
base::Value::Type::BOOLEAN) {} base::Value::Type::BOOLEAN) {}
SyncPolicyHandler::~SyncPolicyHandler() {} SyncPolicyHandler::~SyncPolicyHandler() = default;
void SyncPolicyHandler::ApplyPolicySettings(const policy::PolicyMap& policies, void SyncPolicyHandler::ApplyPolicySettings(const policy::PolicyMap& policies,
PrefValueMap* prefs) { PrefValueMap* prefs) {
...@@ -34,16 +68,10 @@ void SyncPolicyHandler::ApplyPolicySettings(const policy::PolicyMap& policies, ...@@ -34,16 +68,10 @@ void SyncPolicyHandler::ApplyPolicySettings(const policy::PolicyMap& policies,
if (disabled_sync_types_value && disabled_sync_types_value->is_list()) { if (disabled_sync_types_value && disabled_sync_types_value->is_list()) {
auto list = disabled_sync_types_value->GetList(); auto list = disabled_sync_types_value->GetList();
bool has_one_valid_entry = false; for (const base::Value& type_name : list) {
for (auto it = list.begin(); it != list.end(); ++it) { if (!type_name.is_string())
if (!it->is_string())
continue;
const char* pref = SyncPrefs::GetPrefNameForType(
GetUserSelectableTypeFromString(it->GetString()));
if (!pref)
continue; continue;
prefs->SetValue(pref, base::Value(false)); DisableSyncType(type_name.GetString(), prefs);
has_one_valid_entry = true;
} }
} }
} }
......
...@@ -14,12 +14,15 @@ ...@@ -14,12 +14,15 @@
#include "components/sync/base/pref_names.h" #include "components/sync/base/pref_names.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace syncer { #if defined(OS_CHROMEOS)
#include "base/test/scoped_feature_list.h"
#include "chromeos/constants/chromeos_features.h"
#endif // defined(OS_CHROMEOS)
// Test cases for the Sync policy setting. namespace syncer {
class SyncPolicyHandlerTest : public testing::Test {}; namespace {
TEST_F(SyncPolicyHandlerTest, Default) { TEST(SyncPolicyHandlerTest, Default) {
policy::PolicyMap policy; policy::PolicyMap policy;
SyncPolicyHandler handler; SyncPolicyHandler handler;
PrefValueMap prefs; PrefValueMap prefs;
...@@ -27,7 +30,7 @@ TEST_F(SyncPolicyHandlerTest, Default) { ...@@ -27,7 +30,7 @@ TEST_F(SyncPolicyHandlerTest, Default) {
EXPECT_FALSE(prefs.GetValue(prefs::kSyncManaged, nullptr)); EXPECT_FALSE(prefs.GetValue(prefs::kSyncManaged, nullptr));
} }
TEST_F(SyncPolicyHandlerTest, Enabled) { TEST(SyncPolicyHandlerTest, Enabled) {
policy::PolicyMap policy; policy::PolicyMap policy;
policy.Set(policy::key::kSyncDisabled, policy::POLICY_LEVEL_MANDATORY, policy.Set(policy::key::kSyncDisabled, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD, policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
...@@ -40,7 +43,7 @@ TEST_F(SyncPolicyHandlerTest, Enabled) { ...@@ -40,7 +43,7 @@ TEST_F(SyncPolicyHandlerTest, Enabled) {
EXPECT_FALSE(prefs.GetValue(prefs::kSyncManaged, nullptr)); EXPECT_FALSE(prefs.GetValue(prefs::kSyncManaged, nullptr));
} }
TEST_F(SyncPolicyHandlerTest, Disabled) { TEST(SyncPolicyHandlerTest, Disabled) {
policy::PolicyMap policy; policy::PolicyMap policy;
policy.Set(policy::key::kSyncDisabled, policy::POLICY_LEVEL_MANDATORY, policy.Set(policy::key::kSyncDisabled, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD, policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
...@@ -59,4 +62,107 @@ TEST_F(SyncPolicyHandlerTest, Disabled) { ...@@ -59,4 +62,107 @@ TEST_F(SyncPolicyHandlerTest, Disabled) {
EXPECT_TRUE(sync_managed); EXPECT_TRUE(sync_managed);
} }
TEST(SyncPolicyHandlerTest, SyncTypesListDisabled) {
// Start with prefs enabled so we can sense that they have changed.
PrefValueMap prefs;
prefs.SetBoolean(prefs::kSyncBookmarks, true);
prefs.SetBoolean(prefs::kSyncPreferences, true);
prefs.SetBoolean(prefs::kSyncAutofill, true);
prefs.SetBoolean(prefs::kSyncThemes, true);
// Create a policy that disables some types.
policy::PolicyMap policy;
base::ListValue disabled_types;
disabled_types.AppendString("bookmarks");
disabled_types.AppendString("preferences");
policy.Set(policy::key::kSyncTypesListDisabled,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD, disabled_types.CreateDeepCopy(),
nullptr);
SyncPolicyHandler handler;
handler.ApplyPolicySettings(policy, &prefs);
// Prefs in the policy should be disabled.
bool enabled;
ASSERT_TRUE(prefs.GetBoolean(prefs::kSyncBookmarks, &enabled));
EXPECT_FALSE(enabled);
ASSERT_TRUE(prefs.GetBoolean(prefs::kSyncPreferences, &enabled));
EXPECT_FALSE(enabled);
// Prefs that are not part of the policy are still enabled.
ASSERT_TRUE(prefs.GetBoolean(prefs::kSyncAutofill, &enabled));
EXPECT_TRUE(enabled);
ASSERT_TRUE(prefs.GetBoolean(prefs::kSyncThemes, &enabled));
EXPECT_TRUE(enabled);
}
#if defined(OS_CHROMEOS)
class SyncPolicyHandlerOsTest : public testing::Test {
public:
SyncPolicyHandlerOsTest() {
feature_list_.InitAndEnableFeature(chromeos::features::kSplitSettingsSync);
}
base::test::ScopedFeatureList feature_list_;
};
TEST_F(SyncPolicyHandlerOsTest, SyncTypesListDisabled_OsTypes) {
// Start with prefs enabled so we can sense that they have changed.
PrefValueMap prefs;
prefs.SetBoolean(prefs::kSyncOsApps, true);
prefs.SetBoolean(prefs::kSyncOsPreferences, true);
prefs.SetBoolean(prefs::kSyncWifiConfigurations, true);
// Create a policy that disables the types.
policy::PolicyMap policy;
base::ListValue disabled_types;
disabled_types.AppendString("osApps");
disabled_types.AppendString("osPreferences");
disabled_types.AppendString("wifiConfigurations");
policy.Set(policy::key::kSyncTypesListDisabled,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD, disabled_types.CreateDeepCopy(),
nullptr);
SyncPolicyHandler handler;
handler.ApplyPolicySettings(policy, &prefs);
// Prefs in the policy are disabled.
bool enabled;
ASSERT_TRUE(prefs.GetBoolean(prefs::kSyncOsApps, &enabled));
EXPECT_FALSE(enabled);
ASSERT_TRUE(prefs.GetBoolean(prefs::kSyncOsPreferences, &enabled));
EXPECT_FALSE(enabled);
ASSERT_TRUE(prefs.GetBoolean(prefs::kSyncWifiConfigurations, &enabled));
EXPECT_FALSE(enabled);
}
TEST_F(SyncPolicyHandlerOsTest, SyncTypesListDisabled_MigratedTypes) {
// Start with prefs enabled so we can sense that they have changed.
PrefValueMap prefs;
prefs.SetBoolean(prefs::kSyncOsApps, true);
prefs.SetBoolean(prefs::kSyncOsPreferences, true);
// Create a policy that disables the types, but using the original browser
// policy names from before the SplitSettingsSync launch.
policy::PolicyMap policy;
base::ListValue disabled_types;
disabled_types.AppendString("apps");
disabled_types.AppendString("preferences");
policy.Set(policy::key::kSyncTypesListDisabled,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD, disabled_types.CreateDeepCopy(),
nullptr);
SyncPolicyHandler handler;
handler.ApplyPolicySettings(policy, &prefs);
// The equivalent OS types are disabled.
bool enabled;
ASSERT_TRUE(prefs.GetBoolean(prefs::kSyncOsApps, &enabled));
EXPECT_FALSE(enabled);
ASSERT_TRUE(prefs.GetBoolean(prefs::kSyncOsPreferences, &enabled));
EXPECT_FALSE(enabled);
}
#endif // defined(OS_CHROMEOS)
} // namespace
} // namespace syncer } // namespace syncer
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment