| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/policy/managed_mode_policy_provider.h" | |
| 6 | |
| 7 #include "base/callback.h" | |
| 8 #include "base/json/json_reader.h" | |
| 9 #include "base/json/json_writer.h" | |
| 10 #include "base/prefs/json_pref_store.h" | |
| 11 #include "base/strings/string_util.h" | |
| 12 #include "base/threading/sequenced_worker_pool.h" | |
| 13 #include "chrome/browser/managed_mode/managed_mode_url_filter.h" | |
| 14 #include "chrome/browser/policy/external_data_fetcher.h" | |
| 15 #include "chrome/browser/policy/policy_bundle.h" | |
| 16 #include "chrome/browser/prefs/incognito_mode_prefs.h" | |
| 17 #include "chrome/browser/profiles/profile.h" | |
| 18 #include "chrome/common/chrome_constants.h" | |
| 19 #include "content/public/browser/browser_thread.h" | |
| 20 #include "content/public/browser/user_metrics.h" | |
| 21 #include "policy/policy_constants.h" | |
| 22 #include "sync/api/sync_change.h" | |
| 23 #include "sync/protocol/sync.pb.h" | |
| 24 | |
| 25 using base::DictionaryValue; | |
| 26 using base::JSONReader; | |
| 27 using base::Value; | |
| 28 using content::BrowserThread; | |
| 29 using content::UserMetricsAction; | |
| 30 using syncer::MANAGED_USER_SETTINGS; | |
| 31 using syncer::ModelType; | |
| 32 using syncer::SyncChange; | |
| 33 using syncer::SyncChangeList; | |
| 34 using syncer::SyncChangeProcessor; | |
| 35 using syncer::SyncData; | |
| 36 using syncer::SyncDataList; | |
| 37 using syncer::SyncError; | |
| 38 using syncer::SyncErrorFactory; | |
| 39 using syncer::SyncMergeResult; | |
| 40 | |
| 41 namespace { | |
| 42 | |
| 43 const char kAtomicSettings[] = "atomic_settings"; | |
| 44 const char kManagedUserInternalPolicyPrefix[] = "X-"; | |
| 45 const char kQueuedItems[] = "queued_items"; | |
| 46 const char kSplitSettingKeySeparator = ':'; | |
| 47 const char kSplitSettings[] = "split_settings"; | |
| 48 | |
| 49 bool SettingShouldApplyToPolicy(const std::string& key) { | |
| 50 return !StartsWithASCII(key, kManagedUserInternalPolicyPrefix, false); | |
| 51 } | |
| 52 | |
| 53 } // namespace | |
| 54 | |
| 55 namespace policy { | |
| 56 | |
| 57 | |
| 58 // static | |
| 59 scoped_ptr<ManagedModePolicyProvider> ManagedModePolicyProvider::Create( | |
| 60 Profile* profile, | |
| 61 base::SequencedTaskRunner* sequenced_task_runner, | |
| 62 bool force_load) { | |
| 63 base::FilePath path = | |
| 64 profile->GetPath().Append(chrome::kManagedModePolicyFilename); | |
| 65 JsonPrefStore* pref_store = new JsonPrefStore(path, sequenced_task_runner); | |
| 66 // Load the data synchronously if needed (when creating profiles on startup). | |
| 67 if (force_load) | |
| 68 pref_store->ReadPrefs(); | |
| 69 else | |
| 70 pref_store->ReadPrefsAsync(NULL); | |
| 71 | |
| 72 return make_scoped_ptr(new ManagedModePolicyProvider(pref_store)); | |
| 73 } | |
| 74 | |
| 75 ManagedModePolicyProvider::ManagedModePolicyProvider( | |
| 76 PersistentPrefStore* pref_store) | |
| 77 : store_(pref_store), | |
| 78 local_policies_(new DictionaryValue) { | |
| 79 store_->AddObserver(this); | |
| 80 if (store_->IsInitializationComplete()) | |
| 81 UpdatePolicyFromCache(); | |
| 82 } | |
| 83 | |
| 84 ManagedModePolicyProvider::~ManagedModePolicyProvider() {} | |
| 85 | |
| 86 void ManagedModePolicyProvider::Clear() { | |
| 87 store_->RemoveValue(kAtomicSettings); | |
| 88 store_->RemoveValue(kSplitSettings); | |
| 89 } | |
| 90 | |
| 91 // static | |
| 92 std::string ManagedModePolicyProvider::MakeSplitSettingKey( | |
| 93 const std::string& prefix, | |
| 94 const std::string& key) { | |
| 95 return prefix + kSplitSettingKeySeparator + key; | |
| 96 } | |
| 97 | |
| 98 void ManagedModePolicyProvider::UploadItem(const std::string& key, | |
| 99 scoped_ptr<Value> value) { | |
| 100 DCHECK(!SettingShouldApplyToPolicy(key)); | |
| 101 | |
| 102 std::string key_suffix = key; | |
| 103 DictionaryValue* dict = NULL; | |
| 104 if (sync_processor_) { | |
| 105 content::RecordAction( | |
| 106 UserMetricsAction("ManagedUsers_UploadItem_Syncing")); | |
| 107 dict = GetDictionaryAndSplitKey(&key_suffix); | |
| 108 DCHECK(GetQueuedItems()->empty()); | |
| 109 SyncChangeList change_list; | |
| 110 SyncData data = CreateSyncDataForPolicy(key, value.get()); | |
| 111 SyncChange::SyncChangeType change_type = | |
| 112 dict->HasKey(key_suffix) ? SyncChange::ACTION_UPDATE | |
| 113 : SyncChange::ACTION_ADD; | |
| 114 change_list.push_back(SyncChange(FROM_HERE, change_type, data)); | |
| 115 SyncError error = | |
| 116 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list); | |
| 117 DCHECK(!error.IsSet()) << error.ToString(); | |
| 118 } else { | |
| 119 content::RecordAction( | |
| 120 UserMetricsAction("ManagedUsers_UploadItem_Queued")); | |
| 121 dict = GetQueuedItems(); | |
| 122 } | |
| 123 dict->SetWithoutPathExpansion(key_suffix, value.release()); | |
| 124 } | |
| 125 | |
| 126 void ManagedModePolicyProvider::SetLocalPolicyForTesting( | |
| 127 const std::string& key, | |
| 128 scoped_ptr<Value> value) { | |
| 129 if (value) | |
| 130 local_policies_->SetWithoutPathExpansion(key, value.release()); | |
| 131 else | |
| 132 local_policies_->RemoveWithoutPathExpansion(key, NULL); | |
| 133 | |
| 134 UpdatePolicyFromCache(); | |
| 135 } | |
| 136 | |
| 137 // static | |
| 138 SyncData ManagedModePolicyProvider::CreateSyncDataForPolicy( | |
| 139 const std::string& name, | |
| 140 const Value* value) { | |
| 141 std::string json_value; | |
| 142 base::JSONWriter::Write(value, &json_value); | |
| 143 ::sync_pb::EntitySpecifics specifics; | |
| 144 specifics.mutable_managed_user_setting()->set_name(name); | |
| 145 specifics.mutable_managed_user_setting()->set_value(json_value); | |
| 146 return SyncData::CreateLocalData(name, name, specifics); | |
| 147 } | |
| 148 | |
| 149 void ManagedModePolicyProvider::Shutdown() { | |
| 150 store_->RemoveObserver(this); | |
| 151 ConfigurationPolicyProvider::Shutdown(); | |
| 152 } | |
| 153 | |
| 154 void ManagedModePolicyProvider::RefreshPolicies() { | |
| 155 UpdatePolicyFromCache(); | |
| 156 } | |
| 157 | |
| 158 bool ManagedModePolicyProvider::IsInitializationComplete( | |
| 159 PolicyDomain domain) const { | |
| 160 if (domain == POLICY_DOMAIN_CHROME) | |
| 161 return store_->IsInitializationComplete(); | |
| 162 return true; | |
| 163 } | |
| 164 | |
| 165 void ManagedModePolicyProvider::OnPrefValueChanged(const std::string& key) {} | |
| 166 | |
| 167 void ManagedModePolicyProvider::OnInitializationCompleted(bool success) { | |
| 168 DCHECK(success); | |
| 169 UpdatePolicyFromCache(); | |
| 170 } | |
| 171 | |
| 172 SyncMergeResult ManagedModePolicyProvider::MergeDataAndStartSyncing( | |
| 173 ModelType type, | |
| 174 const SyncDataList& initial_sync_data, | |
| 175 scoped_ptr<SyncChangeProcessor> sync_processor, | |
| 176 scoped_ptr<SyncErrorFactory> error_handler) { | |
| 177 DCHECK_EQ(MANAGED_USER_SETTINGS, type); | |
| 178 sync_processor_ = sync_processor.Pass(); | |
| 179 error_handler_ = error_handler.Pass(); | |
| 180 | |
| 181 // Clear all atomic and split settings, then recreate them from Sync data. | |
| 182 Clear(); | |
| 183 for (SyncDataList::const_iterator it = initial_sync_data.begin(); | |
| 184 it != initial_sync_data.end(); ++it) { | |
| 185 DCHECK_EQ(MANAGED_USER_SETTINGS, it->GetDataType()); | |
| 186 const ::sync_pb::ManagedUserSettingSpecifics& managed_user_setting = | |
| 187 it->GetSpecifics().managed_user_setting(); | |
| 188 scoped_ptr<Value> value(JSONReader::Read(managed_user_setting.value())); | |
| 189 std::string name_suffix = managed_user_setting.name(); | |
| 190 DictionaryValue* dict = GetDictionaryAndSplitKey(&name_suffix); | |
| 191 dict->SetWithoutPathExpansion(name_suffix, value.release()); | |
| 192 } | |
| 193 store_->ReportValueChanged(kAtomicSettings); | |
| 194 store_->ReportValueChanged(kSplitSettings); | |
| 195 UpdatePolicyFromCache(); | |
| 196 | |
| 197 // Upload all the queued up items (either with an ADD or an UPDATE action, | |
| 198 // depending on whether they already exist) and move them to split settings. | |
| 199 SyncChangeList change_list; | |
| 200 DictionaryValue* queued_items = GetQueuedItems(); | |
| 201 for (DictionaryValue::Iterator it(*queued_items); !it.IsAtEnd(); | |
| 202 it.Advance()) { | |
| 203 std::string key_suffix = it.key(); | |
| 204 DictionaryValue* dict = GetDictionaryAndSplitKey(&key_suffix); | |
| 205 SyncData data = CreateSyncDataForPolicy(it.key(), &it.value()); | |
| 206 SyncChange::SyncChangeType change_type = | |
| 207 dict->HasKey(key_suffix) ? SyncChange::ACTION_UPDATE | |
| 208 : SyncChange::ACTION_ADD; | |
| 209 change_list.push_back(SyncChange(FROM_HERE, change_type, data)); | |
| 210 dict->SetWithoutPathExpansion(key_suffix, it.value().DeepCopy()); | |
| 211 } | |
| 212 queued_items->Clear(); | |
| 213 | |
| 214 SyncMergeResult result(MANAGED_USER_SETTINGS); | |
| 215 // Process all the accumulated changes from the queued items. | |
| 216 if (change_list.size() > 0) { | |
| 217 store_->ReportValueChanged(kQueuedItems); | |
| 218 result.set_error( | |
| 219 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list)); | |
| 220 } | |
| 221 | |
| 222 // TODO(bauerb): Statistics? | |
| 223 return result; | |
| 224 } | |
| 225 | |
| 226 void ManagedModePolicyProvider::StopSyncing(ModelType type) { | |
| 227 DCHECK_EQ(syncer::MANAGED_USER_SETTINGS, type); | |
| 228 sync_processor_.reset(); | |
| 229 error_handler_.reset(); | |
| 230 } | |
| 231 | |
| 232 SyncDataList ManagedModePolicyProvider::GetAllSyncData(ModelType type) const { | |
| 233 DCHECK_EQ(syncer::MANAGED_USER_SETTINGS, type); | |
| 234 SyncDataList data; | |
| 235 for (DictionaryValue::Iterator it(*GetAtomicSettings()); !it.IsAtEnd(); | |
| 236 it.Advance()) { | |
| 237 data.push_back(CreateSyncDataForPolicy(it.key(), &it.value())); | |
| 238 } | |
| 239 for (DictionaryValue::Iterator it(*GetSplitSettings()); !it.IsAtEnd(); | |
| 240 it.Advance()) { | |
| 241 const DictionaryValue* dict = NULL; | |
| 242 it.value().GetAsDictionary(&dict); | |
| 243 for (DictionaryValue::Iterator jt(*dict); !jt.IsAtEnd(); jt.Advance()) { | |
| 244 data.push_back(CreateSyncDataForPolicy( | |
| 245 MakeSplitSettingKey(it.key(), jt.key()), &jt.value())); | |
| 246 } | |
| 247 } | |
| 248 DCHECK_EQ(0u, GetQueuedItems()->size()); | |
| 249 return data; | |
| 250 } | |
| 251 | |
| 252 SyncError ManagedModePolicyProvider::ProcessSyncChanges( | |
| 253 const tracked_objects::Location& from_here, | |
| 254 const SyncChangeList& change_list) { | |
| 255 for (SyncChangeList::const_iterator it = change_list.begin(); | |
| 256 it != change_list.end(); ++it) { | |
| 257 SyncData data = it->sync_data(); | |
| 258 DCHECK_EQ(MANAGED_USER_SETTINGS, data.GetDataType()); | |
| 259 const ::sync_pb::ManagedUserSettingSpecifics& managed_user_setting = | |
| 260 data.GetSpecifics().managed_user_setting(); | |
| 261 std::string key = managed_user_setting.name(); | |
| 262 DictionaryValue* dict = GetDictionaryAndSplitKey(&key); | |
| 263 switch (it->change_type()) { | |
| 264 case SyncChange::ACTION_ADD: | |
| 265 case SyncChange::ACTION_UPDATE: { | |
| 266 scoped_ptr<Value> value(JSONReader::Read(managed_user_setting.value())); | |
| 267 if (dict->HasKey(key)) { | |
| 268 DLOG_IF(WARNING, it->change_type() == SyncChange::ACTION_ADD) | |
| 269 << "Value for key " << key << " already exists"; | |
| 270 } else { | |
| 271 DLOG_IF(WARNING, it->change_type() == SyncChange::ACTION_UPDATE) | |
| 272 << "Value for key " << key << " doesn't exist yet"; | |
| 273 } | |
| 274 dict->SetWithoutPathExpansion(key, value.release()); | |
| 275 break; | |
| 276 } | |
| 277 case SyncChange::ACTION_DELETE: { | |
| 278 DLOG_IF(WARNING, !dict->HasKey(key)) << "Trying to delete nonexistent " | |
| 279 << "key " << key; | |
| 280 dict->RemoveWithoutPathExpansion(key, NULL); | |
| 281 break; | |
| 282 } | |
| 283 case SyncChange::ACTION_INVALID: { | |
| 284 NOTREACHED(); | |
| 285 break; | |
| 286 } | |
| 287 } | |
| 288 } | |
| 289 store_->ReportValueChanged(kAtomicSettings); | |
| 290 store_->ReportValueChanged(kSplitSettings); | |
| 291 UpdatePolicyFromCache(); | |
| 292 | |
| 293 SyncError error; | |
| 294 return error; | |
| 295 } | |
| 296 | |
| 297 void ManagedModePolicyProvider::InitLocalPolicies() { | |
| 298 local_policies_->Clear(); | |
| 299 local_policies_->SetBoolean(policy::key::kAllowDeletingBrowserHistory, false); | |
| 300 local_policies_->SetInteger(policy::key::kContentPackDefaultFilteringBehavior, | |
| 301 ManagedModeURLFilter::ALLOW); | |
| 302 local_policies_->SetBoolean(policy::key::kForceSafeSearch, true); | |
| 303 local_policies_->SetBoolean(policy::key::kHideWebStoreIcon, true); | |
| 304 local_policies_->SetInteger(policy::key::kIncognitoModeAvailability, | |
| 305 IncognitoModePrefs::DISABLED); | |
| 306 local_policies_->SetBoolean(policy::key::kSigninAllowed, false); | |
| 307 UpdatePolicyFromCache(); | |
| 308 } | |
| 309 | |
| 310 DictionaryValue* ManagedModePolicyProvider::GetOrCreateDictionary( | |
| 311 const std::string& key) const { | |
| 312 Value* value = NULL; | |
| 313 DictionaryValue* dict = NULL; | |
| 314 if (store_->GetMutableValue(key, &value)) { | |
| 315 bool success = value->GetAsDictionary(&dict); | |
| 316 DCHECK(success); | |
| 317 } else { | |
| 318 dict = new base::DictionaryValue; | |
| 319 store_->SetValue(key, dict); | |
| 320 } | |
| 321 | |
| 322 return dict; | |
| 323 } | |
| 324 | |
| 325 DictionaryValue* ManagedModePolicyProvider::GetAtomicSettings() const { | |
| 326 return GetOrCreateDictionary(kAtomicSettings); | |
| 327 } | |
| 328 | |
| 329 DictionaryValue* ManagedModePolicyProvider::GetSplitSettings() const { | |
| 330 return GetOrCreateDictionary(kSplitSettings); | |
| 331 } | |
| 332 | |
| 333 DictionaryValue* ManagedModePolicyProvider::GetQueuedItems() const { | |
| 334 return GetOrCreateDictionary(kQueuedItems); | |
| 335 } | |
| 336 | |
| 337 DictionaryValue* ManagedModePolicyProvider::GetDictionaryAndSplitKey( | |
| 338 std::string* key) const { | |
| 339 size_t pos = key->find_first_of(kSplitSettingKeySeparator); | |
| 340 if (pos == std::string::npos) | |
| 341 return GetAtomicSettings(); | |
| 342 | |
| 343 DictionaryValue* split_settings = GetSplitSettings(); | |
| 344 std::string prefix = key->substr(0, pos); | |
| 345 DictionaryValue* dict = NULL; | |
| 346 if (!split_settings->GetDictionary(prefix, &dict)) { | |
| 347 dict = new DictionaryValue; | |
| 348 DCHECK(!split_settings->HasKey(prefix)); | |
| 349 split_settings->Set(prefix, dict); | |
| 350 } | |
| 351 key->erase(0, pos + 1); | |
| 352 return dict; | |
| 353 } | |
| 354 | |
| 355 void ManagedModePolicyProvider::UpdatePolicyFromCache() { | |
| 356 scoped_ptr<PolicyBundle> policy_bundle(new PolicyBundle); | |
| 357 PolicyMap* policy_map = &policy_bundle->Get( | |
| 358 PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())); | |
| 359 policy_map->LoadFrom( | |
| 360 local_policies_.get(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER); | |
| 361 | |
| 362 DictionaryValue* atomic_settings = GetAtomicSettings(); | |
| 363 for (DictionaryValue::Iterator it(*atomic_settings); !it.IsAtEnd(); | |
| 364 it.Advance()) { | |
| 365 if (!SettingShouldApplyToPolicy(it.key())) | |
| 366 continue; | |
| 367 | |
| 368 policy_map->Set(it.key(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, | |
| 369 it.value().DeepCopy(), NULL); | |
| 370 } | |
| 371 | |
| 372 DictionaryValue* split_settings = GetSplitSettings(); | |
| 373 for (DictionaryValue::Iterator it(*split_settings); !it.IsAtEnd(); | |
| 374 it.Advance()) { | |
| 375 if (!SettingShouldApplyToPolicy(it.key())) | |
| 376 continue; | |
| 377 | |
| 378 policy_map->Set(it.key(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, | |
| 379 it.value().DeepCopy(), NULL); | |
| 380 } | |
| 381 UpdatePolicy(policy_bundle.Pass()); | |
| 382 } | |
| 383 | |
| 384 } // namespace policy | |
| OLD | NEW |