Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / supervised_user / supervised_user_sync_service.cc
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.
4
5 #include "chrome/browser/supervised_user/supervised_user_sync_service.h"
6
7 #include "base/bind.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"
22
23 #if defined(OS_CHROMEOS)
24 #include "components/user_manager/user_image/default_user_images.h"
25 #endif
26
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;
40
41 namespace {
42
43 #if defined(OS_CHROMEOS)
44 const char kChromeOSAvatarPrefix[] = "chromeos-avatar-index:";
45 #else
46 const char kChromeAvatarPrefix[] = "chrome-avatar-index:";
47 #endif
48
49 SyncData CreateLocalSyncData(const std::string& id,
50                              const std::string& name,
51                              bool acknowledged,
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);
66   if (acknowledged)
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);
71   }
72   if (!password_encryption_key.empty()) {
73     specifics.mutable_managed_user()->
74         set_password_encryption_key(password_encryption_key);
75   }
76   return SyncData::CreateLocalData(id, name, specifics);
77 }
78
79 SyncData CreateSyncDataFromDictionaryEntry(const std::string& id,
80                                            const base::Value& value) {
81   const base::DictionaryValue* dict = NULL;
82   bool success = value.GetAsDictionary(&dict);
83   DCHECK(success);
84   bool acknowledged = false;
85   dict->GetBoolean(SupervisedUserSyncService::kAcknowledged, &acknowledged);
86   std::string name;
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,
99                   &encryption);
100
101   return CreateLocalSyncData(id,
102                              name,
103                              acknowledged,
104                              master_key,
105                              chrome_avatar,
106                              chromeos_avatar,
107                              signature,
108                              encryption);
109 }
110
111 }  // namespace
112
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;
123
124 SupervisedUserSyncService::SupervisedUserSyncService(PrefService* prefs)
125     : prefs_(prefs) {
126   pref_change_registrar_.Init(prefs_);
127   pref_change_registrar_.Add(
128       prefs::kGoogleServicesLastUsername,
129       base::Bind(&SupervisedUserSyncService::OnLastSignedInUsernameChange,
130                  base::Unretained(this)));
131 }
132
133 SupervisedUserSyncService::~SupervisedUserSyncService() {
134 }
135
136 // static
137 void SupervisedUserSyncService::RegisterProfilePrefs(
138     PrefRegistrySyncable* registry) {
139   registry->RegisterDictionaryPref(prefs::kSupervisedUsers,
140                                    PrefRegistrySyncable::UNSYNCABLE_PREF);
141 }
142
143 // static
144 bool SupervisedUserSyncService::GetAvatarIndex(const std::string& avatar_str,
145                                                int* avatar_index) {
146   DCHECK(avatar_index);
147   if (avatar_str.empty()) {
148     *avatar_index = kNoAvatar;
149     return true;
150   }
151 #if defined(OS_CHROMEOS)
152   const char* prefix = kChromeOSAvatarPrefix;
153 #else
154   const char* prefix = kChromeAvatarPrefix;
155 #endif
156   size_t prefix_len = strlen(prefix);
157   if (avatar_str.size() <= prefix_len ||
158       avatar_str.substr(0, prefix_len) != prefix) {
159     return false;
160   }
161
162   if (!base::StringToInt(avatar_str.substr(prefix_len), avatar_index))
163     return false;
164
165   const int kChromeOSDummyAvatarIndex = -111;
166
167 #if defined(OS_CHROMEOS)
168   return (*avatar_index == kChromeOSDummyAvatarIndex ||
169           (*avatar_index >= user_manager::kFirstDefaultImageIndex &&
170            *avatar_index < user_manager::kDefaultImagesCount));
171 #else
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()));
183 #endif
184 }
185
186 // static
187 std::string SupervisedUserSyncService::BuildAvatarString(int avatar_index) {
188 #if defined(OS_CHROMEOS)
189   const char* prefix = kChromeOSAvatarPrefix;
190 #else
191   const char* prefix = kChromeAvatarPrefix;
192 #endif
193   return base::StringPrintf("%s%d", prefix, avatar_index);
194 }
195
196 void SupervisedUserSyncService::AddObserver(
197     SupervisedUserSyncServiceObserver* observer) {
198   observers_.AddObserver(observer);
199 }
200
201 void SupervisedUserSyncService::RemoveObserver(
202     SupervisedUserSyncServiceObserver* observer) {
203   observers_.RemoveObserver(observer);
204 }
205
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,
211     int avatar_index) {
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);
223 #else
224   chrome_avatar = BuildAvatarString(avatar_index);
225 #endif
226   result->SetString(kChromeAvatar, chrome_avatar);
227   result->SetString(kChromeOsAvatar, chromeos_avatar);
228   return result.Pass();
229 }
230
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,
237     int avatar_index) {
238   UpdateSupervisedUserImpl(id,
239                            name,
240                            master_key,
241                            signature_key,
242                            encryption_key,
243                            avatar_index,
244                            true /* add */);
245 }
246
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,
253     int avatar_index) {
254   UpdateSupervisedUserImpl(id,
255                            name,
256                            master_key,
257                            signature_key,
258                            encryption_key,
259                            avatar_index,
260                            false /* update */);
261 }
262
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,
269     int avatar_index,
270     bool add_user) {
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);
275
276   DCHECK_EQ(add_user, !dict->HasKey(id));
277   base::DictionaryValue* entry = value.get();
278   dict->SetWithoutPathExpansion(id, value.release());
279
280   if (!sync_processor_)
281     return;
282
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)));
289   SyncError error =
290       sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
291   DCHECK(!error.IsSet()) << error.ToString();
292 }
293
294 void SupervisedUserSyncService::DeleteSupervisedUser(const std::string& id) {
295   DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
296   bool success = update->RemoveWithoutPathExpansion(id, NULL);
297   DCHECK(success);
298
299   if (!sync_processor_)
300     return;
301
302   SyncChangeList change_list;
303   change_list.push_back(SyncChange(
304       FROM_HERE,
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());
310 }
311
312 const base::DictionaryValue* SupervisedUserSyncService::GetSupervisedUsers() {
313   DCHECK(sync_processor_);
314   return prefs_->GetDictionary(prefs::kSupervisedUsers);
315 }
316
317 bool SupervisedUserSyncService::UpdateSupervisedUserAvatarIfNeeded(
318     const std::string& id,
319     int avatar_index) {
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);
325   DCHECK(success);
326
327   bool acknowledged = false;
328   value->GetBoolean(SupervisedUserSyncService::kAcknowledged, &acknowledged);
329   std::string name;
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,
335                    &signature);
336   std::string encryption;
337   value->GetString(SupervisedUserSyncService::kPasswordEncryptionKey,
338                    &encryption);
339   std::string chromeos_avatar;
340   value->GetString(SupervisedUserSyncService::kChromeOsAvatar,
341                    &chromeos_avatar);
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)
350     return false;
351 #else
352   if (!chrome_avatar.empty() && avatar_index != kNoAvatar)
353     return false;
354 #endif
355
356   chrome_avatar = avatar_index == kNoAvatar ?
357       std::string() : BuildAvatarString(avatar_index);
358 #if defined(OS_CHROMEOS)
359   value->SetString(kChromeOsAvatar, chrome_avatar);
360 #else
361   value->SetString(kChromeAvatar, chrome_avatar);
362 #endif
363
364   if (!sync_processor_)
365     return true;
366
367   SyncChangeList change_list;
368   change_list.push_back(SyncChange(
369       FROM_HERE,
370       SyncChange::ACTION_UPDATE,
371       CreateLocalSyncData(id, name, acknowledged, master_key,
372                           chrome_avatar, chromeos_avatar,
373                           signature, encryption)));
374   SyncError error =
375       sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
376   DCHECK(!error.IsSet()) << error.ToString();
377   return true;
378 }
379
380 void SupervisedUserSyncService::ClearSupervisedUserAvatar(
381     const std::string& id) {
382   bool cleared = UpdateSupervisedUserAvatarIfNeeded(id, kNoAvatar);
383   DCHECK(cleared);
384 }
385
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());
391     return;
392   }
393
394   // Otherwise queue it up until we start syncing.
395   callbacks_.push_back(callback);
396 }
397
398 void SupervisedUserSyncService::Shutdown() {
399   NotifySupervisedUsersSyncingStopped();
400 }
401
402 SyncMergeResult SupervisedUserSyncService::MergeDataAndStartSyncing(
403     ModelType type,
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();
410
411   SyncChangeList change_list;
412   SyncMergeResult result(SUPERVISED_USERS);
413
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++;
437     else
438       num_items_added++;
439     dict->SetWithoutPathExpansion(supervised_user.id(), value);
440     seen_ids.insert(supervised_user.id());
441   }
442
443   for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
444     if (seen_ids.find(it.key()) != seen_ids.end())
445       continue;
446
447     change_list.push_back(
448         SyncChange(FROM_HERE,
449                    SyncChange::ACTION_ADD,
450                    CreateSyncDataFromDictionaryEntry(it.key(), it.value())));
451   }
452   result.set_error(sync_processor_->ProcessSyncChanges(FROM_HERE, change_list));
453
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());
457
458   DispatchCallbacks();
459
460   return result;
461 }
462
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();
470 }
471
472 SyncDataList SupervisedUserSyncService::GetAllSyncData(
473     ModelType type) const {
474   SyncDataList data;
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()));
479
480   return data;
481 }
482
483 SyncError SupervisedUserSyncService::ProcessSyncChanges(
484     const tracked_objects::Location& from_here,
485     const SyncChangeList& change_list) {
486   SyncError error;
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(),
502                                                 &old_value);
503
504         // For an update action, the supervised user should already exist, for
505         // an add action, it should not.
506         DCHECK_EQ(
507             old_value ? SyncChange::ACTION_UPDATE : SyncChange::ACTION_ADD,
508             it->change_type());
509
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());
514
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);
526
527         NotifySupervisedUsersChanged();
528         break;
529       }
530       case SyncChange::ACTION_DELETE: {
531         DCHECK(dict->HasKey(supervised_user.id())) << supervised_user.id();
532         dict->RemoveWithoutPathExpansion(supervised_user.id(), NULL);
533         break;
534       }
535       case SyncChange::ACTION_INVALID: {
536         NOTREACHED();
537         break;
538       }
539     }
540   }
541   return error;
542 }
543
544 void SupervisedUserSyncService::OnLastSignedInUsernameChange() {
545   DCHECK(!sync_processor_);
546
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);
550 }
551
552 void SupervisedUserSyncService::NotifySupervisedUserAcknowledged(
553     const std::string& supervised_user_id) {
554   FOR_EACH_OBSERVER(SupervisedUserSyncServiceObserver, observers_,
555                     OnSupervisedUserAcknowledged(supervised_user_id));
556 }
557
558 void SupervisedUserSyncService::NotifySupervisedUsersSyncingStopped() {
559   FOR_EACH_OBSERVER(SupervisedUserSyncServiceObserver, observers_,
560                     OnSupervisedUsersSyncingStopped());
561 }
562
563 void SupervisedUserSyncService::NotifySupervisedUsersChanged() {
564   FOR_EACH_OBSERVER(SupervisedUserSyncServiceObserver,
565                     observers_,
566                     OnSupervisedUsersChanged());
567 }
568
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);
575   }
576   callbacks_.clear();
577 }