1 // Copyright 2013 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.
5 #include "chrome/browser/managed_mode/managed_user_sync_service.h"
8 #include "base/callback.h"
9 #include "base/prefs/scoped_user_pref_update.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/values.h"
13 #include "chrome/browser/profiles/profile_info_cache.h"
14 #include "chrome/common/pref_names.h"
15 #include "components/user_prefs/pref_registry_syncable.h"
16 #include "sync/api/sync_change.h"
17 #include "sync/api/sync_data.h"
18 #include "sync/api/sync_error.h"
19 #include "sync/api/sync_error_factory.h"
20 #include "sync/api/sync_merge_result.h"
21 #include "sync/protocol/sync.pb.h"
23 #if defined(OS_CHROMEOS)
24 #include "chrome/browser/chromeos/login/default_user_images.h"
27 using base::DictionaryValue;
28 using user_prefs::PrefRegistrySyncable;
29 using syncer::MANAGED_USERS;
30 using syncer::ModelType;
31 using syncer::SyncChange;
32 using syncer::SyncChangeList;
33 using syncer::SyncChangeProcessor;
34 using syncer::SyncData;
35 using syncer::SyncDataList;
36 using syncer::SyncError;
37 using syncer::SyncErrorFactory;
38 using syncer::SyncMergeResult;
39 using sync_pb::ManagedUserSpecifics;
43 #if defined(OS_CHROMEOS)
44 const char kChromeOSAvatarPrefix[] = "chromeos-avatar-index:";
46 const char kChromeAvatarPrefix[] = "chrome-avatar-index:";
49 SyncData CreateLocalSyncData(const std::string& id,
50 const std::string& name,
52 const std::string& master_key,
53 const std::string& chrome_avatar,
54 const std::string& chromeos_avatar,
55 const std::string& password_signature_key,
56 const std::string& password_encryption_key) {
57 ::sync_pb::EntitySpecifics specifics;
58 specifics.mutable_managed_user()->set_id(id);
59 specifics.mutable_managed_user()->set_name(name);
60 if (!chrome_avatar.empty())
61 specifics.mutable_managed_user()->set_chrome_avatar(chrome_avatar);
62 if (!chromeos_avatar.empty())
63 specifics.mutable_managed_user()->set_chromeos_avatar(chromeos_avatar);
64 if (!master_key.empty())
65 specifics.mutable_managed_user()->set_master_key(master_key);
67 specifics.mutable_managed_user()->set_acknowledged(true);
68 if (!password_signature_key.empty()) {
69 specifics.mutable_managed_user()->
70 set_password_signature_key(password_signature_key);
72 if (!password_encryption_key.empty()) {
73 specifics.mutable_managed_user()->
74 set_password_encryption_key(password_encryption_key);
76 return SyncData::CreateLocalData(id, name, specifics);
79 SyncData CreateSyncDataFromDictionaryEntry(const std::string& id,
80 const base::Value& value) {
81 const base::DictionaryValue* dict = NULL;
82 bool success = value.GetAsDictionary(&dict);
84 bool acknowledged = false;
85 dict->GetBoolean(ManagedUserSyncService::kAcknowledged, &acknowledged);
87 dict->GetString(ManagedUserSyncService::kName, &name);
88 DCHECK(!name.empty());
89 std::string master_key;
90 dict->GetString(ManagedUserSyncService::kMasterKey, &master_key);
91 std::string chrome_avatar;
92 dict->GetString(ManagedUserSyncService::kChromeAvatar, &chrome_avatar);
93 std::string chromeos_avatar;
94 dict->GetString(ManagedUserSyncService::kChromeOsAvatar, &chromeos_avatar);
95 std::string signature;
96 dict->GetString(ManagedUserSyncService::kPasswordSignatureKey, &signature);
97 std::string encryption;
98 dict->GetString(ManagedUserSyncService::kPasswordEncryptionKey, &encryption);
100 return CreateLocalSyncData(id,
112 const char ManagedUserSyncService::kAcknowledged[] = "acknowledged";
113 const char ManagedUserSyncService::kChromeAvatar[] = "chromeAvatar";
114 const char ManagedUserSyncService::kChromeOsAvatar[] = "chromeOsAvatar";
115 const char ManagedUserSyncService::kMasterKey[] = "masterKey";
116 const char ManagedUserSyncService::kName[] = "name";
117 const char ManagedUserSyncService::kPasswordSignatureKey[] =
118 "passwordSignatureKey";
119 const char ManagedUserSyncService::kPasswordEncryptionKey[] =
120 "passwordEncryptionKey";
121 const int ManagedUserSyncService::kNoAvatar = -100;
123 ManagedUserSyncService::ManagedUserSyncService(PrefService* prefs)
125 pref_change_registrar_.Init(prefs_);
126 pref_change_registrar_.Add(
127 prefs::kGoogleServicesLastUsername,
128 base::Bind(&ManagedUserSyncService::OnLastSignedInUsernameChange,
129 base::Unretained(this)));
132 ManagedUserSyncService::~ManagedUserSyncService() {
136 void ManagedUserSyncService::RegisterProfilePrefs(
137 PrefRegistrySyncable* registry) {
138 registry->RegisterDictionaryPref(prefs::kManagedUsers,
139 PrefRegistrySyncable::UNSYNCABLE_PREF);
143 bool ManagedUserSyncService::GetAvatarIndex(const std::string& avatar_str,
145 DCHECK(avatar_index);
146 if (avatar_str.empty()) {
147 *avatar_index = kNoAvatar;
150 #if defined(OS_CHROMEOS)
151 const char* prefix = kChromeOSAvatarPrefix;
153 const char* prefix = kChromeAvatarPrefix;
155 size_t prefix_len = strlen(prefix);
156 if (avatar_str.size() <= prefix_len ||
157 avatar_str.substr(0, prefix_len) != prefix) {
161 if (!base::StringToInt(avatar_str.substr(prefix_len), avatar_index))
164 const int kChromeOSDummyAvatarIndex = -111;
166 #if defined(OS_CHROMEOS)
167 return (*avatar_index == kChromeOSDummyAvatarIndex ||
168 (*avatar_index >= chromeos::kFirstDefaultImageIndex &&
169 *avatar_index < chromeos::kDefaultImagesCount));
171 // Check if the Chrome avatar index is set to a dummy value. Some early
172 // supervised user profiles on ChromeOS stored a dummy avatar index as a
173 // Chrome Avatar before there was logic to sync the ChromeOS avatar
174 // separately. Handle this as if the Chrome Avatar was not chosen yet (which
175 // is correct for these profiles).
176 if (*avatar_index == kChromeOSDummyAvatarIndex)
177 *avatar_index = kNoAvatar;
178 return (*avatar_index == kNoAvatar ||
179 (*avatar_index >= 0 &&
180 static_cast<size_t>(*avatar_index) <
181 ProfileInfoCache::GetDefaultAvatarIconCount()));
186 std::string ManagedUserSyncService::BuildAvatarString(int avatar_index) {
187 #if defined(OS_CHROMEOS)
188 const char* prefix = kChromeOSAvatarPrefix;
190 const char* prefix = kChromeAvatarPrefix;
192 return base::StringPrintf("%s%d", prefix, avatar_index);
195 void ManagedUserSyncService::AddObserver(
196 ManagedUserSyncServiceObserver* observer) {
197 observers_.AddObserver(observer);
200 void ManagedUserSyncService::RemoveObserver(
201 ManagedUserSyncServiceObserver* observer) {
202 observers_.RemoveObserver(observer);
205 scoped_ptr<base::DictionaryValue> ManagedUserSyncService::CreateDictionary(
206 const std::string& name,
207 const std::string& master_key,
208 const std::string& signature_key,
209 const std::string& encryption_key,
211 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
212 result->SetString(kName, name);
213 result->SetString(kMasterKey, master_key);
214 result->SetString(kPasswordSignatureKey, signature_key);
215 result->SetString(kPasswordEncryptionKey, encryption_key);
216 // TODO(akuegel): Get rid of the avatar stuff here when Chrome OS switches
217 // to the avatar index that is stored as a shared setting.
218 std::string chrome_avatar;
219 std::string chromeos_avatar;
220 #if defined(OS_CHROMEOS)
221 chromeos_avatar = BuildAvatarString(avatar_index);
223 chrome_avatar = BuildAvatarString(avatar_index);
225 result->SetString(kChromeAvatar, chrome_avatar);
226 result->SetString(kChromeOsAvatar, chromeos_avatar);
227 return result.Pass();
230 void ManagedUserSyncService::AddManagedUser(const std::string& id,
231 const std::string& name,
232 const std::string& master_key,
233 const std::string& signature_key,
234 const std::string& encryption_key,
236 UpdateManagedUserImpl(id,
245 void ManagedUserSyncService::UpdateManagedUser(
246 const std::string& id,
247 const std::string& name,
248 const std::string& master_key,
249 const std::string& signature_key,
250 const std::string& encryption_key,
252 UpdateManagedUserImpl(id,
261 void ManagedUserSyncService::UpdateManagedUserImpl(
262 const std::string& id,
263 const std::string& name,
264 const std::string& master_key,
265 const std::string& signature_key,
266 const std::string& encryption_key,
269 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
270 base::DictionaryValue* dict = update.Get();
271 scoped_ptr<base::DictionaryValue> value = CreateDictionary(
272 name, master_key, signature_key, encryption_key, avatar_index);
274 DCHECK_EQ(add_user, !dict->HasKey(id));
275 base::DictionaryValue* entry = value.get();
276 dict->SetWithoutPathExpansion(id, value.release());
278 if (!sync_processor_)
281 // If we're already syncing, create a new change and upload it.
282 SyncChangeList change_list;
283 change_list.push_back(
284 SyncChange(FROM_HERE,
285 add_user ? SyncChange::ACTION_ADD : SyncChange::ACTION_UPDATE,
286 CreateSyncDataFromDictionaryEntry(id, *entry)));
288 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
289 DCHECK(!error.IsSet()) << error.ToString();
292 void ManagedUserSyncService::DeleteManagedUser(const std::string& id) {
293 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
294 bool success = update->RemoveWithoutPathExpansion(id, NULL);
297 if (!sync_processor_)
300 SyncChangeList change_list;
301 change_list.push_back(SyncChange(
303 SyncChange::ACTION_DELETE,
304 SyncData::CreateLocalDelete(id, MANAGED_USERS)));
305 SyncError sync_error =
306 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
307 DCHECK(!sync_error.IsSet());
310 const base::DictionaryValue* ManagedUserSyncService::GetManagedUsers() {
311 DCHECK(sync_processor_);
312 return prefs_->GetDictionary(prefs::kManagedUsers);
315 bool ManagedUserSyncService::UpdateManagedUserAvatarIfNeeded(
316 const std::string& id,
318 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
319 base::DictionaryValue* dict = update.Get();
320 DCHECK(dict->HasKey(id));
321 base::DictionaryValue* value = NULL;
322 bool success = dict->GetDictionaryWithoutPathExpansion(id, &value);
325 bool acknowledged = false;
326 value->GetBoolean(ManagedUserSyncService::kAcknowledged, &acknowledged);
328 value->GetString(ManagedUserSyncService::kName, &name);
329 std::string master_key;
330 value->GetString(ManagedUserSyncService::kMasterKey, &master_key);
331 std::string signature;
332 value->GetString(ManagedUserSyncService::kPasswordSignatureKey, &signature);
333 std::string encryption;
334 value->GetString(ManagedUserSyncService::kPasswordEncryptionKey, &encryption);
335 std::string chromeos_avatar;
336 value->GetString(ManagedUserSyncService::kChromeOsAvatar, &chromeos_avatar);
337 std::string chrome_avatar;
338 value->GetString(ManagedUserSyncService::kChromeAvatar, &chrome_avatar);
339 // The following check is just for safety. We want to avoid that the existing
340 // avatar selection is overwritten. Currently we don't allow the user to
341 // choose a different avatar in the recreation dialog, anyway, if there is
342 // already an avatar selected.
343 #if defined(OS_CHROMEOS)
344 if (!chromeos_avatar.empty() && avatar_index != kNoAvatar)
347 if (!chrome_avatar.empty() && avatar_index != kNoAvatar)
351 chrome_avatar = avatar_index == kNoAvatar ?
352 std::string() : BuildAvatarString(avatar_index);
353 #if defined(OS_CHROMEOS)
354 value->SetString(kChromeOsAvatar, chrome_avatar);
356 value->SetString(kChromeAvatar, chrome_avatar);
359 if (!sync_processor_)
362 SyncChangeList change_list;
363 change_list.push_back(SyncChange(
365 SyncChange::ACTION_UPDATE,
366 CreateLocalSyncData(id, name, acknowledged, master_key,
367 chrome_avatar, chromeos_avatar,
368 signature, encryption)));
370 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
371 DCHECK(!error.IsSet()) << error.ToString();
375 void ManagedUserSyncService::ClearManagedUserAvatar(const std::string& id) {
376 bool cleared = UpdateManagedUserAvatarIfNeeded(id, kNoAvatar);
380 void ManagedUserSyncService::GetManagedUsersAsync(
381 const ManagedUsersCallback& callback) {
382 // If we are already syncing, just run the callback.
383 if (sync_processor_) {
384 callback.Run(GetManagedUsers());
388 // Otherwise queue it up until we start syncing.
389 callbacks_.push_back(callback);
392 void ManagedUserSyncService::Shutdown() {
393 NotifyManagedUsersSyncingStopped();
396 SyncMergeResult ManagedUserSyncService::MergeDataAndStartSyncing(
398 const SyncDataList& initial_sync_data,
399 scoped_ptr<SyncChangeProcessor> sync_processor,
400 scoped_ptr<SyncErrorFactory> error_handler) {
401 DCHECK_EQ(MANAGED_USERS, type);
402 sync_processor_ = sync_processor.Pass();
403 error_handler_ = error_handler.Pass();
405 SyncChangeList change_list;
406 SyncMergeResult result(MANAGED_USERS);
408 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
409 base::DictionaryValue* dict = update.Get();
410 result.set_num_items_before_association(dict->size());
411 std::set<std::string> seen_ids;
412 int num_items_added = 0;
413 int num_items_modified = 0;
414 for (SyncDataList::const_iterator it = initial_sync_data.begin();
415 it != initial_sync_data.end(); ++it) {
416 DCHECK_EQ(MANAGED_USERS, it->GetDataType());
417 const ManagedUserSpecifics& managed_user =
418 it->GetSpecifics().managed_user();
419 base::DictionaryValue* value = new base::DictionaryValue();
420 value->SetString(kName, managed_user.name());
421 value->SetBoolean(kAcknowledged, managed_user.acknowledged());
422 value->SetString(kMasterKey, managed_user.master_key());
423 value->SetString(kChromeAvatar, managed_user.chrome_avatar());
424 value->SetString(kChromeOsAvatar, managed_user.chromeos_avatar());
425 value->SetString(kPasswordSignatureKey,
426 managed_user.password_signature_key());
427 value->SetString(kPasswordEncryptionKey,
428 managed_user.password_encryption_key());
429 if (dict->HasKey(managed_user.id()))
430 num_items_modified++;
433 dict->SetWithoutPathExpansion(managed_user.id(), value);
434 seen_ids.insert(managed_user.id());
437 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
438 if (seen_ids.find(it.key()) != seen_ids.end())
441 change_list.push_back(
442 SyncChange(FROM_HERE,
443 SyncChange::ACTION_ADD,
444 CreateSyncDataFromDictionaryEntry(it.key(), it.value())));
446 result.set_error(sync_processor_->ProcessSyncChanges(FROM_HERE, change_list));
448 result.set_num_items_modified(num_items_modified);
449 result.set_num_items_added(num_items_added);
450 result.set_num_items_after_association(dict->size());
457 void ManagedUserSyncService::StopSyncing(ModelType type) {
458 DCHECK_EQ(MANAGED_USERS, type);
459 // The observers may want to change the Sync data, so notify them before
460 // resetting the |sync_processor_|.
461 NotifyManagedUsersSyncingStopped();
462 sync_processor_.reset();
463 error_handler_.reset();
466 SyncDataList ManagedUserSyncService::GetAllSyncData(
467 ModelType type) const {
469 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
470 base::DictionaryValue* dict = update.Get();
471 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance())
472 data.push_back(CreateSyncDataFromDictionaryEntry(it.key(), it.value()));
477 SyncError ManagedUserSyncService::ProcessSyncChanges(
478 const tracked_objects::Location& from_here,
479 const SyncChangeList& change_list) {
481 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
482 base::DictionaryValue* dict = update.Get();
483 for (SyncChangeList::const_iterator it = change_list.begin();
484 it != change_list.end(); ++it) {
485 SyncData data = it->sync_data();
486 DCHECK_EQ(MANAGED_USERS, data.GetDataType());
487 const ManagedUserSpecifics& managed_user =
488 data.GetSpecifics().managed_user();
489 switch (it->change_type()) {
490 case SyncChange::ACTION_ADD:
491 case SyncChange::ACTION_UPDATE: {
492 // Every item we get from the server should be acknowledged.
493 DCHECK(managed_user.acknowledged());
494 const base::DictionaryValue* old_value = NULL;
495 dict->GetDictionaryWithoutPathExpansion(managed_user.id(), &old_value);
497 // For an update action, the managed user should already exist, for an
498 // add action, it should not.
500 old_value ? SyncChange::ACTION_UPDATE : SyncChange::ACTION_ADD,
503 // If the managed user switched from unacknowledged to acknowledged,
504 // we might need to continue with a registration.
505 if (old_value && !old_value->HasKey(kAcknowledged))
506 NotifyManagedUserAcknowledged(managed_user.id());
508 base::DictionaryValue* value = new base::DictionaryValue;
509 value->SetString(kName, managed_user.name());
510 value->SetBoolean(kAcknowledged, managed_user.acknowledged());
511 value->SetString(kMasterKey, managed_user.master_key());
512 value->SetString(kChromeAvatar, managed_user.chrome_avatar());
513 value->SetString(kChromeOsAvatar, managed_user.chromeos_avatar());
514 value->SetString(kPasswordSignatureKey,
515 managed_user.password_signature_key());
516 value->SetString(kPasswordEncryptionKey,
517 managed_user.password_encryption_key());
518 dict->SetWithoutPathExpansion(managed_user.id(), value);
520 NotifyManagedUsersChanged();
523 case SyncChange::ACTION_DELETE: {
524 DCHECK(dict->HasKey(managed_user.id())) << managed_user.id();
525 dict->RemoveWithoutPathExpansion(managed_user.id(), NULL);
528 case SyncChange::ACTION_INVALID: {
537 void ManagedUserSyncService::OnLastSignedInUsernameChange() {
538 DCHECK(!sync_processor_);
540 // If the last signed in user changes, we clear all data, to avoid managed
541 // users from one custodian appearing in another one's profile.
542 prefs_->ClearPref(prefs::kManagedUsers);
545 void ManagedUserSyncService::NotifyManagedUserAcknowledged(
546 const std::string& managed_user_id) {
547 FOR_EACH_OBSERVER(ManagedUserSyncServiceObserver, observers_,
548 OnManagedUserAcknowledged(managed_user_id));
551 void ManagedUserSyncService::NotifyManagedUsersSyncingStopped() {
552 FOR_EACH_OBSERVER(ManagedUserSyncServiceObserver, observers_,
553 OnManagedUsersSyncingStopped());
556 void ManagedUserSyncService::NotifyManagedUsersChanged() {
557 FOR_EACH_OBSERVER(ManagedUserSyncServiceObserver,
559 OnManagedUsersChanged());
562 void ManagedUserSyncService::DispatchCallbacks() {
563 const base::DictionaryValue* managed_users =
564 prefs_->GetDictionary(prefs::kManagedUsers);
565 for (std::vector<ManagedUsersCallback>::iterator it = callbacks_.begin();
566 it != callbacks_.end(); ++it) {
567 it->Run(managed_users);