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 27using base::DictionaryValue; 28using user_prefs::PrefRegistrySyncable; 29using syncer::SUPERVISED_USERS; 30using syncer::ModelType; 31using syncer::SyncChange; 32using syncer::SyncChangeList; 33using syncer::SyncChangeProcessor; 34using syncer::SyncData; 35using syncer::SyncDataList; 36using syncer::SyncError; 37using syncer::SyncErrorFactory; 38using syncer::SyncMergeResult; 39using sync_pb::ManagedUserSpecifics; 40 41namespace { 42 43#if defined(OS_CHROMEOS) 44const char kChromeOSAvatarPrefix[] = "chromeos-avatar-index:"; 45#else 46const char kChromeAvatarPrefix[] = "chrome-avatar-index:"; 47#endif 48 49SyncData 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 79SyncData 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 113const char SupervisedUserSyncService::kAcknowledged[] = "acknowledged"; 114const char SupervisedUserSyncService::kChromeAvatar[] = "chromeAvatar"; 115const char SupervisedUserSyncService::kChromeOsAvatar[] = "chromeOsAvatar"; 116const char SupervisedUserSyncService::kMasterKey[] = "masterKey"; 117const char SupervisedUserSyncService::kName[] = "name"; 118const char SupervisedUserSyncService::kPasswordSignatureKey[] = 119 "passwordSignatureKey"; 120const char SupervisedUserSyncService::kPasswordEncryptionKey[] = 121 "passwordEncryptionKey"; 122const int SupervisedUserSyncService::kNoAvatar = -100; 123 124SupervisedUserSyncService::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 133SupervisedUserSyncService::~SupervisedUserSyncService() { 134} 135 136// static 137void SupervisedUserSyncService::RegisterProfilePrefs( 138 PrefRegistrySyncable* registry) { 139 registry->RegisterDictionaryPref(prefs::kSupervisedUsers, 140 PrefRegistrySyncable::UNSYNCABLE_PREF); 141} 142 143// static 144bool 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 187std::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 196void SupervisedUserSyncService::AddObserver( 197 SupervisedUserSyncServiceObserver* observer) { 198 observers_.AddObserver(observer); 199} 200 201void SupervisedUserSyncService::RemoveObserver( 202 SupervisedUserSyncServiceObserver* observer) { 203 observers_.RemoveObserver(observer); 204} 205 206scoped_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 231void 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 247void 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 263void 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 294void 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 312const base::DictionaryValue* SupervisedUserSyncService::GetSupervisedUsers() { 313 DCHECK(sync_processor_); 314 return prefs_->GetDictionary(prefs::kSupervisedUsers); 315} 316 317bool 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 380void SupervisedUserSyncService::ClearSupervisedUserAvatar( 381 const std::string& id) { 382 bool cleared = UpdateSupervisedUserAvatarIfNeeded(id, kNoAvatar); 383 DCHECK(cleared); 384} 385 386void 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 398void SupervisedUserSyncService::Shutdown() { 399 NotifySupervisedUsersSyncingStopped(); 400} 401 402SyncMergeResult 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 463void 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 472SyncDataList 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 483SyncError 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 544void 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 552void SupervisedUserSyncService::NotifySupervisedUserAcknowledged( 553 const std::string& supervised_user_id) { 554 FOR_EACH_OBSERVER(SupervisedUserSyncServiceObserver, observers_, 555 OnSupervisedUserAcknowledged(supervised_user_id)); 556} 557 558void SupervisedUserSyncService::NotifySupervisedUsersSyncingStopped() { 559 FOR_EACH_OBSERVER(SupervisedUserSyncServiceObserver, observers_, 560 OnSupervisedUsersSyncingStopped()); 561} 562 563void SupervisedUserSyncService::NotifySupervisedUsersChanged() { 564 FOR_EACH_OBSERVER(SupervisedUserSyncServiceObserver, 565 observers_, 566 OnSupervisedUsersChanged()); 567} 568 569void 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