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 |