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 385