1 // Copyright 2014 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/supervised_user/supervised_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_avatar_icon_util.h"
14 #include "chrome/common/pref_names.h"
15 #include "components/pref_registry/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 "components/user_manager/user_image/default_user_images.h"
27 using base::DictionaryValue
;
28 using user_prefs::PrefRegistrySyncable
;
29 using syncer::SUPERVISED_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(SupervisedUserSyncService::kAcknowledged
, &acknowledged
);
87 dict
->GetString(SupervisedUserSyncService::kName
, &name
);
88 DCHECK(!name
.empty());
89 std::string master_key
;
90 dict
->GetString(SupervisedUserSyncService::kMasterKey
, &master_key
);
91 std::string chrome_avatar
;
92 dict
->GetString(SupervisedUserSyncService::kChromeAvatar
, &chrome_avatar
);
93 std::string chromeos_avatar
;
94 dict
->GetString(SupervisedUserSyncService::kChromeOsAvatar
, &chromeos_avatar
);
95 std::string signature
;
96 dict
->GetString(SupervisedUserSyncService::kPasswordSignatureKey
, &signature
);
97 std::string encryption
;
98 dict
->GetString(SupervisedUserSyncService::kPasswordEncryptionKey
,
101 return CreateLocalSyncData(id
,
113 const char SupervisedUserSyncService::kAcknowledged
[] = "acknowledged";
114 const char SupervisedUserSyncService::kChromeAvatar
[] = "chromeAvatar";
115 const char SupervisedUserSyncService::kChromeOsAvatar
[] = "chromeOsAvatar";
116 const char SupervisedUserSyncService::kMasterKey
[] = "masterKey";
117 const char SupervisedUserSyncService::kName
[] = "name";
118 const char SupervisedUserSyncService::kPasswordSignatureKey
[] =
119 "passwordSignatureKey";
120 const char SupervisedUserSyncService::kPasswordEncryptionKey
[] =
121 "passwordEncryptionKey";
122 const int SupervisedUserSyncService::kNoAvatar
= -100;
124 SupervisedUserSyncService::SupervisedUserSyncService(PrefService
* prefs
)
126 pref_change_registrar_
.Init(prefs_
);
127 pref_change_registrar_
.Add(
128 prefs::kGoogleServicesLastUsername
,
129 base::Bind(&SupervisedUserSyncService::OnLastSignedInUsernameChange
,
130 base::Unretained(this)));
133 SupervisedUserSyncService::~SupervisedUserSyncService() {
137 void SupervisedUserSyncService::RegisterProfilePrefs(
138 PrefRegistrySyncable
* registry
) {
139 registry
->RegisterDictionaryPref(prefs::kSupervisedUsers
,
140 PrefRegistrySyncable::UNSYNCABLE_PREF
);
144 bool SupervisedUserSyncService::GetAvatarIndex(const std::string
& avatar_str
,
146 DCHECK(avatar_index
);
147 if (avatar_str
.empty()) {
148 *avatar_index
= kNoAvatar
;
151 #if defined(OS_CHROMEOS)
152 const char* prefix
= kChromeOSAvatarPrefix
;
154 const char* prefix
= kChromeAvatarPrefix
;
156 size_t prefix_len
= strlen(prefix
);
157 if (avatar_str
.size() <= prefix_len
||
158 avatar_str
.substr(0, prefix_len
) != prefix
) {
162 if (!base::StringToInt(avatar_str
.substr(prefix_len
), avatar_index
))
165 const int kChromeOSDummyAvatarIndex
= -111;
167 #if defined(OS_CHROMEOS)
168 return (*avatar_index
== kChromeOSDummyAvatarIndex
||
169 (*avatar_index
>= user_manager::kFirstDefaultImageIndex
&&
170 *avatar_index
< user_manager::kDefaultImagesCount
));
172 // Check if the Chrome avatar index is set to a dummy value. Some early
173 // supervised user profiles on ChromeOS stored a dummy avatar index as a
174 // Chrome Avatar before there was logic to sync the ChromeOS avatar
175 // separately. Handle this as if the Chrome Avatar was not chosen yet (which
176 // is correct for these profiles).
177 if (*avatar_index
== kChromeOSDummyAvatarIndex
)
178 *avatar_index
= kNoAvatar
;
179 return (*avatar_index
== kNoAvatar
||
180 (*avatar_index
>= 0 &&
181 static_cast<size_t>(*avatar_index
) <
182 profiles::GetDefaultAvatarIconCount()));
187 std::string
SupervisedUserSyncService::BuildAvatarString(int avatar_index
) {
188 #if defined(OS_CHROMEOS)
189 const char* prefix
= kChromeOSAvatarPrefix
;
191 const char* prefix
= kChromeAvatarPrefix
;
193 return base::StringPrintf("%s%d", prefix
, avatar_index
);
196 void SupervisedUserSyncService::AddObserver(
197 SupervisedUserSyncServiceObserver
* observer
) {
198 observers_
.AddObserver(observer
);
201 void SupervisedUserSyncService::RemoveObserver(
202 SupervisedUserSyncServiceObserver
* observer
) {
203 observers_
.RemoveObserver(observer
);
206 scoped_ptr
<base::DictionaryValue
> SupervisedUserSyncService::CreateDictionary(
207 const std::string
& name
,
208 const std::string
& master_key
,
209 const std::string
& signature_key
,
210 const std::string
& encryption_key
,
212 scoped_ptr
<base::DictionaryValue
> result(new base::DictionaryValue());
213 result
->SetString(kName
, name
);
214 result
->SetString(kMasterKey
, master_key
);
215 result
->SetString(kPasswordSignatureKey
, signature_key
);
216 result
->SetString(kPasswordEncryptionKey
, encryption_key
);
217 // TODO(akuegel): Get rid of the avatar stuff here when Chrome OS switches
218 // to the avatar index that is stored as a shared setting.
219 std::string chrome_avatar
;
220 std::string chromeos_avatar
;
221 #if defined(OS_CHROMEOS)
222 chromeos_avatar
= BuildAvatarString(avatar_index
);
224 chrome_avatar
= BuildAvatarString(avatar_index
);
226 result
->SetString(kChromeAvatar
, chrome_avatar
);
227 result
->SetString(kChromeOsAvatar
, chromeos_avatar
);
228 return result
.Pass();
231 void SupervisedUserSyncService::AddSupervisedUser(
232 const std::string
& id
,
233 const std::string
& name
,
234 const std::string
& master_key
,
235 const std::string
& signature_key
,
236 const std::string
& encryption_key
,
238 UpdateSupervisedUserImpl(id
,
247 void SupervisedUserSyncService::UpdateSupervisedUser(
248 const std::string
& id
,
249 const std::string
& name
,
250 const std::string
& master_key
,
251 const std::string
& signature_key
,
252 const std::string
& encryption_key
,
254 UpdateSupervisedUserImpl(id
,
263 void SupervisedUserSyncService::UpdateSupervisedUserImpl(
264 const std::string
& id
,
265 const std::string
& name
,
266 const std::string
& master_key
,
267 const std::string
& signature_key
,
268 const std::string
& encryption_key
,
271 DictionaryPrefUpdate
update(prefs_
, prefs::kSupervisedUsers
);
272 base::DictionaryValue
* dict
= update
.Get();
273 scoped_ptr
<base::DictionaryValue
> value
= CreateDictionary(
274 name
, master_key
, signature_key
, encryption_key
, avatar_index
);
276 DCHECK_EQ(add_user
, !dict
->HasKey(id
));
277 base::DictionaryValue
* entry
= value
.get();
278 dict
->SetWithoutPathExpansion(id
, value
.release());
280 if (!sync_processor_
)
283 // If we're already syncing, create a new change and upload it.
284 SyncChangeList change_list
;
285 change_list
.push_back(
286 SyncChange(FROM_HERE
,
287 add_user
? SyncChange::ACTION_ADD
: SyncChange::ACTION_UPDATE
,
288 CreateSyncDataFromDictionaryEntry(id
, *entry
)));
290 sync_processor_
->ProcessSyncChanges(FROM_HERE
, change_list
);
291 DCHECK(!error
.IsSet()) << error
.ToString();
294 void SupervisedUserSyncService::DeleteSupervisedUser(const std::string
& id
) {
295 DictionaryPrefUpdate
update(prefs_
, prefs::kSupervisedUsers
);
296 bool success
= update
->RemoveWithoutPathExpansion(id
, NULL
);
299 if (!sync_processor_
)
302 SyncChangeList change_list
;
303 change_list
.push_back(SyncChange(
305 SyncChange::ACTION_DELETE
,
306 SyncData::CreateLocalDelete(id
, SUPERVISED_USERS
)));
307 SyncError sync_error
=
308 sync_processor_
->ProcessSyncChanges(FROM_HERE
, change_list
);
309 DCHECK(!sync_error
.IsSet());
312 const base::DictionaryValue
* SupervisedUserSyncService::GetSupervisedUsers() {
313 DCHECK(sync_processor_
);
314 return prefs_
->GetDictionary(prefs::kSupervisedUsers
);
317 bool SupervisedUserSyncService::UpdateSupervisedUserAvatarIfNeeded(
318 const std::string
& id
,
320 DictionaryPrefUpdate
update(prefs_
, prefs::kSupervisedUsers
);
321 base::DictionaryValue
* dict
= update
.Get();
322 DCHECK(dict
->HasKey(id
));
323 base::DictionaryValue
* value
= NULL
;
324 bool success
= dict
->GetDictionaryWithoutPathExpansion(id
, &value
);
327 bool acknowledged
= false;
328 value
->GetBoolean(SupervisedUserSyncService::kAcknowledged
, &acknowledged
);
330 value
->GetString(SupervisedUserSyncService::kName
, &name
);
331 std::string master_key
;
332 value
->GetString(SupervisedUserSyncService::kMasterKey
, &master_key
);
333 std::string signature
;
334 value
->GetString(SupervisedUserSyncService::kPasswordSignatureKey
,
336 std::string encryption
;
337 value
->GetString(SupervisedUserSyncService::kPasswordEncryptionKey
,
339 std::string chromeos_avatar
;
340 value
->GetString(SupervisedUserSyncService::kChromeOsAvatar
,
342 std::string chrome_avatar
;
343 value
->GetString(SupervisedUserSyncService::kChromeAvatar
, &chrome_avatar
);
344 // The following check is just for safety. We want to avoid that the existing
345 // avatar selection is overwritten. Currently we don't allow the user to
346 // choose a different avatar in the recreation dialog, anyway, if there is
347 // already an avatar selected.
348 #if defined(OS_CHROMEOS)
349 if (!chromeos_avatar
.empty() && avatar_index
!= kNoAvatar
)
352 if (!chrome_avatar
.empty() && avatar_index
!= kNoAvatar
)
356 chrome_avatar
= avatar_index
== kNoAvatar
?
357 std::string() : BuildAvatarString(avatar_index
);
358 #if defined(OS_CHROMEOS)
359 value
->SetString(kChromeOsAvatar
, chrome_avatar
);
361 value
->SetString(kChromeAvatar
, chrome_avatar
);
364 if (!sync_processor_
)
367 SyncChangeList change_list
;
368 change_list
.push_back(SyncChange(
370 SyncChange::ACTION_UPDATE
,
371 CreateLocalSyncData(id
, name
, acknowledged
, master_key
,
372 chrome_avatar
, chromeos_avatar
,
373 signature
, encryption
)));
375 sync_processor_
->ProcessSyncChanges(FROM_HERE
, change_list
);
376 DCHECK(!error
.IsSet()) << error
.ToString();
380 void SupervisedUserSyncService::ClearSupervisedUserAvatar(
381 const std::string
& id
) {
382 bool cleared
= UpdateSupervisedUserAvatarIfNeeded(id
, kNoAvatar
);
386 void SupervisedUserSyncService::GetSupervisedUsersAsync(
387 const SupervisedUsersCallback
& callback
) {
388 // If we are already syncing, just run the callback.
389 if (sync_processor_
) {
390 callback
.Run(GetSupervisedUsers());
394 // Otherwise queue it up until we start syncing.
395 callbacks_
.push_back(callback
);
398 void SupervisedUserSyncService::Shutdown() {
399 NotifySupervisedUsersSyncingStopped();
402 SyncMergeResult
SupervisedUserSyncService::MergeDataAndStartSyncing(
404 const SyncDataList
& initial_sync_data
,
405 scoped_ptr
<SyncChangeProcessor
> sync_processor
,
406 scoped_ptr
<SyncErrorFactory
> error_handler
) {
407 DCHECK_EQ(SUPERVISED_USERS
, type
);
408 sync_processor_
= sync_processor
.Pass();
409 error_handler_
= error_handler
.Pass();
411 SyncChangeList change_list
;
412 SyncMergeResult
result(SUPERVISED_USERS
);
414 DictionaryPrefUpdate
update(prefs_
, prefs::kSupervisedUsers
);
415 base::DictionaryValue
* dict
= update
.Get();
416 result
.set_num_items_before_association(dict
->size());
417 std::set
<std::string
> seen_ids
;
418 int num_items_added
= 0;
419 int num_items_modified
= 0;
420 for (SyncDataList::const_iterator it
= initial_sync_data
.begin();
421 it
!= initial_sync_data
.end(); ++it
) {
422 DCHECK_EQ(SUPERVISED_USERS
, it
->GetDataType());
423 const ManagedUserSpecifics
& supervised_user
=
424 it
->GetSpecifics().managed_user();
425 base::DictionaryValue
* value
= new base::DictionaryValue();
426 value
->SetString(kName
, supervised_user
.name());
427 value
->SetBoolean(kAcknowledged
, supervised_user
.acknowledged());
428 value
->SetString(kMasterKey
, supervised_user
.master_key());
429 value
->SetString(kChromeAvatar
, supervised_user
.chrome_avatar());
430 value
->SetString(kChromeOsAvatar
, supervised_user
.chromeos_avatar());
431 value
->SetString(kPasswordSignatureKey
,
432 supervised_user
.password_signature_key());
433 value
->SetString(kPasswordEncryptionKey
,
434 supervised_user
.password_encryption_key());
435 if (dict
->HasKey(supervised_user
.id()))
436 num_items_modified
++;
439 dict
->SetWithoutPathExpansion(supervised_user
.id(), value
);
440 seen_ids
.insert(supervised_user
.id());
443 for (base::DictionaryValue::Iterator
it(*dict
); !it
.IsAtEnd(); it
.Advance()) {
444 if (seen_ids
.find(it
.key()) != seen_ids
.end())
447 change_list
.push_back(
448 SyncChange(FROM_HERE
,
449 SyncChange::ACTION_ADD
,
450 CreateSyncDataFromDictionaryEntry(it
.key(), it
.value())));
452 result
.set_error(sync_processor_
->ProcessSyncChanges(FROM_HERE
, change_list
));
454 result
.set_num_items_modified(num_items_modified
);
455 result
.set_num_items_added(num_items_added
);
456 result
.set_num_items_after_association(dict
->size());
463 void SupervisedUserSyncService::StopSyncing(ModelType type
) {
464 DCHECK_EQ(SUPERVISED_USERS
, type
);
465 // The observers may want to change the Sync data, so notify them before
466 // resetting the |sync_processor_|.
467 NotifySupervisedUsersSyncingStopped();
468 sync_processor_
.reset();
469 error_handler_
.reset();
472 SyncDataList
SupervisedUserSyncService::GetAllSyncData(
473 ModelType type
) const {
475 DictionaryPrefUpdate
update(prefs_
, prefs::kSupervisedUsers
);
476 base::DictionaryValue
* dict
= update
.Get();
477 for (base::DictionaryValue::Iterator
it(*dict
); !it
.IsAtEnd(); it
.Advance())
478 data
.push_back(CreateSyncDataFromDictionaryEntry(it
.key(), it
.value()));
483 SyncError
SupervisedUserSyncService::ProcessSyncChanges(
484 const tracked_objects::Location
& from_here
,
485 const SyncChangeList
& change_list
) {
487 DictionaryPrefUpdate
update(prefs_
, prefs::kSupervisedUsers
);
488 base::DictionaryValue
* dict
= update
.Get();
489 for (SyncChangeList::const_iterator it
= change_list
.begin();
490 it
!= change_list
.end(); ++it
) {
491 SyncData data
= it
->sync_data();
492 DCHECK_EQ(SUPERVISED_USERS
, data
.GetDataType());
493 const ManagedUserSpecifics
& supervised_user
=
494 data
.GetSpecifics().managed_user();
495 switch (it
->change_type()) {
496 case SyncChange::ACTION_ADD
:
497 case SyncChange::ACTION_UPDATE
: {
498 // Every item we get from the server should be acknowledged.
499 DCHECK(supervised_user
.acknowledged());
500 const base::DictionaryValue
* old_value
= NULL
;
501 dict
->GetDictionaryWithoutPathExpansion(supervised_user
.id(),
504 // For an update action, the supervised user should already exist, for
505 // an add action, it should not.
507 old_value
? SyncChange::ACTION_UPDATE
: SyncChange::ACTION_ADD
,
510 // If the supervised user switched from unacknowledged to acknowledged,
511 // we might need to continue with a registration.
512 if (old_value
&& !old_value
->HasKey(kAcknowledged
))
513 NotifySupervisedUserAcknowledged(supervised_user
.id());
515 base::DictionaryValue
* value
= new base::DictionaryValue
;
516 value
->SetString(kName
, supervised_user
.name());
517 value
->SetBoolean(kAcknowledged
, supervised_user
.acknowledged());
518 value
->SetString(kMasterKey
, supervised_user
.master_key());
519 value
->SetString(kChromeAvatar
, supervised_user
.chrome_avatar());
520 value
->SetString(kChromeOsAvatar
, supervised_user
.chromeos_avatar());
521 value
->SetString(kPasswordSignatureKey
,
522 supervised_user
.password_signature_key());
523 value
->SetString(kPasswordEncryptionKey
,
524 supervised_user
.password_encryption_key());
525 dict
->SetWithoutPathExpansion(supervised_user
.id(), value
);
527 NotifySupervisedUsersChanged();
530 case SyncChange::ACTION_DELETE
: {
531 DCHECK(dict
->HasKey(supervised_user
.id())) << supervised_user
.id();
532 dict
->RemoveWithoutPathExpansion(supervised_user
.id(), NULL
);
535 case SyncChange::ACTION_INVALID
: {
544 void SupervisedUserSyncService::OnLastSignedInUsernameChange() {
545 DCHECK(!sync_processor_
);
547 // If the last signed in user changes, we clear all data, to avoid supervised
548 // users from one custodian appearing in another one's profile.
549 prefs_
->ClearPref(prefs::kSupervisedUsers
);
552 void SupervisedUserSyncService::NotifySupervisedUserAcknowledged(
553 const std::string
& supervised_user_id
) {
554 FOR_EACH_OBSERVER(SupervisedUserSyncServiceObserver
, observers_
,
555 OnSupervisedUserAcknowledged(supervised_user_id
));
558 void SupervisedUserSyncService::NotifySupervisedUsersSyncingStopped() {
559 FOR_EACH_OBSERVER(SupervisedUserSyncServiceObserver
, observers_
,
560 OnSupervisedUsersSyncingStopped());
563 void SupervisedUserSyncService::NotifySupervisedUsersChanged() {
564 FOR_EACH_OBSERVER(SupervisedUserSyncServiceObserver
,
566 OnSupervisedUsersChanged());
569 void SupervisedUserSyncService::DispatchCallbacks() {
570 const base::DictionaryValue
* supervised_users
=
571 prefs_
->GetDictionary(prefs::kSupervisedUsers
);
572 for (std::vector
<SupervisedUsersCallback
>::iterator it
= callbacks_
.begin();
573 it
!= callbacks_
.end(); ++it
) {
574 it
->Run(supervised_users
);