Revert 168224 - Update V8 to version 3.15.4.
[chromium-blink-merge.git] / chrome / browser / sync / credential_cache_service_win.cc
blob7b1c621dfa650956fde1a5a682c2df47ce5eb85c
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
3 // found in the LICENSE file.
5 #include "chrome/browser/sync/credential_cache_service_win.h"
7 #include "base/base64.h"
8 #include "base/bind.h"
9 #include "base/bind_helpers.h"
10 #include "base/command_line.h"
11 #include "base/compiler_specific.h"
12 #include "base/file_util.h"
13 #include "base/string_number_conversions.h"
14 #include "base/time.h"
15 #include "base/values.h"
16 #include "base/win/windows_version.h"
17 #include "chrome/browser/prefs/pref_service.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/profiles/profile_manager.h"
20 #include "chrome/browser/signin/signin_manager.h"
21 #include "chrome/browser/signin/signin_manager_factory.h"
22 #include "chrome/browser/signin/token_service.h"
23 #include "chrome/browser/signin/token_service_factory.h"
24 #include "chrome/browser/sync/credential_cache_service_factory_win.h"
25 #include "chrome/browser/sync/glue/chrome_encryptor.h"
26 #include "chrome/browser/sync/profile_sync_service.h"
27 #include "chrome/browser/sync/profile_sync_service_factory.h"
28 #include "chrome/common/chrome_constants.h"
29 #include "chrome/common/chrome_notification_types.h"
30 #include "chrome/common/chrome_paths_internal.h"
31 #include "chrome/common/chrome_switches.h"
32 #include "chrome/common/pref_names.h"
33 #include "content/public/browser/browser_thread.h"
34 #include "content/public/browser/notification_details.h"
35 #include "content/public/browser/notification_source.h"
36 #include "google_apis/gaia/gaia_auth_consumer.h"
37 #include "google_apis/gaia/gaia_constants.h"
38 #include "sync/internal_api/public/base/model_type.h"
40 namespace syncer {
42 // The time delay (in seconds) between two consecutive polls of the alternate
43 // credential cache. A two minute delay seems like a reasonable amount of time
44 // in which to propagate changes to signed in state between Metro and Desktop.
45 const int kCredentialCachePollIntervalSecs = 2 * 60;
47 // Keeps track of the last time a credential cache was written to. Used to make
48 // sure that we only apply changes from newer credential caches to older ones,
49 // and not vice versa.
50 const char kLastCacheUpdateTimeKey[] = "last_cache_update_time";
52 // Deprecated. We were previously using base::TimeTicks as a timestamp. This was
53 // bad because TimeTicks values roll over on machine restart. We now use
54 // base::Time as a timestamp. However, we can't simply reuse "last_updated_time"
55 // because it may result in a Time value being compared with a TimeTicks value.
56 const char kLastUpdatedTimeTicksDeprecated[] = "last_updated_time";
58 using base::TimeDelta;
59 using content::BrowserThread;
61 CredentialCacheService::CredentialCacheService(Profile* profile)
62 : profile_(profile),
63 // |profile_| is null in unit tests.
64 sync_prefs_(profile_ ? profile_->GetPrefs() : NULL),
65 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
66 if (profile_) {
67 InitializeLocalCredentialCacheWriter();
68 // If sync is not disabled, look for credentials in the alternate profile.
69 // Note that we do want to look for credentials in the alternate profile
70 // even if the local user is signed in, so that we can detect a sign out or
71 // reconfigure originating from the alternate profile.
72 if (!sync_prefs_.IsManaged())
73 LookForCachedCredentialsInAlternateProfile();
77 CredentialCacheService::~CredentialCacheService() {
78 Shutdown();
81 void CredentialCacheService::Shutdown() {
82 if (local_store_.get())
83 local_store_->CommitPendingWrite();
84 local_store_observer_.release();
85 local_store_.release();
86 alternate_store_observer_.release();
87 alternate_store_.release();
90 void CredentialCacheService::Observe(
91 int type,
92 const content::NotificationSource& source,
93 const content::NotificationDetails& details) {
94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
95 DCHECK(local_store_.get());
96 switch (type) {
97 case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT: {
98 // The user has signed out. Write blank values to the google username,
99 // encryption tokens and token service credentials in the local cache.
100 PackAndUpdateStringPref(prefs::kGoogleServicesUsername, std::string());
101 if (HasPref(local_store_, prefs::kSyncEncryptionBootstrapToken)) {
102 PackAndUpdateStringPref(prefs::kSyncEncryptionBootstrapToken,
103 std::string());
105 if (HasPref(local_store_, prefs::kSyncKeystoreEncryptionBootstrapToken)) {
106 PackAndUpdateStringPref(prefs::kSyncKeystoreEncryptionBootstrapToken,
107 std::string());
109 PackAndUpdateStringPref(GaiaConstants::kGaiaLsid, std::string());
110 PackAndUpdateStringPref(GaiaConstants::kGaiaSid, std::string());
111 break;
114 case chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL: {
115 // The user has signed in. Write the new value of the google username to
116 // the local cache.
117 SigninManager* signin = SigninManagerFactory::GetForProfile(profile_);
118 PackAndUpdateStringPref(prefs::kGoogleServicesUsername,
119 signin->GetAuthenticatedUsername());
120 break;
123 case chrome::NOTIFICATION_SYNC_CONFIGURE_DONE: {
124 // Local sync configuration is done. The sync service is now ready to
125 // be reconfigured. Immediately look for any unconsumed config changes in
126 // the alternate profile. If all changes have been consumed, this is a
127 // no-op.
128 ScheduleNextReadFromAlternateCredentialCache(0);
129 break;
132 case chrome::NOTIFICATION_SYNC_CONFIGURE_START: {
133 // We have detected a sync sign in, auto-start or reconfigure. Write the
134 // latest sync preferences to the local cache.
135 WriteSyncPrefsToLocalCache();
136 break;
139 case chrome::NOTIFICATION_TOKEN_LOADING_FINISHED: {
140 // The token service has been fully initialized. Update the token service
141 // credentials in the local cache. This is a no-op if the cache already
142 // contains the latest values.
143 TokenService* token_service =
144 TokenServiceFactory::GetForProfile(profile_);
145 if (token_service->AreCredentialsValid()) {
146 GaiaAuthConsumer::ClientLoginResult credentials =
147 token_service->credentials();
148 PackAndUpdateStringPref(GaiaConstants::kGaiaLsid, credentials.lsid);
149 PackAndUpdateStringPref(GaiaConstants::kGaiaSid, credentials.sid);
151 break;
154 case chrome::NOTIFICATION_TOKEN_SERVICE_CREDENTIALS_UPDATED: {
155 // The token service has new credentials. Write them to the local cache.
156 const TokenService::CredentialsUpdatedDetails& token_details =
157 *(content::Details<const TokenService::CredentialsUpdatedDetails>(
158 details).ptr());
159 PackAndUpdateStringPref(GaiaConstants::kGaiaLsid, token_details.lsid());
160 PackAndUpdateStringPref(GaiaConstants::kGaiaSid, token_details.sid());
161 break;
164 case chrome::NOTIFICATION_TOKENS_CLEARED: {
165 // Tokens have been cleared. Blank out lsid and sid in the local cache.
166 PackAndUpdateStringPref(GaiaConstants::kGaiaLsid, std::string());
167 PackAndUpdateStringPref(GaiaConstants::kGaiaSid, std::string());
168 break;
171 default: {
172 NOTREACHED();
173 break;
178 void CredentialCacheService::OnPreferenceChanged(PrefServiceBase* service,
179 const std::string& pref_name) {
180 // One of the two sync encryption tokens has changed. Update its value in
181 // the local cache.
182 if (pref_name == prefs::kSyncEncryptionBootstrapToken) {
183 PackAndUpdateStringPref(pref_name,
184 sync_prefs_.GetEncryptionBootstrapToken());
185 } else if (pref_name == prefs::kSyncKeystoreEncryptionBootstrapToken) {
186 PackAndUpdateStringPref(
187 pref_name,
188 sync_prefs_.GetKeystoreEncryptionBootstrapToken());
189 } else {
190 NOTREACHED() "Invalid pref name " << pref_name << ".";
194 void CredentialCacheService::ReadCachedCredentialsFromAlternateProfile() {
195 // If the local user has signed in and signed out, we do not consume cached
196 // credentials from the alternate profile. There is nothing more to do, now or
197 // later on.
198 if (HasUserSignedOut())
199 return;
201 // Sanity check the alternate credential cache. Note that it is sufficient to
202 // have just one of the two sync encryption tokens. If any string credentials
203 // are outright missing even though the file exists, something is awry with
204 // the alternate profile store. There is no sense in flagging an error as the
205 // problem lies in a different profile directory. There is nothing to do now.
206 // We schedule a future read from the alternate credential cache and return.
207 DCHECK(alternate_store_.get());
208 if (!HasPref(alternate_store_, prefs::kGoogleServicesUsername) ||
209 !HasPref(alternate_store_, GaiaConstants::kGaiaLsid) ||
210 !HasPref(alternate_store_, GaiaConstants::kGaiaSid) ||
211 !(HasPref(alternate_store_, prefs::kSyncEncryptionBootstrapToken) ||
212 HasPref(alternate_store_,
213 prefs::kSyncKeystoreEncryptionBootstrapToken)) ||
214 !HasPref(alternate_store_, prefs::kSyncKeepEverythingSynced)) {
215 VLOG(1) << "Could not find cached credentials in \""
216 << GetCredentialPathInAlternateProfile().value() << "\".";
217 ScheduleNextReadFromAlternateCredentialCache(
218 kCredentialCachePollIntervalSecs);
219 return;
222 // Extract the google username, lsid and sid from the alternate credential
223 // cache.
224 std::string alternate_google_services_username =
225 GetAndUnpackStringPref(alternate_store_, prefs::kGoogleServicesUsername);
226 std::string alternate_lsid =
227 GetAndUnpackStringPref(alternate_store_, GaiaConstants::kGaiaLsid);
228 std::string alternate_sid =
229 GetAndUnpackStringPref(alternate_store_, GaiaConstants::kGaiaSid);
231 // Extract the sync encryption tokens from the alternate credential cache.
232 // Both tokens may not be found, since only one of them is used at any time.
233 std::string alternate_encryption_bootstrap_token;
234 if (HasPref(alternate_store_, prefs::kSyncEncryptionBootstrapToken)) {
235 alternate_encryption_bootstrap_token =
236 GetAndUnpackStringPref(alternate_store_,
237 prefs::kSyncEncryptionBootstrapToken);
239 std::string alternate_keystore_encryption_bootstrap_token;
240 if (HasPref(alternate_store_, prefs::kSyncKeystoreEncryptionBootstrapToken)) {
241 alternate_keystore_encryption_bootstrap_token =
242 GetAndUnpackStringPref(alternate_store_,
243 prefs::kSyncKeystoreEncryptionBootstrapToken);
246 // Sign out of sync if the alternate profile has signed out the same user.
247 // There is no need to schedule any more reads of the alternate profile
248 // cache because we only apply cached credentials for first-time sign-ins.
249 if (ShouldSignOutOfSync(alternate_google_services_username)) {
250 VLOG(1) << "User has signed out on the other profile. Signing out.";
251 InitiateSignOut();
252 return;
255 // Extract cached sync prefs from the alternate credential cache.
256 bool alternate_keep_everything_synced =
257 GetBooleanPref(alternate_store_, prefs::kSyncKeepEverythingSynced);
258 ProfileSyncService* service =
259 ProfileSyncServiceFactory::GetForProfile(profile_);
260 ModelTypeSet registered_types = service->GetRegisteredDataTypes();
261 ModelTypeSet alternate_preferred_types;
262 for (ModelTypeSet::Iterator it = registered_types.First();
263 it.Good();
264 it.Inc()) {
265 std::string datatype_pref_name =
266 browser_sync::SyncPrefs::GetPrefNameForDataType(it.Get());
267 if (!HasPref(alternate_store_, datatype_pref_name)) {
268 // If there is no cached pref for a specific data type, it means that the
269 // user originally signed in with an older version of Chrome, and then
270 // upgraded to a version with a new datatype. In such cases, we leave the
271 // default initial datatype setting as false while reading cached
272 // credentials, just like we do in SyncPrefs::RegisterPreferences.
273 VLOG(1) << "Could not find cached datatype pref for "
274 << datatype_pref_name << " in "
275 << GetCredentialPathInAlternateProfile().value() << ".";
276 continue;
278 if (GetBooleanPref(alternate_store_, datatype_pref_name))
279 alternate_preferred_types.Put(it.Get());
282 // Reconfigure if sync settings, encryption tokens or token service
283 // credentials have changed in the alternate profile, but for the same user
284 // that is signed in to the local profile.
285 if (MayReconfigureSync(alternate_google_services_username)) {
286 if (HaveSyncPrefsChanged(alternate_keep_everything_synced,
287 alternate_preferred_types)) {
288 VLOG(1) << "Sync prefs have changed in other profile. Reconfiguring.";
289 service->OnUserChoseDatatypes(alternate_keep_everything_synced,
290 alternate_preferred_types);
292 if (HaveSyncEncryptionTokensChanged(
293 alternate_encryption_bootstrap_token,
294 alternate_keystore_encryption_bootstrap_token)) {
295 VLOG(1) << "Sync encryption tokens have changed in other profile.";
296 sync_prefs_.SetEncryptionBootstrapToken(
297 alternate_encryption_bootstrap_token);
298 sync_prefs_.SetKeystoreEncryptionBootstrapToken(
299 alternate_keystore_encryption_bootstrap_token);
301 if (HaveTokenServiceCredentialsChanged(alternate_lsid, alternate_sid)) {
302 VLOG(1) << "Token service credentials have changed in other profile.";
303 UpdateTokenServiceCredentials(alternate_lsid, alternate_sid);
307 // Sign in if we notice new cached credentials in the alternate profile.
308 if (ShouldSignInToSync(alternate_google_services_username,
309 alternate_lsid,
310 alternate_sid,
311 alternate_encryption_bootstrap_token,
312 alternate_keystore_encryption_bootstrap_token)) {
313 InitiateSignInWithCachedCredentials(
314 alternate_google_services_username,
315 alternate_encryption_bootstrap_token,
316 alternate_keystore_encryption_bootstrap_token,
317 alternate_keep_everything_synced,
318 alternate_preferred_types);
319 UpdateTokenServiceCredentials(alternate_lsid, alternate_sid);
322 // Schedule the next read from the alternate credential cache so that we can
323 // detect future reconfigures or sign outs.
324 ScheduleNextReadFromAlternateCredentialCache(
325 kCredentialCachePollIntervalSecs);
328 void CredentialCacheService::WriteSyncPrefsToLocalCache() {
329 UpdateBooleanPref(prefs::kSyncKeepEverythingSynced,
330 sync_prefs_.HasKeepEverythingSynced());
331 ProfileSyncService* service =
332 ProfileSyncServiceFactory::GetForProfile(profile_);
333 ModelTypeSet registered_types = service->GetRegisteredDataTypes();
334 for (ModelTypeSet::Iterator it = registered_types.First();
335 it.Good();
336 it.Inc()) {
337 std::string datatype_pref_name =
338 browser_sync::SyncPrefs::GetPrefNameForDataType(it.Get());
339 UpdateBooleanPref(
340 datatype_pref_name,
341 profile_->GetPrefs()->GetBoolean(datatype_pref_name.c_str()));
345 void CredentialCacheService::ScheduleNextReadFromAlternateCredentialCache(
346 int delay_secs) {
347 DCHECK_LE(0, delay_secs);
348 // We must reinitialize |alternate_store_| here because the underlying
349 // credential file in the alternate profile might have changed, and we must
350 // re-read it afresh.
351 alternate_store_observer_.release();
352 alternate_store_.release();
353 next_read_.Reset(base::Bind(
354 &CredentialCacheService::LookForCachedCredentialsInAlternateProfile,
355 weak_factory_.GetWeakPtr()));
356 MessageLoop::current()->PostDelayedTask(
357 FROM_HERE,
358 next_read_.callback(),
359 TimeDelta::FromSeconds(delay_secs));
362 bool CredentialCacheService::HasPref(scoped_refptr<JsonPrefStore> store,
363 const std::string& pref_name) {
364 return store->GetValue(pref_name, NULL);
367 // static
368 base::StringValue* CredentialCacheService::PackCredential(
369 const std::string& credential) {
370 // Do nothing for empty credentials.
371 if (credential.empty())
372 return base::Value::CreateStringValue("");
374 browser_sync::ChromeEncryptor encryptor;
375 std::string encrypted;
376 if (!encryptor.EncryptString(credential, &encrypted)) {
377 NOTREACHED();
378 return base::Value::CreateStringValue(std::string());
381 std::string encoded;
382 if (!base::Base64Encode(encrypted, &encoded)) {
383 NOTREACHED();
384 return base::Value::CreateStringValue(std::string());
387 return base::Value::CreateStringValue(encoded);
390 // static
391 std::string CredentialCacheService::UnpackCredential(
392 const base::Value& packed) {
393 std::string encoded;
394 if (!packed.GetAsString(&encoded)) {
395 NOTREACHED();
396 return std::string();
399 // Do nothing for empty credentials.
400 if (encoded.empty())
401 return std::string();
403 std::string encrypted;
404 if (!base::Base64Decode(encoded, &encrypted)) {
405 NOTREACHED();
406 return std::string();
409 browser_sync::ChromeEncryptor encryptor;
410 std::string unencrypted;
411 if (!encryptor.DecryptString(encrypted, &unencrypted)) {
412 NOTREACHED();
413 return std::string();
416 return unencrypted;
419 void CredentialCacheService::WriteLastCacheUpdateTime() {
420 DCHECK(local_store_.get());
421 int64 last_cache_update_time_int64 = base::Time::Now().ToInternalValue();
422 std::string last_cache_update_time_string =
423 base::Int64ToString(last_cache_update_time_int64);
424 local_store_->SetValueSilently(
425 kLastCacheUpdateTimeKey,
426 base::Value::CreateStringValue(last_cache_update_time_string));
429 void CredentialCacheService::PackAndUpdateStringPref(
430 const std::string& pref_name,
431 const std::string& new_value) {
432 DCHECK(local_store_.get());
433 if (HasPref(local_store_, pref_name) &&
434 GetAndUnpackStringPref(local_store_, pref_name) == new_value) {
435 return;
437 if (!HasUserSignedOut()) {
438 local_store_->SetValueSilently(pref_name, PackCredential(new_value));
439 } else {
440 // Write a blank value since we cache credentials only for first-time
441 // sign-ins.
442 local_store_->SetValueSilently(pref_name, PackCredential(std::string()));
444 WriteLastCacheUpdateTime();
447 void CredentialCacheService::UpdateBooleanPref(const std::string& pref_name,
448 bool new_value) {
449 DCHECK(local_store_.get());
450 if (HasPref(local_store_, pref_name) &&
451 GetBooleanPref(local_store_, pref_name) == new_value) {
452 return;
454 if (!HasUserSignedOut()) {
455 local_store_->SetValueSilently(pref_name,
456 base::Value::CreateBooleanValue(new_value));
457 } else {
458 // Write a default value of false since we cache credentials only for
459 // first-time sign-ins.
460 local_store_->SetValueSilently(pref_name,
461 base::Value::CreateBooleanValue(false));
463 WriteLastCacheUpdateTime();
466 base::Time CredentialCacheService::GetLastCacheUpdateTime(
467 scoped_refptr<JsonPrefStore> store) {
468 DCHECK(HasPref(store, kLastCacheUpdateTimeKey));
469 const base::Value* last_cache_update_time_value = NULL;
470 store->GetValue(kLastCacheUpdateTimeKey, &last_cache_update_time_value);
471 DCHECK(last_cache_update_time_value);
472 std::string last_cache_update_time_string;
473 last_cache_update_time_value->GetAsString(&last_cache_update_time_string);
474 int64 last_cache_update_time_int64;
475 bool success = base::StringToInt64(last_cache_update_time_string,
476 &last_cache_update_time_int64);
477 DCHECK(success);
478 return base::Time::FromInternalValue(last_cache_update_time_int64);
481 bool CredentialCacheService::AlternateCacheIsMoreRecent() {
482 DCHECK(alternate_store_.get());
483 // If the alternate credential cache doesn't have the "last_cache_update_time"
484 // field, it was written by an older version of chrome, and we therefore
485 // consider the local cache to be more recent.
486 if (!HasPref(alternate_store_, kLastCacheUpdateTimeKey))
487 return false;
488 DCHECK(HasPref(local_store_, kLastCacheUpdateTimeKey));
489 return GetLastCacheUpdateTime(alternate_store_) >
490 GetLastCacheUpdateTime(local_store_);
493 std::string CredentialCacheService::GetAndUnpackStringPref(
494 scoped_refptr<JsonPrefStore> store,
495 const std::string& pref_name) {
496 const base::Value* pref_value = NULL;
497 store->GetValue(pref_name, &pref_value);
498 return UnpackCredential(*pref_value);
501 bool CredentialCacheService::GetBooleanPref(
502 scoped_refptr<JsonPrefStore> store,
503 const std::string& pref_name) {
504 const base::Value* pref_value = NULL;
505 store->GetValue(pref_name, &pref_value);
506 bool pref;
507 pref_value->GetAsBoolean(&pref);
508 return pref;
511 CredentialCacheService::LocalStoreObserver::LocalStoreObserver(
512 CredentialCacheService* service,
513 scoped_refptr<JsonPrefStore> local_store)
514 : service_(service),
515 local_store_(local_store) {
516 local_store_->AddObserver(this);
519 CredentialCacheService::LocalStoreObserver::~LocalStoreObserver() {
520 local_store_->RemoveObserver(this);
523 void CredentialCacheService::LocalStoreObserver::OnInitializationCompleted(
524 bool succeeded) {
525 // Note that |succeeded| will be true even if the local cache file wasn't
526 // found, so long as its parent dir (the chrome profile directory) was found.
527 // If |succeeded| is false, it means that the chrome profile directory is
528 // missing. In this case, there's nothing we can do other than DCHECK.
529 DCHECK(succeeded);
531 // During startup, we do a precautionary write of the google username,
532 // encryption tokens, sync prefs and last cache update time to the local cache
533 // in order to recover from the following cases:
534 // 1) There is no local credential cache, but the user is signed in. This
535 // could happen if a signed-in user restarts chrome after upgrading from
536 // an older version that didn't support credential caching.
537 // 2) There is a local credential cache, but we missed writing sync credential
538 // updates to it in the past due to a crash, or due to the user exiting
539 // chrome in the midst of a sign in, sign out or reconfigure.
540 // 3) There is a local credential cache that was written to by an older
541 // version of Chrome, and it does not contain the "last_cache_update_time"
542 // field.
543 // Note: If the local credential cache was already up-to-date, the operations
544 // below will be no-ops, and won't change the cache's last updated time. Also,
545 // if the user is not signed in and there is no local credential cache, we
546 // don't want to create a cache with empty values.
547 SigninManager* signin =
548 SigninManagerFactory::GetForProfile(service_->profile_);
549 if ((local_store_->GetReadError() == JsonPrefStore::PREF_READ_ERROR_NO_FILE &&
550 !signin->GetAuthenticatedUsername().empty()) ||
551 (local_store_->GetReadError() == JsonPrefStore::PREF_READ_ERROR_NONE)) {
552 service_->PackAndUpdateStringPref(prefs::kGoogleServicesUsername,
553 signin->GetAuthenticatedUsername());
554 if (!service_->sync_prefs_.GetEncryptionBootstrapToken().empty()) {
555 service_->PackAndUpdateStringPref(
556 prefs::kSyncEncryptionBootstrapToken,
557 service_->sync_prefs_.GetEncryptionBootstrapToken());
559 if (!service_->sync_prefs_.GetKeystoreEncryptionBootstrapToken().empty()) {
560 service_->PackAndUpdateStringPref(
561 prefs::kSyncKeystoreEncryptionBootstrapToken,
562 service_->sync_prefs_.GetKeystoreEncryptionBootstrapToken());
564 service_->WriteSyncPrefsToLocalCache();
565 if (!service_->HasPref(local_store_, kLastCacheUpdateTimeKey))
566 service_->WriteLastCacheUpdateTime();
567 if (service_->HasPref(local_store_, kLastUpdatedTimeTicksDeprecated))
568 local_store_->RemoveValue(kLastUpdatedTimeTicksDeprecated);
571 // Now that the local credential cache is ready, start listening for events
572 // associated with various sync config changes.
573 service_->StartListeningForSyncConfigChanges();
576 void CredentialCacheService::LocalStoreObserver::OnPrefValueChanged(
577 const std::string& key) {
578 // Nothing to do here, since credentials are cached silently.
581 CredentialCacheService::AlternateStoreObserver::AlternateStoreObserver(
582 CredentialCacheService* service,
583 scoped_refptr<JsonPrefStore> alternate_store)
584 : service_(service),
585 alternate_store_(alternate_store) {
586 alternate_store_->AddObserver(this);
589 CredentialCacheService::AlternateStoreObserver::~AlternateStoreObserver() {
590 alternate_store_->RemoveObserver(this);
593 void CredentialCacheService::AlternateStoreObserver::OnInitializationCompleted(
594 bool succeeded) {
595 // If an alternate credential cache was found, begin consuming its contents.
596 // If not, schedule a future read.
597 if (succeeded &&
598 alternate_store_->GetReadError() == JsonPrefStore::PREF_READ_ERROR_NONE) {
599 service_->ReadCachedCredentialsFromAlternateProfile();
600 } else {
601 service_->ScheduleNextReadFromAlternateCredentialCache(
602 kCredentialCachePollIntervalSecs);
606 void CredentialCacheService::AlternateStoreObserver::OnPrefValueChanged(
607 const std::string& key) {
608 // Nothing to do here, since credentials are cached silently.
611 FilePath CredentialCacheService::GetCredentialPathInCurrentProfile() const {
612 // The sync credential path in the default Desktop profile is
613 // "%Appdata%\Local\Google\Chrome\User Data\Default\Sync Credentials", while
614 // the sync credential path in the default Metro profile is
615 // "%Appdata%\Local\Google\Chrome\Metro\User Data\Default\Sync Credentials".
616 DCHECK(profile_);
617 return profile_->GetPath().Append(chrome::kSyncCredentialsFilename);
620 FilePath CredentialCacheService::GetCredentialPathInAlternateProfile() const {
621 DCHECK(profile_);
622 FilePath alternate_user_data_dir;
623 chrome::GetAlternateUserDataDirectory(&alternate_user_data_dir);
625 // TODO(rsimha): This code path is to allow for testing in the presence of
626 // strange singleton mode. Delete this block before shipping.
627 // See http://crbug.com/144280.
628 const CommandLine* command_line = CommandLine::ForCurrentProcess();
629 if (command_line->HasSwitch(switches::kEnableSyncCredentialCaching) &&
630 !CredentialCacheServiceFactory::IsDefaultProfile(profile_)) {
631 DCHECK(CredentialCacheServiceFactory::IsDefaultAlternateProfileForTest(
632 profile_));
633 chrome::GetDefaultUserDataDirectory(&alternate_user_data_dir);
636 FilePath alternate_default_profile_dir =
637 ProfileManager::GetDefaultProfileDir(alternate_user_data_dir);
638 return alternate_default_profile_dir.Append(chrome::kSyncCredentialsFilename);
641 void CredentialCacheService::InitializeLocalCredentialCacheWriter() {
642 local_store_ = new JsonPrefStore(
643 GetCredentialPathInCurrentProfile(),
644 content::BrowserThread::GetMessageLoopProxyForThread(
645 content::BrowserThread::FILE));
646 local_store_observer_ = new LocalStoreObserver(this, local_store_);
647 local_store_->ReadPrefsAsync(NULL);
650 void CredentialCacheService::StartListeningForSyncConfigChanges() {
651 // Register for notifications for google sign in and sign out.
652 registrar_.Add(this,
653 chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
654 content::Source<Profile>(profile_));
655 registrar_.Add(this,
656 chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
657 content::Source<Profile>(profile_));
659 // Register for notifications for sync configuration changes that could occur
660 // during sign in or reconfiguration.
661 ProfileSyncService* service =
662 ProfileSyncServiceFactory::GetForProfile(profile_);
663 registrar_.Add(this,
664 chrome::NOTIFICATION_SYNC_CONFIGURE_DONE,
665 content::Source<ProfileSyncService>(service));
666 registrar_.Add(this,
667 chrome::NOTIFICATION_SYNC_CONFIGURE_START,
668 content::Source<ProfileSyncService>(service));
670 // Register for notifications for updates to the sync encryption tokens, which
671 // are stored in the PrefStore.
672 pref_registrar_.Init(profile_->GetPrefs());
673 pref_registrar_.Add(prefs::kSyncEncryptionBootstrapToken, this);
674 pref_registrar_.Add(prefs::kSyncKeystoreEncryptionBootstrapToken, this);
676 // Register for notifications for updates to lsid and sid, which are stored in
677 // the TokenService.
678 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
679 registrar_.Add(this,
680 chrome::NOTIFICATION_TOKEN_LOADING_FINISHED,
681 content::Source<TokenService>(token_service));
682 registrar_.Add(this,
683 chrome::NOTIFICATION_TOKEN_SERVICE_CREDENTIALS_UPDATED,
684 content::Source<TokenService>(token_service));
685 registrar_.Add(this,
686 chrome::NOTIFICATION_TOKENS_CLEARED,
687 content::Source<TokenService>(token_service));
690 void CredentialCacheService::LookForCachedCredentialsInAlternateProfile() {
691 // Attempt to read cached credentials from the alternate profile. If no file
692 // exists, ReadPrefsAsync() will cause PREF_READ_ERROR_NO_FILE to be returned
693 // after initialization is complete.
694 FilePath path = GetCredentialPathInAlternateProfile();
695 alternate_store_ = new JsonPrefStore(
696 path,
697 content::BrowserThread::GetMessageLoopProxyForThread(
698 content::BrowserThread::FILE));
699 alternate_store_observer_ = new AlternateStoreObserver(this,
700 alternate_store_);
701 alternate_store_->ReadPrefsAsync(NULL);
704 bool CredentialCacheService::HasUserSignedOut() {
705 DCHECK(local_store_.get());
706 // If HasPref() is false, the user never signed in, since there are no
707 // previously cached credentials. If the kGoogleServicesUsername pref is
708 // empty, it means that the user signed in and subsequently signed out.
709 return HasPref(local_store_, prefs::kGoogleServicesUsername) &&
710 GetAndUnpackStringPref(local_store_,
711 prefs::kGoogleServicesUsername).empty();
714 void CredentialCacheService::InitiateSignInWithCachedCredentials(
715 const std::string& google_services_username,
716 const std::string& encryption_bootstrap_token,
717 const std::string& keystore_encryption_bootstrap_token,
718 bool keep_everything_synced,
719 ModelTypeSet preferred_types) {
720 // Update the google username in the SigninManager and PrefStore. Also update
721 // its value in the local credential cache, since we will not send out
722 // NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL in this case.
723 ProfileSyncService* service =
724 ProfileSyncServiceFactory::GetForProfile(profile_);
725 service->signin()->SetAuthenticatedUsername(google_services_username);
726 profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
727 google_services_username);
728 PackAndUpdateStringPref(prefs::kGoogleServicesUsername,
729 service->signin()->GetAuthenticatedUsername());
731 // Update sync encryption tokens after making sure at least one of them is
732 // non-empty.
733 DCHECK(!encryption_bootstrap_token.empty() ||
734 !keystore_encryption_bootstrap_token.empty());
735 if (!encryption_bootstrap_token.empty()) {
736 sync_prefs_.SetEncryptionBootstrapToken(encryption_bootstrap_token);
738 if (!keystore_encryption_bootstrap_token.empty()) {
739 sync_prefs_.SetKeystoreEncryptionBootstrapToken(
740 keystore_encryption_bootstrap_token);
743 // Update the sync preferences.
744 sync_prefs_.SetStartSuppressed(false);
745 sync_prefs_.SetSyncSetupCompleted();
746 sync_prefs_.SetKeepEverythingSynced(keep_everything_synced);
747 sync_prefs_.SetPreferredDataTypes(service->GetRegisteredDataTypes(),
748 preferred_types);
751 void CredentialCacheService::UpdateTokenServiceCredentials(
752 const std::string& alternate_lsid,
753 const std::string& alternate_sid) {
754 GaiaAuthConsumer::ClientLoginResult login_result;
755 login_result.lsid = alternate_lsid;
756 login_result.sid = alternate_sid;
757 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
758 token_service->UpdateCredentials(login_result);
759 DCHECK(token_service->AreCredentialsValid());
760 token_service->StartFetchingTokens();
763 void CredentialCacheService::InitiateSignOut() {
764 ProfileSyncService* service =
765 ProfileSyncServiceFactory::GetForProfile(profile_);
766 service->DisableForUser();
769 bool CredentialCacheService::HaveSyncPrefsChanged(
770 bool alternate_keep_everything_synced,
771 ModelTypeSet alternate_preferred_types) const {
772 if (alternate_keep_everything_synced &&
773 sync_prefs_.HasKeepEverythingSynced()) {
774 return false;
776 ProfileSyncService* service =
777 ProfileSyncServiceFactory::GetForProfile(profile_);
778 ModelTypeSet local_preferred_types =
779 sync_prefs_.GetPreferredDataTypes(service->GetRegisteredDataTypes());
780 return
781 (alternate_keep_everything_synced !=
782 sync_prefs_.HasKeepEverythingSynced()) ||
783 !alternate_preferred_types.Equals(local_preferred_types);
786 bool CredentialCacheService::HaveSyncEncryptionTokensChanged(
787 const std::string& alternate_encryption_bootstrap_token,
788 const std::string& alternate_keystore_encryption_bootstrap_token) {
789 std::string local_encryption_bootstrap_token;
790 if (HasPref(local_store_, prefs::kSyncEncryptionBootstrapToken)) {
791 local_encryption_bootstrap_token =
792 GetAndUnpackStringPref(local_store_,
793 prefs::kSyncEncryptionBootstrapToken);
795 std::string local_keystore_encryption_bootstrap_token;
796 if (HasPref(local_store_, prefs::kSyncKeystoreEncryptionBootstrapToken)) {
797 local_keystore_encryption_bootstrap_token =
798 GetAndUnpackStringPref(local_store_,
799 prefs::kSyncKeystoreEncryptionBootstrapToken);
801 return (local_encryption_bootstrap_token !=
802 alternate_encryption_bootstrap_token) ||
803 (local_keystore_encryption_bootstrap_token !=
804 alternate_keystore_encryption_bootstrap_token);
807 bool CredentialCacheService::HaveTokenServiceCredentialsChanged(
808 const std::string& alternate_lsid,
809 const std::string& alternate_sid) {
810 std::string local_lsid =
811 GetAndUnpackStringPref(local_store_, GaiaConstants::kGaiaLsid);
812 std::string local_sid =
813 GetAndUnpackStringPref(local_store_, GaiaConstants::kGaiaSid);
814 return local_lsid != alternate_lsid || local_sid != alternate_sid;
817 bool CredentialCacheService::ShouldSignOutOfSync(
818 const std::string& alternate_google_services_username) {
819 // We must sign out of sync iff:
820 // 1) The user is signed in to the local profile.
821 // 2) The user has never signed out of the local profile in the past.
822 // 3) We noticed that the user has signed out of the alternate profile.
823 // 4) The user is not already in the process of configuring sync.
824 // 5) The alternate cache was updated more recently than the local cache.
825 ProfileSyncService* service =
826 ProfileSyncServiceFactory::GetForProfile(profile_);
827 return !service->signin()->GetAuthenticatedUsername().empty() &&
828 !HasUserSignedOut() &&
829 alternate_google_services_username.empty() &&
830 !service->setup_in_progress() &&
831 AlternateCacheIsMoreRecent();
834 bool CredentialCacheService::MayReconfigureSync(
835 const std::string& alternate_google_services_username) {
836 // We may attempt to reconfigure sync iff:
837 // 1) The user is signed in to the local profile.
838 // 2) The user has never signed out of the local profile in the past.
839 // 3) The user is signed in to the alternate profile with the same account.
840 // 4) The user is not already in the process of configuring sync.
841 // 5) The alternate cache was updated more recently than the local cache.
842 // 6) The sync backend is initialized and ready to consume config changes.
843 ProfileSyncService* service =
844 ProfileSyncServiceFactory::GetForProfile(profile_);
845 return !service->signin()->GetAuthenticatedUsername().empty() &&
846 !HasUserSignedOut() &&
847 (alternate_google_services_username ==
848 service->signin()->GetAuthenticatedUsername()) &&
849 !service->setup_in_progress() &&
850 AlternateCacheIsMoreRecent() &&
851 service->ShouldPushChanges();
854 bool CredentialCacheService::ShouldSignInToSync(
855 const std::string& alternate_google_services_username,
856 const std::string& alternate_lsid,
857 const std::string& alternate_sid,
858 const std::string& alternate_encryption_bootstrap_token,
859 const std::string& alternate_keystore_encryption_bootstrap_token) {
860 // We should sign in with cached credentials from the alternate profile iff:
861 // 1) The user is not currently signed in to the local profile.
862 // 2) The user has never signed out of the local profile in the past.
863 // 3) Valid cached credentials are available in the alternate profile.
864 // 4) The user is not already in the process of configuring sync.
865 ProfileSyncService* service =
866 ProfileSyncServiceFactory::GetForProfile(profile_);
867 return service->signin()->GetAuthenticatedUsername().empty() &&
868 !HasUserSignedOut() &&
869 !alternate_google_services_username.empty() &&
870 !alternate_lsid.empty() &&
871 !alternate_sid.empty() &&
872 !(alternate_encryption_bootstrap_token.empty() &&
873 alternate_keystore_encryption_bootstrap_token.empty()) &&
874 !service->setup_in_progress();
877 } // namespace syncer