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. 4 5#include "chrome/browser/managed_mode/managed_user_sync_service.h" 6 7#include "base/bind.h" 8#include "base/values.h" 9#include "chrome/browser/prefs/scoped_user_pref_update.h" 10#include "chrome/browser/profiles/profile.h" 11#include "chrome/common/pref_names.h" 12#include "components/user_prefs/pref_registry_syncable.h" 13#include "sync/api/sync_change.h" 14#include "sync/api/sync_data.h" 15#include "sync/api/sync_error.h" 16#include "sync/api/sync_error_factory.h" 17#include "sync/api/sync_merge_result.h" 18#include "sync/protocol/sync.pb.h" 19 20using base::DictionaryValue; 21using user_prefs::PrefRegistrySyncable; 22using syncer::MANAGED_USERS; 23using syncer::ModelType; 24using syncer::SyncChange; 25using syncer::SyncChangeList; 26using syncer::SyncChangeProcessor; 27using syncer::SyncData; 28using syncer::SyncDataList; 29using syncer::SyncError; 30using syncer::SyncErrorFactory; 31using syncer::SyncMergeResult; 32using sync_pb::ManagedUserSpecifics; 33 34namespace { 35 36const char kAcknowledged[] = "acknowledged"; 37const char kName[] = "name"; 38const char kMasterKey[] = "masterKey"; 39 40SyncData CreateLocalSyncData(const std::string& id, 41 const std::string& name, 42 bool acknowledged, 43 const std::string& master_key) { 44 ::sync_pb::EntitySpecifics specifics; 45 specifics.mutable_managed_user()->set_id(id); 46 specifics.mutable_managed_user()->set_name(name); 47 if (!master_key.empty()) 48 specifics.mutable_managed_user()->set_master_key(master_key); 49 if (acknowledged) 50 specifics.mutable_managed_user()->set_acknowledged(true); 51 return SyncData::CreateLocalData(id, name, specifics); 52} 53 54} // namespace 55 56ManagedUserSyncService::ManagedUserSyncService(PrefService* prefs) 57 : prefs_(prefs) { 58 pref_change_registrar_.Init(prefs_); 59 pref_change_registrar_.Add( 60 prefs::kGoogleServicesLastUsername, 61 base::Bind(&ManagedUserSyncService::OnLastSignedInUsernameChange, 62 base::Unretained(this))); 63} 64 65ManagedUserSyncService::~ManagedUserSyncService() { 66} 67 68// static 69void ManagedUserSyncService::RegisterProfilePrefs( 70 PrefRegistrySyncable* registry) { 71 registry->RegisterDictionaryPref(prefs::kManagedUsers, 72 PrefRegistrySyncable::UNSYNCABLE_PREF); 73} 74 75void ManagedUserSyncService::AddObserver( 76 ManagedUserSyncServiceObserver* observer) { 77 observers_.AddObserver(observer); 78} 79 80void ManagedUserSyncService::RemoveObserver( 81 ManagedUserSyncServiceObserver* observer) { 82 observers_.RemoveObserver(observer); 83} 84 85void ManagedUserSyncService::AddManagedUser(const std::string& id, 86 const std::string& name, 87 const std::string& master_key) { 88 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers); 89 DictionaryValue* dict = update.Get(); 90 DictionaryValue* value = new DictionaryValue; 91 value->SetString(kName, name); 92 value->SetString(kMasterKey, master_key); 93 DCHECK(!dict->HasKey(id)); 94 dict->SetWithoutPathExpansion(id, value); 95 96 if (!sync_processor_) 97 return; 98 99 // If we're already syncing, create a new change and upload it. 100 SyncChangeList change_list; 101 change_list.push_back(SyncChange( 102 FROM_HERE, 103 SyncChange::ACTION_ADD, 104 CreateLocalSyncData(id, name, false, master_key))); 105 SyncError error = 106 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list); 107 DCHECK(!error.IsSet()) << error.ToString(); 108} 109 110void ManagedUserSyncService::DeleteManagedUser(const std::string& id) { 111 if (!sync_processor_) 112 return; 113 114 SyncChangeList change_list; 115 change_list.push_back(SyncChange( 116 FROM_HERE, 117 SyncChange::ACTION_DELETE, 118 SyncData::CreateLocalDelete(id, MANAGED_USERS))); 119 SyncError sync_error = 120 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list); 121 DCHECK(!sync_error.IsSet()); 122} 123 124void ManagedUserSyncService::Shutdown() { 125 NotifyManagedUsersSyncingStopped(); 126} 127 128SyncMergeResult ManagedUserSyncService::MergeDataAndStartSyncing( 129 ModelType type, 130 const SyncDataList& initial_sync_data, 131 scoped_ptr<SyncChangeProcessor> sync_processor, 132 scoped_ptr<SyncErrorFactory> error_handler) { 133 DCHECK_EQ(MANAGED_USERS, type); 134 sync_processor_ = sync_processor.Pass(); 135 error_handler_ = error_handler.Pass(); 136 137 SyncChangeList change_list; 138 SyncMergeResult result(MANAGED_USERS); 139 140 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers); 141 DictionaryValue* dict = update.Get(); 142 result.set_num_items_before_association(dict->size()); 143 std::set<std::string> seen_ids; 144 int num_items_added = 0; 145 int num_items_modified = 0; 146 for (SyncDataList::const_iterator it = initial_sync_data.begin(); 147 it != initial_sync_data.end(); ++it) { 148 DCHECK_EQ(MANAGED_USERS, it->GetDataType()); 149 const ManagedUserSpecifics& managed_user = 150 it->GetSpecifics().managed_user(); 151 DictionaryValue* value = new DictionaryValue(); 152 value->SetString(kName, managed_user.name()); 153 DCHECK(managed_user.acknowledged()); 154 value->SetBoolean(kAcknowledged, managed_user.acknowledged()); 155 value->SetString(kMasterKey, managed_user.master_key()); 156 if (dict->HasKey(managed_user.id())) 157 num_items_modified++; 158 else 159 num_items_added++; 160 dict->SetWithoutPathExpansion(managed_user.id(), value); 161 seen_ids.insert(managed_user.id()); 162 } 163 164 for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) { 165 if (seen_ids.find(it.key()) != seen_ids.end()) 166 continue; 167 168 const DictionaryValue* dict = NULL; 169 bool success = it.value().GetAsDictionary(&dict); 170 DCHECK(success); 171 bool acknowledged = false; 172 dict->GetBoolean(kAcknowledged, &acknowledged); 173 std::string name; 174 dict->GetString(kName, &name); 175 std::string master_key; 176 dict->GetString(kMasterKey, &master_key); 177 DCHECK(!name.empty()); 178 change_list.push_back( 179 SyncChange(FROM_HERE, SyncChange::ACTION_ADD, 180 CreateLocalSyncData(it.key(), name, acknowledged, master_key))); 181 } 182 result.set_error(sync_processor_->ProcessSyncChanges(FROM_HERE, change_list)); 183 184 result.set_num_items_modified(num_items_modified); 185 result.set_num_items_added(num_items_added); 186 result.set_num_items_after_association(dict->size()); 187 188 return result; 189} 190 191void ManagedUserSyncService::StopSyncing(ModelType type) { 192 DCHECK_EQ(MANAGED_USERS, type); 193 // The observers may want to change the Sync data, so notify them before 194 // resetting the |sync_processor_|. 195 NotifyManagedUsersSyncingStopped(); 196 sync_processor_.reset(); 197 error_handler_.reset(); 198} 199 200SyncDataList ManagedUserSyncService::GetAllSyncData( 201 ModelType type) const { 202 SyncDataList data; 203 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers); 204 DictionaryValue* dict = update.Get(); 205 for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) { 206 const DictionaryValue* dict = NULL; 207 bool success = it.value().GetAsDictionary(&dict); 208 DCHECK(success); 209 std::string name; 210 dict->GetString(kName, &name); 211 std::string master_key; 212 dict->GetString(kMasterKey, &master_key); 213 bool acknowledged = false; 214 dict->GetBoolean(kAcknowledged, &acknowledged); 215 data.push_back( 216 CreateLocalSyncData(it.key(), name, acknowledged, master_key)); 217 } 218 return data; 219} 220 221SyncError ManagedUserSyncService::ProcessSyncChanges( 222 const tracked_objects::Location& from_here, 223 const SyncChangeList& change_list) { 224 SyncError error; 225 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers); 226 DictionaryValue* dict = update.Get(); 227 for (SyncChangeList::const_iterator it = change_list.begin(); 228 it != change_list.end(); ++it) { 229 SyncData data = it->sync_data(); 230 DCHECK_EQ(MANAGED_USERS, data.GetDataType()); 231 const ManagedUserSpecifics& managed_user = 232 data.GetSpecifics().managed_user(); 233 switch (it->change_type()) { 234 case SyncChange::ACTION_ADD: 235 case SyncChange::ACTION_UPDATE: { 236 // Every item we get from the server should be acknowledged. 237 DCHECK(managed_user.acknowledged()); 238 const DictionaryValue* old_value = NULL; 239 dict->GetDictionaryWithoutPathExpansion(managed_user.id(), &old_value); 240 241 // For an update action, the managed user should already exist, for an 242 // add action, it should not. 243 DCHECK_EQ( 244 old_value ? SyncChange::ACTION_UPDATE : SyncChange::ACTION_ADD, 245 it->change_type()); 246 247 // If the managed user switched from unacknowledged to acknowledged, 248 // we might need to continue with a registration. 249 if (old_value && !old_value->HasKey(kAcknowledged)) 250 NotifyManagedUserAcknowledged(managed_user.id()); 251 252 DictionaryValue* value = new DictionaryValue; 253 value->SetString(kName, managed_user.name()); 254 value->SetBoolean(kAcknowledged, managed_user.acknowledged()); 255 value->SetString(kMasterKey, managed_user.master_key()); 256 dict->SetWithoutPathExpansion(managed_user.id(), value); 257 break; 258 } 259 case SyncChange::ACTION_DELETE: { 260 DCHECK(dict->HasKey(managed_user.id())) << managed_user.id(); 261 dict->RemoveWithoutPathExpansion(managed_user.id(), NULL); 262 break; 263 } 264 case SyncChange::ACTION_INVALID: { 265 NOTREACHED(); 266 break; 267 } 268 } 269 } 270 return error; 271} 272 273void ManagedUserSyncService::OnLastSignedInUsernameChange() { 274 DCHECK(!sync_processor_); 275 276 // If the last signed in user changes, we clear all data, to avoid managed 277 // users from one custodian appearing in another one's profile. 278 prefs_->ClearPref(prefs::kManagedUsers); 279} 280 281void ManagedUserSyncService::NotifyManagedUserAcknowledged( 282 const std::string& managed_user_id) { 283 FOR_EACH_OBSERVER(ManagedUserSyncServiceObserver, observers_, 284 OnManagedUserAcknowledged(managed_user_id)); 285} 286 287void ManagedUserSyncService::NotifyManagedUsersSyncingStopped() { 288 FOR_EACH_OBSERVER(ManagedUserSyncServiceObserver, observers_, 289 OnManagedUsersSyncingStopped()); 290} 291