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 } 578