Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/sync/credential_cache_service_win.h" | 5 #include "chrome/browser/sync/credential_cache_service_win.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/base64.h" | 9 #include "base/base64.h" |
| 10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
| 11 #include "base/file_util.h" | 11 #include "base/file_util.h" |
| 12 #include "base/time.h" | |
| 12 #include "base/values.h" | 13 #include "base/values.h" |
| 13 #include "base/win/windows_version.h" | 14 #include "base/win/windows_version.h" |
| 14 #include "chrome/browser/prefs/pref_service.h" | 15 #include "chrome/browser/prefs/pref_service.h" |
| 15 #include "chrome/browser/profiles/profile.h" | 16 #include "chrome/browser/profiles/profile.h" |
| 16 #include "chrome/browser/profiles/profile_manager.h" | 17 #include "chrome/browser/profiles/profile_manager.h" |
| 17 #include "chrome/browser/signin/signin_manager.h" | 18 #include "chrome/browser/signin/signin_manager.h" |
| 18 #include "chrome/browser/signin/token_service.h" | 19 #include "chrome/browser/signin/token_service.h" |
| 19 #include "chrome/browser/signin/token_service_factory.h" | 20 #include "chrome/browser/signin/token_service_factory.h" |
| 20 #include "chrome/browser/sync/glue/chrome_encryptor.h" | 21 #include "chrome/browser/sync/glue/chrome_encryptor.h" |
| 21 #include "chrome/browser/sync/profile_sync_service.h" | 22 #include "chrome/browser/sync/profile_sync_service.h" |
| 22 #include "chrome/browser/sync/profile_sync_service_factory.h" | 23 #include "chrome/browser/sync/profile_sync_service_factory.h" |
| 23 #include "chrome/common/chrome_constants.h" | 24 #include "chrome/common/chrome_constants.h" |
| 24 #include "chrome/common/chrome_notification_types.h" | 25 #include "chrome/common/chrome_notification_types.h" |
| 25 #include "chrome/common/chrome_paths_internal.h" | 26 #include "chrome/common/chrome_paths_internal.h" |
| 26 #include "chrome/common/net/gaia/gaia_auth_consumer.h" | 27 #include "chrome/common/net/gaia/gaia_auth_consumer.h" |
| 27 #include "chrome/common/net/gaia/gaia_constants.h" | 28 #include "chrome/common/net/gaia/gaia_constants.h" |
| 28 #include "chrome/common/pref_names.h" | 29 #include "chrome/common/pref_names.h" |
| 29 #include "content/public/browser/browser_thread.h" | 30 #include "content/public/browser/browser_thread.h" |
| 30 #include "content/public/browser/notification_details.h" | 31 #include "content/public/browser/notification_details.h" |
| 31 #include "content/public/browser/notification_source.h" | 32 #include "content/public/browser/notification_source.h" |
| 32 #include "sync/internal_api/public/base/model_type.h" | 33 #include "sync/internal_api/public/base/model_type.h" |
| 33 | 34 |
| 34 namespace syncer { | 35 namespace syncer { |
| 35 | 36 |
| 37 // The time delay (in seconds) between two consecutive polls of the alternate | |
| 38 // credential cache. A one minute delay seems like a reasonable amount of time | |
| 39 // in which to propagate changes to signed in state between Metro and Desktop. | |
| 40 const int kCredentialCachePollIntervalSecs = 60; | |
|
Andrew T Wilson (Slow)
2012/08/03 23:33:24
Now I wonder if 60 secs is too frequent for us to
Raghu Simha
2012/08/04 00:18:02
I could increase this to 2 minutes, or even 5 minu
| |
| 41 | |
| 42 // Keeps track of the last time a credential cache was written to. Used to make | |
| 43 // sure that we only apply changes from newer credential caches to older ones, | |
| 44 // and not vice versa. | |
| 45 const char kLastUpdatedTime[] = "last_updated_time"; | |
| 46 | |
| 47 using base::TimeDelta; | |
| 36 using content::BrowserThread; | 48 using content::BrowserThread; |
| 37 | 49 |
| 38 CredentialCacheService::CredentialCacheService(Profile* profile) | 50 CredentialCacheService::CredentialCacheService(Profile* profile) |
| 39 : profile_(profile), | 51 : profile_(profile), |
| 40 // |profile_| is null in unit tests. | 52 // |profile_| is null in unit tests. |
| 41 sync_prefs_(profile_ ? profile_->GetPrefs() : NULL), | 53 sync_prefs_(profile_ ? profile_->GetPrefs() : NULL), |
| 42 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | 54 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
| 43 if (profile_) { | 55 if (profile_) { |
| 44 InitializeLocalCredentialCacheWriter(); | 56 InitializeLocalCredentialCacheWriter(); |
| 45 if (ShouldLookForCachedCredentialsInAlternateProfile()) | 57 if (ShouldLookForCachedCredentialsInAlternateProfile()) |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 57 } | 69 } |
| 58 | 70 |
| 59 if (alternate_store_.get()) { | 71 if (alternate_store_.get()) { |
| 60 alternate_store_->RemoveObserver(this); | 72 alternate_store_->RemoveObserver(this); |
| 61 alternate_store_.release(); | 73 alternate_store_.release(); |
| 62 } | 74 } |
| 63 } | 75 } |
| 64 | 76 |
| 65 void CredentialCacheService::OnInitializationCompleted(bool succeeded) { | 77 void CredentialCacheService::OnInitializationCompleted(bool succeeded) { |
| 66 DCHECK(succeeded); | 78 DCHECK(succeeded); |
| 67 // When the alternate credential store becomes available, begin consuming its | 79 // When the local and alternate credential stores become available, begin |
| 68 // cached credentials. | 80 // consuming the alternate cached credentials. We must also wait for the local |
| 69 if (alternate_store_.get() && alternate_store_->IsInitializationComplete()) { | 81 // credential store because the credentials read from the alternate cache and |
| 82 // applied locally must eventually get stored in the local cache. | |
| 83 if (alternate_store_.get() && | |
| 84 alternate_store_->IsInitializationComplete() && | |
| 85 local_store_.get() && | |
| 86 local_store_->IsInitializationComplete()) { | |
| 70 ReadCachedCredentialsFromAlternateProfile(); | 87 ReadCachedCredentialsFromAlternateProfile(); |
| 71 } | 88 } |
| 72 } | 89 } |
| 73 | 90 |
| 74 void CredentialCacheService::OnPrefValueChanged(const std::string& key) { | 91 void CredentialCacheService::OnPrefValueChanged(const std::string& key) { |
| 75 // Nothing to do here, since credentials are cached silently. | 92 // Nothing to do here, since credentials are cached silently. |
| 76 } | 93 } |
| 77 | 94 |
| 78 void CredentialCacheService::Observe( | 95 void CredentialCacheService::Observe( |
| 79 int type, | 96 int type, |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 169 browser_sync::ChromeEncryptor encryptor; | 186 browser_sync::ChromeEncryptor encryptor; |
| 170 std::string unencrypted; | 187 std::string unencrypted; |
| 171 if (!encryptor.DecryptString(encrypted, &unencrypted)) { | 188 if (!encryptor.DecryptString(encrypted, &unencrypted)) { |
| 172 NOTREACHED(); | 189 NOTREACHED(); |
| 173 return std::string(); | 190 return std::string(); |
| 174 } | 191 } |
| 175 | 192 |
| 176 return unencrypted; | 193 return unencrypted; |
| 177 } | 194 } |
| 178 | 195 |
| 196 void CredentialCacheService::WriteLastUpdatedTime() { | |
| 197 DCHECK(local_store_.get()); | |
| 198 int last_updated_time = base::TimeTicks::Now().ToInternalValue(); | |
| 199 local_store_->SetValueSilently( | |
| 200 kLastUpdatedTime, | |
| 201 base::Value::CreateIntegerValue(last_updated_time)); | |
| 202 } | |
| 203 | |
| 179 void CredentialCacheService::PackAndUpdateStringPref( | 204 void CredentialCacheService::PackAndUpdateStringPref( |
| 180 const std::string& pref_name, | 205 const std::string& pref_name, |
| 181 const std::string& new_value) { | 206 const std::string& new_value) { |
| 182 DCHECK(local_store_.get()); | 207 DCHECK(local_store_.get()); |
| 183 if (!HasUserSignedOut()) { | 208 if (!HasUserSignedOut()) { |
| 184 local_store_->SetValueSilently(pref_name, PackCredential(new_value)); | 209 local_store_->SetValueSilently(pref_name, PackCredential(new_value)); |
| 185 } else { | 210 } else { |
| 186 // Write a blank value since we cache credentials only for first-time | 211 // Write a blank value since we cache credentials only for first-time |
| 187 // sign-ins. | 212 // sign-ins. |
| 188 local_store_->SetValueSilently(pref_name, PackCredential(std::string())); | 213 local_store_->SetValueSilently(pref_name, PackCredential(std::string())); |
| 189 } | 214 } |
| 215 WriteLastUpdatedTime(); | |
| 190 } | 216 } |
| 191 | 217 |
| 192 void CredentialCacheService::UpdateBooleanPref(const std::string& pref_name, | 218 void CredentialCacheService::UpdateBooleanPref(const std::string& pref_name, |
| 193 bool new_value) { | 219 bool new_value) { |
| 194 DCHECK(local_store_.get()); | 220 DCHECK(local_store_.get()); |
| 195 if (!HasUserSignedOut()) { | 221 if (!HasUserSignedOut()) { |
| 196 local_store_->SetValueSilently(pref_name, | 222 local_store_->SetValueSilently(pref_name, |
| 197 base::Value::CreateBooleanValue(new_value)); | 223 base::Value::CreateBooleanValue(new_value)); |
|
Andrew T Wilson (Slow)
2012/08/03 23:33:24
Incorrect indentation.
Raghu Simha
2012/08/04 00:18:02
Done.
| |
| 198 } else { | 224 } else { |
| 199 // Write a default value of false since we cache credentials only for | 225 // Write a default value of false since we cache credentials only for |
| 200 // first-time sign-ins. | 226 // first-time sign-ins. |
| 201 local_store_->SetValueSilently(pref_name, | 227 local_store_->SetValueSilently(pref_name, |
| 202 base::Value::CreateBooleanValue(false)); | 228 base::Value::CreateBooleanValue(false)); |
| 203 } | 229 } |
| 230 WriteLastUpdatedTime(); | |
| 231 } | |
| 232 | |
| 233 int CredentialCacheService::GetLastUpdatedTime( | |
| 234 scoped_refptr<JsonPrefStore> store) { | |
| 235 const base::Value* last_updated_time_value = NULL; | |
| 236 store->GetValue(kLastUpdatedTime, &last_updated_time_value); | |
| 237 int last_updated_time; | |
| 238 last_updated_time_value->GetAsInteger(&last_updated_time); | |
|
Andrew T Wilson (Slow)
2012/08/03 23:33:24
Should we add a CHECK here for the return value? O
Raghu Simha
2012/08/04 00:18:02
I've now made this a string pref that's converted
| |
| 239 return last_updated_time; | |
| 204 } | 240 } |
| 205 | 241 |
| 206 std::string CredentialCacheService::GetAndUnpackStringPref( | 242 std::string CredentialCacheService::GetAndUnpackStringPref( |
| 207 scoped_refptr<JsonPrefStore> store, | 243 scoped_refptr<JsonPrefStore> store, |
| 208 const std::string& pref_name) { | 244 const std::string& pref_name) { |
| 209 const base::Value* pref_value = NULL; | 245 const base::Value* pref_value = NULL; |
| 210 store->GetValue(pref_name, &pref_value); | 246 store->GetValue(pref_name, &pref_value); |
| 211 return UnpackCredential(*pref_value); | 247 return UnpackCredential(*pref_value); |
| 212 } | 248 } |
| 213 | 249 |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 238 ProfileManager::GetDefaultProfileDir(alternate_user_data_dir); | 274 ProfileManager::GetDefaultProfileDir(alternate_user_data_dir); |
| 239 return alternate_default_profile_dir.Append(chrome::kSyncCredentialsFilename); | 275 return alternate_default_profile_dir.Append(chrome::kSyncCredentialsFilename); |
| 240 } | 276 } |
| 241 | 277 |
| 242 bool CredentialCacheService::ShouldLookForCachedCredentialsInAlternateProfile() | 278 bool CredentialCacheService::ShouldLookForCachedCredentialsInAlternateProfile() |
| 243 const { | 279 const { |
| 244 // We must look for credentials in the alternate profile iff the following are | 280 // We must look for credentials in the alternate profile iff the following are |
| 245 // true: | 281 // true: |
| 246 // 1) Sync is not disabled by policy. | 282 // 1) Sync is not disabled by policy. |
| 247 // 2) Sync startup is not suppressed. | 283 // 2) Sync startup is not suppressed. |
| 248 // 3) No user is currently signed in to sync. | 284 // Note that we do want to look for credentials in the alternate profile even |
| 249 DCHECK(profile_); | 285 // if the local user is signed in, so we can detect a sign out originating |
| 250 PrefService* prefs = profile_->GetPrefs(); | 286 // from the alternate profile. |
| 251 DCHECK(prefs); | 287 return !sync_prefs_.IsManaged() && !sync_prefs_.IsStartSuppressed(); |
| 252 return !sync_prefs_.IsManaged() && | |
| 253 !sync_prefs_.IsStartSuppressed() && | |
| 254 prefs->GetString(prefs::kGoogleServicesUsername).empty(); | |
| 255 } | 288 } |
| 256 | 289 |
| 257 void CredentialCacheService::InitializeLocalCredentialCacheWriter() { | 290 void CredentialCacheService::InitializeLocalCredentialCacheWriter() { |
| 258 local_store_ = new JsonPrefStore( | 291 local_store_ = new JsonPrefStore( |
| 259 GetCredentialPathInCurrentProfile(), | 292 GetCredentialPathInCurrentProfile(), |
| 260 content::BrowserThread::GetMessageLoopProxyForThread( | 293 content::BrowserThread::GetMessageLoopProxyForThread( |
| 261 content::BrowserThread::FILE)); | 294 content::BrowserThread::FILE)); |
| 295 local_store_->AddObserver(this); | |
| 262 local_store_->ReadPrefsAsync(NULL); | 296 local_store_->ReadPrefsAsync(NULL); |
| 263 | 297 |
| 264 // Register for notifications for updates to the sync credentials, which are | 298 // Register for notifications for updates to the sync credentials, which are |
| 265 // stored in the PrefStore. | 299 // stored in the PrefStore. |
| 266 pref_registrar_.Init(profile_->GetPrefs()); | 300 pref_registrar_.Init(profile_->GetPrefs()); |
| 267 pref_registrar_.Add(prefs::kSyncEncryptionBootstrapToken, this); | 301 pref_registrar_.Add(prefs::kSyncEncryptionBootstrapToken, this); |
| 268 pref_registrar_.Add(prefs::kGoogleServicesUsername, this); | 302 pref_registrar_.Add(prefs::kGoogleServicesUsername, this); |
| 269 pref_registrar_.Add(prefs::kSyncKeepEverythingSynced, this); | 303 pref_registrar_.Add(prefs::kSyncKeepEverythingSynced, this); |
| 270 for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) { | 304 ModelTypeSet all_types = syncer::ModelTypeSet::All(); |
| 271 if (i == NIGORI) // The NIGORI preference is not persisted. | 305 for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) { |
| 306 if (it.Get() == NIGORI) // The NIGORI preference is not persisted. | |
| 272 continue; | 307 continue; |
| 273 pref_registrar_.Add( | 308 pref_registrar_.Add( |
| 274 browser_sync::SyncPrefs::GetPrefNameForDataType(ModelTypeFromInt(i)), | 309 browser_sync::SyncPrefs::GetPrefNameForDataType(it.Get()), |
| 275 this); | 310 this); |
| 276 } | 311 } |
| 277 | 312 |
| 278 // Register for notifications for updates to lsid and sid, which are stored in | 313 // Register for notifications for updates to lsid and sid, which are stored in |
| 279 // the TokenService. | 314 // the TokenService. |
| 280 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | 315 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
| 281 registrar_.Add(this, | 316 registrar_.Add(this, |
| 282 chrome::NOTIFICATION_TOKEN_SERVICE_CREDENTIALS_UPDATED, | 317 chrome::NOTIFICATION_TOKEN_SERVICE_CREDENTIALS_UPDATED, |
| 283 content::Source<TokenService>(token_service)); | 318 content::Source<TokenService>(token_service)); |
| 284 registrar_.Add(this, | 319 registrar_.Add(this, |
| 285 chrome::NOTIFICATION_TOKENS_CLEARED, | 320 chrome::NOTIFICATION_TOKENS_CLEARED, |
| 286 content::Source<TokenService>(token_service)); | 321 content::Source<TokenService>(token_service)); |
| 287 } | 322 } |
| 288 | 323 |
| 289 void CredentialCacheService::InitializeAlternateCredentialCacheReader( | 324 void CredentialCacheService::InitializeAlternateCredentialCacheReader( |
| 290 bool* should_initialize) { | 325 bool* should_initialize) { |
| 291 // If |should_initialize| is false, there was no credential cache in the | 326 // If |should_initialize| is false, there was no credential cache in the |
| 292 // alternate profile directory, and there is nothing to do. | 327 // alternate profile directory, and there is nothing to do right now. Schedule |
| 293 // TODO(rsimha): Add a polling mechanism that periodically examines the | 328 // another read in the future and exit. |
| 294 // credential file in the alternate profile directory so we can respond to the | |
| 295 // user signing in and signing out. | |
| 296 DCHECK(should_initialize); | 329 DCHECK(should_initialize); |
| 297 if (!*should_initialize) | 330 if (!*should_initialize) { |
| 331 ScheduleNextReadFromAlternateCredentialCache(); | |
| 298 return; | 332 return; |
| 333 } | |
| 334 | |
| 335 // A credential cache file was found in the alternate profile. Prepare to | |
| 336 // consume its contents. | |
| 299 alternate_store_ = new JsonPrefStore( | 337 alternate_store_ = new JsonPrefStore( |
| 300 GetCredentialPathInAlternateProfile(), | 338 GetCredentialPathInAlternateProfile(), |
| 301 content::BrowserThread::GetMessageLoopProxyForThread( | 339 content::BrowserThread::GetMessageLoopProxyForThread( |
| 302 content::BrowserThread::FILE)); | 340 content::BrowserThread::FILE)); |
| 303 alternate_store_->AddObserver(this); | 341 alternate_store_->AddObserver(this); |
| 304 alternate_store_->ReadPrefsAsync(NULL); | 342 alternate_store_->ReadPrefsAsync(NULL); |
| 305 } | 343 } |
| 306 | 344 |
| 307 bool CredentialCacheService::HasUserSignedOut() { | 345 bool CredentialCacheService::HasUserSignedOut() { |
| 308 DCHECK(local_store_.get()); | 346 DCHECK(local_store_.get()); |
| 309 // If HasPref() is false, the user never signed in, since there are no | 347 // If HasPref() is false, the user never signed in, since there are no |
| 310 // previously cached credentials. If the kGoogleServicesUsername pref is | 348 // previously cached credentials. If the kGoogleServicesUsername pref is |
| 311 // empty, it means that the user signed in and subsequently signed out. | 349 // empty, it means that the user signed in and subsequently signed out. |
| 312 return HasPref(local_store_, prefs::kGoogleServicesUsername) && | 350 return HasPref(local_store_, prefs::kGoogleServicesUsername) && |
| 313 GetAndUnpackStringPref(local_store_, | 351 GetAndUnpackStringPref(local_store_, |
| 314 prefs::kGoogleServicesUsername).empty(); | 352 prefs::kGoogleServicesUsername).empty(); |
| 315 } | 353 } |
| 316 | 354 |
| 317 namespace { | 355 namespace { |
| 318 | 356 |
| 319 // Determines if credentials should be read from the alternate profile based | 357 // Determines if there is a sync credential cache in the alternate profile. |
| 320 // on the existence of the local and alternate credential files. Returns | 358 // Returns true via |result| if there is a credential cache file in the |
| 321 // true via |result| if there is a credential cache file in the alternate | 359 // alternate profile. Returns false otherwise. |
| 322 // profile, but there isn't one in the local profile. Returns false otherwise. | 360 void AlternateCredentialCacheExists( |
| 323 void ShouldReadFromAlternateCache( | |
| 324 const FilePath& credential_path_in_current_profile, | |
| 325 const FilePath& credential_path_in_alternate_profile, | 361 const FilePath& credential_path_in_alternate_profile, |
| 326 bool* result) { | 362 bool* result) { |
| 327 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | 363 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
| 328 DCHECK(result); | 364 DCHECK(result); |
| 329 *result = !file_util::PathExists(credential_path_in_current_profile) && | 365 *result = file_util::PathExists(credential_path_in_alternate_profile); |
| 330 file_util::PathExists(credential_path_in_alternate_profile); | |
| 331 } | 366 } |
| 332 | 367 |
| 333 } // namespace | 368 } // namespace |
| 334 | 369 |
| 335 void CredentialCacheService::LookForCachedCredentialsInAlternateProfile() { | 370 void CredentialCacheService::LookForCachedCredentialsInAlternateProfile() { |
| 336 bool* should_initialize = new bool(false); | 371 bool* should_initialize = new bool(false); |
| 337 content::BrowserThread::PostTaskAndReply( | 372 content::BrowserThread::PostTaskAndReply( |
| 338 content::BrowserThread::FILE, | 373 content::BrowserThread::FILE, |
| 339 FROM_HERE, | 374 FROM_HERE, |
| 340 base::Bind(&ShouldReadFromAlternateCache, | 375 base::Bind(&AlternateCredentialCacheExists, |
| 341 GetCredentialPathInCurrentProfile(), | |
| 342 GetCredentialPathInAlternateProfile(), | 376 GetCredentialPathInAlternateProfile(), |
| 343 should_initialize), | 377 should_initialize), |
| 344 base::Bind( | 378 base::Bind( |
| 345 &CredentialCacheService::InitializeAlternateCredentialCacheReader, | 379 &CredentialCacheService::InitializeAlternateCredentialCacheReader, |
| 346 weak_factory_.GetWeakPtr(), | 380 weak_factory_.GetWeakPtr(), |
| 347 base::Owned(should_initialize))); | 381 base::Owned(should_initialize))); |
| 348 } | 382 } |
| 349 | 383 |
| 350 void CredentialCacheService::ReadCachedCredentialsFromAlternateProfile() { | 384 void CredentialCacheService::ReadCachedCredentialsFromAlternateProfile() { |
| 385 // If the local user has signed in and signed out, we do not consume cached | |
| 386 // credentials from the alternate profile. There is nothing more to do, now or | |
| 387 // later on. | |
| 388 if (HasUserSignedOut()) | |
|
Andrew T Wilson (Slow)
2012/08/03 23:33:24
So, if the user logs out in one profile, that shou
Raghu Simha
2012/08/04 00:18:02
As of now, the answer is no, as discussed in the d
| |
| 389 return; | |
| 390 | |
| 391 // Sanity check the alternate credential cache. If any string credentials | |
| 392 // are outright missing even though the file exists, something is awry with | |
| 393 // the alternate profile store. There is no sense in flagging an error as the | |
| 394 // problem lies in a different profile directory. There is nothing to do now. | |
| 395 // We schedule a future read from the alternate credential cache and return. | |
| 351 DCHECK(alternate_store_.get()); | 396 DCHECK(alternate_store_.get()); |
| 352 if (!HasPref(alternate_store_, prefs::kGoogleServicesUsername) || | 397 if (!HasPref(alternate_store_, prefs::kGoogleServicesUsername) || |
| 353 !HasPref(alternate_store_, GaiaConstants::kGaiaLsid) || | 398 !HasPref(alternate_store_, GaiaConstants::kGaiaLsid) || |
| 354 !HasPref(alternate_store_, GaiaConstants::kGaiaSid) || | 399 !HasPref(alternate_store_, GaiaConstants::kGaiaSid) || |
| 355 !HasPref(alternate_store_, prefs::kSyncEncryptionBootstrapToken) || | 400 !HasPref(alternate_store_, prefs::kSyncEncryptionBootstrapToken) || |
| 356 !HasPref(alternate_store_, prefs::kSyncKeepEverythingSynced)) { | 401 !HasPref(alternate_store_, prefs::kSyncKeepEverythingSynced)) { |
| 357 VLOG(1) << "Could not find cached credentials."; | 402 VLOG(1) << "Could not find cached credentials in \"" |
| 403 << GetCredentialPathInAlternateProfile().value() << "\"."; | |
| 404 ScheduleNextReadFromAlternateCredentialCache(); | |
| 358 return; | 405 return; |
| 359 } | 406 } |
| 360 | 407 |
| 408 // Extract cached credentials from the alternate credential cache. | |
| 361 std::string google_services_username = | 409 std::string google_services_username = |
| 362 GetAndUnpackStringPref(alternate_store_, prefs::kGoogleServicesUsername); | 410 GetAndUnpackStringPref(alternate_store_, prefs::kGoogleServicesUsername); |
| 363 std::string lsid = | 411 std::string lsid = |
| 364 GetAndUnpackStringPref(alternate_store_, GaiaConstants::kGaiaLsid); | 412 GetAndUnpackStringPref(alternate_store_, GaiaConstants::kGaiaLsid); |
| 365 std::string sid = | 413 std::string sid = |
| 366 GetAndUnpackStringPref(alternate_store_, GaiaConstants::kGaiaSid); | 414 GetAndUnpackStringPref(alternate_store_, GaiaConstants::kGaiaSid); |
| 367 std::string encryption_bootstrap_token = | 415 std::string encryption_bootstrap_token = |
| 368 GetAndUnpackStringPref(alternate_store_, | 416 GetAndUnpackStringPref(alternate_store_, |
| 369 prefs::kSyncEncryptionBootstrapToken); | 417 prefs::kSyncEncryptionBootstrapToken); |
| 370 bool keep_everything_synced = | |
| 371 GetBooleanPref(alternate_store_, prefs::kSyncKeepEverythingSynced); | |
| 372 | 418 |
| 373 if (google_services_username.empty() || | 419 // Sign out of sync if the alternate profile has signed out the same user. |
| 374 lsid.empty() || | 420 // There is no need to schedule any more reads of the alternate profile |
| 375 sid.empty() || | 421 // cache because we only apply cached credentials for first-time sign-ins. |
| 376 encryption_bootstrap_token.empty()) { | 422 if (ShouldSignOutOfSync(google_services_username)) { |
| 377 VLOG(1) << "Found empty cached credentials."; | 423 VLOG(1) << "User has signed out on the other profile. Signing out."; |
| 424 InitiateSignOut(); | |
| 378 return; | 425 return; |
| 379 } | 426 } |
| 380 | 427 |
| 381 bool datatype_prefs[MODEL_TYPE_COUNT] = { false }; | 428 // Extract cached sync prefs from the alternate credential cache. |
| 382 for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) { | 429 bool keep_everything_synced = |
| 383 if (i == NIGORI) // The NIGORI preference is not persisted. | 430 GetBooleanPref(alternate_store_, prefs::kSyncKeepEverythingSynced); |
| 431 ProfileSyncService* service = | |
| 432 ProfileSyncServiceFactory::GetForProfile(profile_); | |
| 433 ModelTypeSet registered_types = service->GetRegisteredDataTypes(); | |
| 434 ModelTypeSet preferred_types; | |
| 435 for (ModelTypeSet::Iterator it = registered_types.First(); | |
| 436 it.Good(); | |
| 437 it.Inc()) { | |
| 438 std::string datatype_pref_name = | |
| 439 browser_sync::SyncPrefs::GetPrefNameForDataType(it.Get()); | |
| 440 if (!HasPref(alternate_store_, datatype_pref_name)) { | |
| 441 // If there is no cached pref for a specific data type, it means that the | |
| 442 // user originally signed in with an older version of Chrome, and then | |
| 443 // upgraded to a version with a new datatype. In such cases, we leave the | |
| 444 // default initial datatype setting as false while reading cached | |
| 445 // credentials, just like we do in SyncPrefs::RegisterPreferences. | |
| 446 VLOG(1) << "Could not find cached datatype pref for " | |
| 447 << datatype_pref_name << " in " | |
| 448 << GetCredentialPathInAlternateProfile().value() << "."; | |
| 384 continue; | 449 continue; |
| 385 std::string datatype_pref_name = | |
| 386 browser_sync::SyncPrefs::GetPrefNameForDataType(ModelTypeFromInt(i)); | |
| 387 if (!HasPref(alternate_store_, datatype_pref_name)) { | |
| 388 VLOG(1) << "Could not find cached datatype prefs."; | |
| 389 return; | |
| 390 } | 450 } |
| 391 datatype_prefs[i] = GetBooleanPref(alternate_store_, datatype_pref_name); | 451 if (GetBooleanPref(alternate_store_, datatype_pref_name)) |
| 452 preferred_types.Put(it.Get()); | |
| 392 } | 453 } |
| 393 | 454 |
| 394 ApplyCachedCredentials(google_services_username, | 455 // Reconfigure if sync settings or credentials have changed in the alternate |
| 456 // profile, but for the same user that is signed in to the local profile. | |
| 457 // Follow this up by scheduling a future read from the alternate profile, so | |
| 458 // we can detect future reconfigures or sign outs. | |
| 459 if (MayReconfigureSync(google_services_username)) { | |
| 460 if (HaveSyncPrefsChanged(keep_everything_synced, preferred_types)) { | |
| 461 VLOG(1) << "Sync prefs have changed in other profile. Reconfiguring."; | |
| 462 service->OnUserChoseDatatypes(keep_everything_synced, preferred_types); | |
| 463 } | |
| 464 if (HaveTokenServiceCredentialsChanged(lsid, sid)) { | |
| 465 VLOG(1) << "Token service credentials have changed in other profile."; | |
| 466 UpdateTokenServiceCredentials(lsid, sid); | |
| 467 } | |
| 468 ScheduleNextReadFromAlternateCredentialCache(); | |
| 469 return; | |
| 470 } | |
| 471 | |
| 472 // Sign in if we notice new cached credentials in the alternate profile. | |
| 473 // Follow this up by scheduling a future read from the alternate profile, so | |
| 474 // we can detect future reconfigures or sign outs. | |
| 475 if (ShouldSignInToSync(google_services_username, | |
| 395 lsid, | 476 lsid, |
| 396 sid, | 477 sid, |
| 397 encryption_bootstrap_token, | 478 encryption_bootstrap_token)) { |
| 398 keep_everything_synced, | 479 InitiateSignInWithCachedCredentials(google_services_username, |
| 399 datatype_prefs); | 480 encryption_bootstrap_token, |
| 481 keep_everything_synced, | |
| 482 preferred_types); | |
| 483 UpdateTokenServiceCredentials(lsid, sid); | |
| 484 ScheduleNextReadFromAlternateCredentialCache(); | |
| 485 return; | |
| 486 } | |
| 400 } | 487 } |
| 401 | 488 |
| 402 void CredentialCacheService::ApplyCachedCredentials( | 489 void CredentialCacheService::InitiateSignInWithCachedCredentials( |
| 403 const std::string& google_services_username, | 490 const std::string& google_services_username, |
| 404 const std::string& lsid, | |
| 405 const std::string& sid, | |
| 406 const std::string& encryption_bootstrap_token, | 491 const std::string& encryption_bootstrap_token, |
| 407 bool keep_everything_synced, | 492 bool keep_everything_synced, |
| 408 const bool datatype_prefs[]) { | 493 ModelTypeSet preferred_types) { |
| 409 // Update the google username in the SigninManager and PrefStore. | 494 // Update the google username in the SigninManager and PrefStore. |
| 410 ProfileSyncService* service = | 495 ProfileSyncService* service = |
| 411 ProfileSyncServiceFactory::GetForProfile(profile_); | 496 ProfileSyncServiceFactory::GetForProfile(profile_); |
| 412 service->signin()->SetAuthenticatedUsername(google_services_username); | 497 service->signin()->SetAuthenticatedUsername(google_services_username); |
| 413 profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, | 498 profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, |
| 414 google_services_username); | 499 google_services_username); |
| 415 | 500 |
| 416 // Update the sync preferences. | 501 // Update the sync preferences. |
| 417 sync_prefs_.SetStartSuppressed(false); | 502 sync_prefs_.SetStartSuppressed(false); |
| 418 sync_prefs_.SetSyncSetupCompleted(); | 503 sync_prefs_.SetSyncSetupCompleted(); |
| 419 sync_prefs_.SetEncryptionBootstrapToken(encryption_bootstrap_token); | 504 sync_prefs_.SetEncryptionBootstrapToken(encryption_bootstrap_token); |
| 420 sync_prefs_.SetKeepEverythingSynced(keep_everything_synced); | 505 sync_prefs_.SetKeepEverythingSynced(keep_everything_synced); |
| 421 syncer::ModelTypeSet registered_types; | 506 sync_prefs_.SetPreferredDataTypes(service->GetRegisteredDataTypes(), |
| 422 syncer::ModelTypeSet preferred_types; | 507 preferred_types); |
| 423 for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) { | 508 } |
| 424 if (i == NIGORI) // The NIGORI preference is not persisted. | |
| 425 continue; | |
| 426 registered_types.Put(ModelTypeFromInt(i)); | |
| 427 if (datatype_prefs[i]) | |
| 428 preferred_types.Put(ModelTypeFromInt(i)); | |
| 429 } | |
| 430 sync_prefs_.SetPreferredDataTypes(registered_types, preferred_types); | |
| 431 | 509 |
| 432 // Update the lsid and sid in the TokenService and mint new tokens for all | 510 void CredentialCacheService::UpdateTokenServiceCredentials( |
| 433 // Chrome services. | 511 const std::string& lsid, |
| 512 const std::string& sid) { | |
| 434 GaiaAuthConsumer::ClientLoginResult login_result; | 513 GaiaAuthConsumer::ClientLoginResult login_result; |
| 435 login_result.lsid = lsid; | 514 login_result.lsid = lsid; |
| 436 login_result.sid = sid; | 515 login_result.sid = sid; |
| 437 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | 516 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
| 438 token_service->UpdateCredentials(login_result); | 517 token_service->UpdateCredentials(login_result); |
| 439 DCHECK(token_service->AreCredentialsValid()); | 518 DCHECK(token_service->AreCredentialsValid()); |
| 440 token_service->StartFetchingTokens(); | 519 token_service->StartFetchingTokens(); |
| 441 } | 520 } |
| 442 | 521 |
| 522 void CredentialCacheService::InitiateSignOut() { | |
| 523 ProfileSyncService* service = | |
| 524 ProfileSyncServiceFactory::GetForProfile(profile_); | |
| 525 service->DisableForUser(); | |
| 526 } | |
| 527 | |
| 528 bool CredentialCacheService::HaveSyncPrefsChanged( | |
| 529 bool keep_everything_synced, | |
| 530 const ModelTypeSet& preferred_types) const { | |
|
Andrew T Wilson (Slow)
2012/08/03 23:33:24
Part of the contract of ModelTypeSet is that you c
Raghu Simha
2012/08/04 00:18:02
Done.
| |
| 531 ProfileSyncService* service = | |
| 532 ProfileSyncServiceFactory::GetForProfile(profile_); | |
| 533 ModelTypeSet local_preferred_types = | |
| 534 sync_prefs_.GetPreferredDataTypes(service->GetRegisteredDataTypes()); | |
| 535 return | |
| 536 (keep_everything_synced != sync_prefs_.HasKeepEverythingSynced()) || | |
| 537 !Difference(preferred_types, local_preferred_types).Empty(); | |
| 538 } | |
| 539 | |
| 540 bool CredentialCacheService::HaveTokenServiceCredentialsChanged( | |
| 541 const std::string& lsid, | |
| 542 const std::string& sid) { | |
| 543 std::string local_lsid = | |
| 544 GetAndUnpackStringPref(local_store_, GaiaConstants::kGaiaLsid); | |
| 545 std::string local_sid = | |
| 546 GetAndUnpackStringPref(local_store_, GaiaConstants::kGaiaSid); | |
| 547 return local_lsid != lsid || local_sid != sid; | |
| 548 } | |
| 549 | |
| 550 bool CredentialCacheService::ShouldSignOutOfSync( | |
| 551 const std::string& google_services_username) { | |
| 552 // We must sign out of sync iff: | |
| 553 // 1) The user is signed in to the local profile. | |
| 554 // 2) The user has never signed out of the local profile in the past. | |
| 555 // 3) We noticed that the user has signed out of the alternate profile. | |
| 556 // 4) The user is not already in the process of configuring sync. | |
| 557 // 5) The alternate cache was updated more recently than the local cache. | |
| 558 ProfileSyncService* service = | |
| 559 ProfileSyncServiceFactory::GetForProfile(profile_); | |
| 560 return !service->signin()->GetAuthenticatedUsername().empty() && | |
| 561 !HasUserSignedOut() && | |
| 562 google_services_username.empty() && | |
| 563 !service->setup_in_progress() && | |
| 564 (GetLastUpdatedTime(alternate_store_) > | |
| 565 GetLastUpdatedTime(local_store_)); | |
| 566 } | |
| 567 | |
| 568 bool CredentialCacheService::MayReconfigureSync( | |
| 569 const std::string& google_services_username) { | |
| 570 // We may attempt to reconfigure sync iff: | |
| 571 // 1) The user is signed in to the local profile. | |
| 572 // 2) The user has never signed out of the local profile in the past. | |
| 573 // 3) The user is signed in to the alternate profile with the same account. | |
| 574 // 4) The user is not already in the process of configuring sync. | |
| 575 // 5) The alternate cache was updated more recently than the local cache. | |
| 576 ProfileSyncService* service = | |
| 577 ProfileSyncServiceFactory::GetForProfile(profile_); | |
| 578 return !service->signin()->GetAuthenticatedUsername().empty() && | |
| 579 !HasUserSignedOut() && | |
| 580 (google_services_username == | |
| 581 service->signin()->GetAuthenticatedUsername()) && | |
| 582 !service->setup_in_progress() && | |
| 583 (GetLastUpdatedTime(alternate_store_) > | |
| 584 GetLastUpdatedTime(local_store_)); | |
| 585 } | |
| 586 | |
| 587 bool CredentialCacheService::ShouldSignInToSync( | |
| 588 const std::string& google_services_username, | |
| 589 const std::string& lsid, | |
| 590 const std::string& sid, | |
| 591 const std::string& encryption_bootstrap_token) { | |
| 592 // We should sign in with cached credentials from the alternate profile iff: | |
| 593 // 1) The user is not currently signed in to the local profile. | |
| 594 // 2) The user has never signed out of the local profile in the past. | |
| 595 // 3) Valid cached credentials are available in the alternate profile. | |
| 596 // 4) The user is not already in the process of configuring sync. | |
| 597 ProfileSyncService* service = | |
| 598 ProfileSyncServiceFactory::GetForProfile(profile_); | |
| 599 return service->signin()->GetAuthenticatedUsername().empty() && | |
| 600 !HasUserSignedOut() && | |
| 601 !google_services_username.empty() && | |
| 602 !lsid.empty() && | |
| 603 !sid.empty() && | |
| 604 !encryption_bootstrap_token.empty() && | |
| 605 !service->setup_in_progress(); | |
| 606 } | |
| 607 | |
| 608 void CredentialCacheService::ScheduleNextReadFromAlternateCredentialCache() { | |
| 609 // We must reinitialize |alternate_store_| here because the underlying | |
| 610 // credential file in the alternate profile might have changed, and we must | |
| 611 // re-read it afresh. | |
| 612 if (alternate_store_.get()) { | |
| 613 alternate_store_->RemoveObserver(this); | |
| 614 alternate_store_.release(); | |
| 615 } | |
| 616 next_read_.Reset(base::Bind( | |
| 617 &CredentialCacheService::LookForCachedCredentialsInAlternateProfile, | |
| 618 weak_factory_.GetWeakPtr())); | |
| 619 MessageLoop::current()->PostDelayedTask( | |
| 620 FROM_HERE, | |
| 621 next_read_.callback(), | |
| 622 TimeDelta::FromSeconds(kCredentialCachePollIntervalSecs)); | |
| 623 } | |
| 624 | |
| 443 } // namespace syncer | 625 } // namespace syncer |
| OLD | NEW |