Commit a8fa4cae authored by rsimha@chromium.org's avatar rsimha@chromium.org

[sync] Auto-heal sync credential cache on startup, and no longer rely on NOTIFICATION_PREF_CHANGED

CredentialCacheService listens for initial sync configuration during
sign in by directly observing sync preferences in the pref store. This
is not good because sync preferences are not always re-written
during sign in, and we cannot rely on NOTIFICATION_PREF_CHANGED.

In addition, if during startup, we find an older version of a credential
cache with some fields missing (like the last_updated_time), we could
run into bugs due to the missing fields.

This patch does the following:

1) Makes CredentialCacheService listen to the notification
   NOTIFICATION_SYNC_CONFIGURE_START for sign-in, restart and
   reconfigure scenarios.
2) No longer relies on NOTIFICATION_PREF_CHANGED for detecting
   changes to sync datatype preferences.
2) Freshly writes any missing sync credentials during startup to
   auto-heal the cache in case chrome crashed during a previous run,
   or if a signed-in user upgraded chrome from an older version that
   didn't support credential caching or was missing some newer fields.
3) Adds caching support for both sync encryption tokens:
   kSyncEncryptionBootstrapToken and kSyncKeystoreEncryptionBootstrapToken,
   and makes the required logic changes to sign in / reconfigure with
   one or the other.
4) Modifies PackAndUpdateStringPref and UpdateBooleanPref to only
   update the cache if the new value being written is different from the
   existing value.
5) Other misc. changes to support the design described above.

BUG=142550, 143214
TEST=Sign in to sync, sign out, exit chrome, delete the credential cache from the profile directory or merely delete some fields, and sign in again. All sync preferences must get written to the credential cache.

Review URL: https://chromiumcodereview.appspot.com/10829310

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@152157 0039d316-1c4b-4281-b951-d872f2087c98
parent 3295f031
...@@ -70,6 +70,8 @@ CredentialCacheService::~CredentialCacheService() { ...@@ -70,6 +70,8 @@ CredentialCacheService::~CredentialCacheService() {
} }
void CredentialCacheService::Shutdown() { void CredentialCacheService::Shutdown() {
if (local_store_.get())
local_store_->CommitPendingWrite();
local_store_observer_.release(); local_store_observer_.release();
local_store_.release(); local_store_.release();
alternate_store_observer_.release(); alternate_store_observer_.release();
...@@ -84,36 +86,60 @@ void CredentialCacheService::Observe( ...@@ -84,36 +86,60 @@ void CredentialCacheService::Observe(
DCHECK(local_store_.get()); DCHECK(local_store_.get());
switch (type) { switch (type) {
case chrome::NOTIFICATION_PREF_CHANGED: { case chrome::NOTIFICATION_PREF_CHANGED: {
// One of the two sync encryption tokens has changed. Update its value in
// the local cache.
const std::string pref_name = const std::string pref_name =
*(content::Details<const std::string>(details).ptr()); *(content::Details<const std::string>(details).ptr());
if (pref_name == prefs::kSyncEncryptionBootstrapToken) { if (pref_name == prefs::kSyncEncryptionBootstrapToken) {
PackAndUpdateStringPref(pref_name, PackAndUpdateStringPref(pref_name,
sync_prefs_.GetEncryptionBootstrapToken()); sync_prefs_.GetEncryptionBootstrapToken());
} else if (pref_name == prefs::kSyncKeystoreEncryptionBootstrapToken) {
PackAndUpdateStringPref(
pref_name,
sync_prefs_.GetKeystoreEncryptionBootstrapToken());
} else { } else {
UpdateBooleanPref(pref_name, NOTREACHED() "Invalid pref name " << pref_name << ".";
profile_->GetPrefs()->GetBoolean(pref_name.c_str()));
} }
break; break;
} }
case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT: case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT: {
// The user has signed out. Write blank values to the google username,
// encryption tokens and token service credentials in the local cache.
PackAndUpdateStringPref(prefs::kGoogleServicesUsername, std::string());
if (HasPref(local_store_, prefs::kSyncEncryptionBootstrapToken)) {
PackAndUpdateStringPref(prefs::kSyncEncryptionBootstrapToken,
std::string());
}
if (HasPref(local_store_, prefs::kSyncKeystoreEncryptionBootstrapToken)) {
PackAndUpdateStringPref(prefs::kSyncKeystoreEncryptionBootstrapToken,
std::string());
}
PackAndUpdateStringPref(GaiaConstants::kGaiaLsid, std::string());
PackAndUpdateStringPref(GaiaConstants::kGaiaSid, std::string());
break;
}
case chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL: { case chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL: {
// The user has signed in. Write the new value of the google username to
// the local cache.
SigninManager* signin = SigninManagerFactory::GetForProfile(profile_); SigninManager* signin = SigninManagerFactory::GetForProfile(profile_);
PackAndUpdateStringPref(prefs::kGoogleServicesUsername, PackAndUpdateStringPref(prefs::kGoogleServicesUsername,
signin->GetAuthenticatedUsername()); signin->GetAuthenticatedUsername());
break; break;
} }
case chrome::NOTIFICATION_SYNC_CONFIGURE_START: {
// We have detected a sync sign in, auto-start or reconfigure. Write the
// latest sync preferences to the local cache.
WriteSyncPrefsToLocalCache();
break;
}
case chrome::NOTIFICATION_TOKEN_LOADING_FINISHED: { case chrome::NOTIFICATION_TOKEN_LOADING_FINISHED: {
// If there is no existing local credential cache, and the token service // The token service has been fully initialized. Update the token service
// already has valid credentials as a result of the user having signed in, // credentials in the local cache. This is a no-op if the cache already
// write them to the cache. Used in cases where the user was already // contains the latest values.
// signed in and then upgraded from a version of chrome that didn't
// support credential caching.
if (local_store_.get() &&
local_store_->IsInitializationComplete() &&
local_store_->GetReadError() ==
JsonPrefStore::PREF_READ_ERROR_NO_FILE) {
TokenService* token_service = TokenService* token_service =
TokenServiceFactory::GetForProfile(profile_); TokenServiceFactory::GetForProfile(profile_);
if (token_service->AreCredentialsValid()) { if (token_service->AreCredentialsValid()) {
...@@ -122,11 +148,11 @@ void CredentialCacheService::Observe( ...@@ -122,11 +148,11 @@ void CredentialCacheService::Observe(
PackAndUpdateStringPref(GaiaConstants::kGaiaLsid, credentials.lsid); PackAndUpdateStringPref(GaiaConstants::kGaiaLsid, credentials.lsid);
PackAndUpdateStringPref(GaiaConstants::kGaiaSid, credentials.sid); PackAndUpdateStringPref(GaiaConstants::kGaiaSid, credentials.sid);
} }
}
break; break;
} }
case chrome::NOTIFICATION_TOKEN_SERVICE_CREDENTIALS_UPDATED: { case chrome::NOTIFICATION_TOKEN_SERVICE_CREDENTIALS_UPDATED: {
// The token service has new credentials. Write them to the local cache.
const TokenService::CredentialsUpdatedDetails& token_details = const TokenService::CredentialsUpdatedDetails& token_details =
*(content::Details<const TokenService::CredentialsUpdatedDetails>( *(content::Details<const TokenService::CredentialsUpdatedDetails>(
details).ptr()); details).ptr());
...@@ -136,6 +162,7 @@ void CredentialCacheService::Observe( ...@@ -136,6 +162,7 @@ void CredentialCacheService::Observe(
} }
case chrome::NOTIFICATION_TOKENS_CLEARED: { case chrome::NOTIFICATION_TOKENS_CLEARED: {
// Tokens have been cleared. Blank out lsid and sid in the local cache.
PackAndUpdateStringPref(GaiaConstants::kGaiaLsid, std::string()); PackAndUpdateStringPref(GaiaConstants::kGaiaLsid, std::string());
PackAndUpdateStringPref(GaiaConstants::kGaiaSid, std::string()); PackAndUpdateStringPref(GaiaConstants::kGaiaSid, std::string());
break; break;
...@@ -155,7 +182,8 @@ void CredentialCacheService::ReadCachedCredentialsFromAlternateProfile() { ...@@ -155,7 +182,8 @@ void CredentialCacheService::ReadCachedCredentialsFromAlternateProfile() {
if (HasUserSignedOut()) if (HasUserSignedOut())
return; return;
// Sanity check the alternate credential cache. If any string credentials // Sanity check the alternate credential cache. Note that it is sufficient to
// have just one of the two sync encryption tokens. If any string credentials
// are outright missing even though the file exists, something is awry with // are outright missing even though the file exists, something is awry with
// the alternate profile store. There is no sense in flagging an error as the // the alternate profile store. There is no sense in flagging an error as the
// problem lies in a different profile directory. There is nothing to do now. // problem lies in a different profile directory. There is nothing to do now.
...@@ -164,7 +192,9 @@ void CredentialCacheService::ReadCachedCredentialsFromAlternateProfile() { ...@@ -164,7 +192,9 @@ void CredentialCacheService::ReadCachedCredentialsFromAlternateProfile() {
if (!HasPref(alternate_store_, prefs::kGoogleServicesUsername) || if (!HasPref(alternate_store_, prefs::kGoogleServicesUsername) ||
!HasPref(alternate_store_, GaiaConstants::kGaiaLsid) || !HasPref(alternate_store_, GaiaConstants::kGaiaLsid) ||
!HasPref(alternate_store_, GaiaConstants::kGaiaSid) || !HasPref(alternate_store_, GaiaConstants::kGaiaSid) ||
!HasPref(alternate_store_, prefs::kSyncEncryptionBootstrapToken) || !(HasPref(alternate_store_, prefs::kSyncEncryptionBootstrapToken) ||
HasPref(alternate_store_,
prefs::kSyncKeystoreEncryptionBootstrapToken)) ||
!HasPref(alternate_store_, prefs::kSyncKeepEverythingSynced)) { !HasPref(alternate_store_, prefs::kSyncKeepEverythingSynced)) {
VLOG(1) << "Could not find cached credentials in \"" VLOG(1) << "Could not find cached credentials in \""
<< GetCredentialPathInAlternateProfile().value() << "\"."; << GetCredentialPathInAlternateProfile().value() << "\".";
...@@ -172,33 +202,46 @@ void CredentialCacheService::ReadCachedCredentialsFromAlternateProfile() { ...@@ -172,33 +202,46 @@ void CredentialCacheService::ReadCachedCredentialsFromAlternateProfile() {
return; return;
} }
// Extract cached credentials from the alternate credential cache. // Extract the google username, lsid and sid from the alternate credential
std::string google_services_username = // cache.
std::string alternate_google_services_username =
GetAndUnpackStringPref(alternate_store_, prefs::kGoogleServicesUsername); GetAndUnpackStringPref(alternate_store_, prefs::kGoogleServicesUsername);
std::string lsid = std::string alternate_lsid =
GetAndUnpackStringPref(alternate_store_, GaiaConstants::kGaiaLsid); GetAndUnpackStringPref(alternate_store_, GaiaConstants::kGaiaLsid);
std::string sid = std::string alternate_sid =
GetAndUnpackStringPref(alternate_store_, GaiaConstants::kGaiaSid); GetAndUnpackStringPref(alternate_store_, GaiaConstants::kGaiaSid);
std::string encryption_bootstrap_token =
// Extract the sync encryption tokens from the alternate credential cache.
// Both tokens may not be found, since only one of them is used at any time.
std::string alternate_encryption_bootstrap_token;
if (HasPref(alternate_store_, prefs::kSyncEncryptionBootstrapToken)) {
alternate_encryption_bootstrap_token =
GetAndUnpackStringPref(alternate_store_, GetAndUnpackStringPref(alternate_store_,
prefs::kSyncEncryptionBootstrapToken); prefs::kSyncEncryptionBootstrapToken);
}
std::string alternate_keystore_encryption_bootstrap_token;
if (HasPref(alternate_store_, prefs::kSyncKeystoreEncryptionBootstrapToken)) {
alternate_keystore_encryption_bootstrap_token =
GetAndUnpackStringPref(alternate_store_,
prefs::kSyncKeystoreEncryptionBootstrapToken);
}
// Sign out of sync if the alternate profile has signed out the same user. // Sign out of sync if the alternate profile has signed out the same user.
// There is no need to schedule any more reads of the alternate profile // There is no need to schedule any more reads of the alternate profile
// cache because we only apply cached credentials for first-time sign-ins. // cache because we only apply cached credentials for first-time sign-ins.
if (ShouldSignOutOfSync(google_services_username)) { if (ShouldSignOutOfSync(alternate_google_services_username)) {
VLOG(1) << "User has signed out on the other profile. Signing out."; VLOG(1) << "User has signed out on the other profile. Signing out.";
InitiateSignOut(); InitiateSignOut();
return; return;
} }
// Extract cached sync prefs from the alternate credential cache. // Extract cached sync prefs from the alternate credential cache.
bool keep_everything_synced = bool alternate_keep_everything_synced =
GetBooleanPref(alternate_store_, prefs::kSyncKeepEverythingSynced); GetBooleanPref(alternate_store_, prefs::kSyncKeepEverythingSynced);
ProfileSyncService* service = ProfileSyncService* service =
ProfileSyncServiceFactory::GetForProfile(profile_); ProfileSyncServiceFactory::GetForProfile(profile_);
ModelTypeSet registered_types = service->GetRegisteredDataTypes(); ModelTypeSet registered_types = service->GetRegisteredDataTypes();
ModelTypeSet preferred_types; ModelTypeSet alternate_preferred_types;
for (ModelTypeSet::Iterator it = registered_types.First(); for (ModelTypeSet::Iterator it = registered_types.First();
it.Good(); it.Good();
it.Inc()) { it.Inc()) {
...@@ -216,32 +259,47 @@ void CredentialCacheService::ReadCachedCredentialsFromAlternateProfile() { ...@@ -216,32 +259,47 @@ void CredentialCacheService::ReadCachedCredentialsFromAlternateProfile() {
continue; continue;
} }
if (GetBooleanPref(alternate_store_, datatype_pref_name)) if (GetBooleanPref(alternate_store_, datatype_pref_name))
preferred_types.Put(it.Get()); alternate_preferred_types.Put(it.Get());
} }
// Reconfigure if sync settings or credentials have changed in the alternate // Reconfigure if sync settings, encryption tokens or token service
// profile, but for the same user that is signed in to the local profile. // credentials have changed in the alternate profile, but for the same user
if (MayReconfigureSync(google_services_username)) { // that is signed in to the local profile.
if (HaveSyncPrefsChanged(keep_everything_synced, preferred_types)) { if (MayReconfigureSync(alternate_google_services_username)) {
if (HaveSyncPrefsChanged(alternate_keep_everything_synced,
alternate_preferred_types)) {
VLOG(1) << "Sync prefs have changed in other profile. Reconfiguring."; VLOG(1) << "Sync prefs have changed in other profile. Reconfiguring.";
service->OnUserChoseDatatypes(keep_everything_synced, preferred_types); service->OnUserChoseDatatypes(alternate_keep_everything_synced,
alternate_preferred_types);
} }
if (HaveTokenServiceCredentialsChanged(lsid, sid)) { if (HaveSyncEncryptionTokensChanged(
alternate_encryption_bootstrap_token,
alternate_keystore_encryption_bootstrap_token)) {
VLOG(1) << "Sync encryption tokens have changed in other profile.";
sync_prefs_.SetEncryptionBootstrapToken(
alternate_encryption_bootstrap_token);
sync_prefs_.SetKeystoreEncryptionBootstrapToken(
alternate_keystore_encryption_bootstrap_token);
}
if (HaveTokenServiceCredentialsChanged(alternate_lsid, alternate_sid)) {
VLOG(1) << "Token service credentials have changed in other profile."; VLOG(1) << "Token service credentials have changed in other profile.";
UpdateTokenServiceCredentials(lsid, sid); UpdateTokenServiceCredentials(alternate_lsid, alternate_sid);
} }
} }
// Sign in if we notice new cached credentials in the alternate profile. // Sign in if we notice new cached credentials in the alternate profile.
if (ShouldSignInToSync(google_services_username, if (ShouldSignInToSync(alternate_google_services_username,
lsid, alternate_lsid,
sid, alternate_sid,
encryption_bootstrap_token)) { alternate_encryption_bootstrap_token,
InitiateSignInWithCachedCredentials(google_services_username, alternate_keystore_encryption_bootstrap_token)) {
encryption_bootstrap_token, InitiateSignInWithCachedCredentials(
keep_everything_synced, alternate_google_services_username,
preferred_types); alternate_encryption_bootstrap_token,
UpdateTokenServiceCredentials(lsid, sid); alternate_keystore_encryption_bootstrap_token,
alternate_keep_everything_synced,
alternate_preferred_types);
UpdateTokenServiceCredentials(alternate_lsid, alternate_sid);
} }
// Schedule the next read from the alternate credential cache so that we can // Schedule the next read from the alternate credential cache so that we can
...@@ -249,19 +307,7 @@ void CredentialCacheService::ReadCachedCredentialsFromAlternateProfile() { ...@@ -249,19 +307,7 @@ void CredentialCacheService::ReadCachedCredentialsFromAlternateProfile() {
ScheduleNextReadFromAlternateCredentialCache(); ScheduleNextReadFromAlternateCredentialCache();
} }
void CredentialCacheService::WriteExistingSyncPrefsToLocalCache() { void CredentialCacheService::WriteSyncPrefsToLocalCache() {
// If the local user is already signed in and there is no local credential
// cache file, write all the existing sync prefs to the local cache.
DCHECK(local_store_.get() &&
local_store_->GetReadError() ==
JsonPrefStore::PREF_READ_ERROR_NO_FILE);
SigninManager* signin = SigninManagerFactory::GetForProfile(profile_);
if (!signin->GetAuthenticatedUsername().empty() &&
!HasPref(local_store_, prefs::kGoogleServicesUsername)) {
PackAndUpdateStringPref(prefs::kGoogleServicesUsername,
signin->GetAuthenticatedUsername());
PackAndUpdateStringPref(prefs::kSyncEncryptionBootstrapToken,
sync_prefs_.GetEncryptionBootstrapToken());
UpdateBooleanPref(prefs::kSyncKeepEverythingSynced, UpdateBooleanPref(prefs::kSyncKeepEverythingSynced,
sync_prefs_.HasKeepEverythingSynced()); sync_prefs_.HasKeepEverythingSynced());
ProfileSyncService* service = ProfileSyncService* service =
...@@ -276,7 +322,6 @@ void CredentialCacheService::WriteExistingSyncPrefsToLocalCache() { ...@@ -276,7 +322,6 @@ void CredentialCacheService::WriteExistingSyncPrefsToLocalCache() {
datatype_pref_name, datatype_pref_name,
profile_->GetPrefs()->GetBoolean(datatype_pref_name.c_str())); profile_->GetPrefs()->GetBoolean(datatype_pref_name.c_str()));
} }
}
} }
void CredentialCacheService::ScheduleNextReadFromAlternateCredentialCache() { void CredentialCacheService::ScheduleNextReadFromAlternateCredentialCache() {
...@@ -364,6 +409,10 @@ void CredentialCacheService::PackAndUpdateStringPref( ...@@ -364,6 +409,10 @@ void CredentialCacheService::PackAndUpdateStringPref(
const std::string& pref_name, const std::string& pref_name,
const std::string& new_value) { const std::string& new_value) {
DCHECK(local_store_.get()); DCHECK(local_store_.get());
if (HasPref(local_store_, pref_name) &&
GetAndUnpackStringPref(local_store_, pref_name) == new_value) {
return;
}
if (!HasUserSignedOut()) { if (!HasUserSignedOut()) {
local_store_->SetValueSilently(pref_name, PackCredential(new_value)); local_store_->SetValueSilently(pref_name, PackCredential(new_value));
} else { } else {
...@@ -377,6 +426,10 @@ void CredentialCacheService::PackAndUpdateStringPref( ...@@ -377,6 +426,10 @@ void CredentialCacheService::PackAndUpdateStringPref(
void CredentialCacheService::UpdateBooleanPref(const std::string& pref_name, void CredentialCacheService::UpdateBooleanPref(const std::string& pref_name,
bool new_value) { bool new_value) {
DCHECK(local_store_.get()); DCHECK(local_store_.get());
if (HasPref(local_store_, pref_name) &&
GetBooleanPref(local_store_, pref_name) == new_value) {
return;
}
if (!HasUserSignedOut()) { if (!HasUserSignedOut()) {
local_store_->SetValueSilently(pref_name, local_store_->SetValueSilently(pref_name,
base::Value::CreateBooleanValue(new_value)); base::Value::CreateBooleanValue(new_value));
...@@ -434,15 +487,48 @@ CredentialCacheService::LocalStoreObserver::~LocalStoreObserver() { ...@@ -434,15 +487,48 @@ CredentialCacheService::LocalStoreObserver::~LocalStoreObserver() {
void CredentialCacheService::LocalStoreObserver::OnInitializationCompleted( void CredentialCacheService::LocalStoreObserver::OnInitializationCompleted(
bool succeeded) { bool succeeded) {
// If there is no existing local credential cache, write any existing sync // Note that |succeeded| will be true even if the local cache file wasn't
// prefs to the local cache. This could happen if the user was already signed // found, so long as its parent dir (the chrome profile directory) was found.
// in and restarts chrome after upgrading from an older version that didn't // If |succeeded| is false, it means that the chrome profile directory is
// support credential caching. Note that |succeeded| will be true even if // missing. In this case, there's nothing we can do other than DCHECK.
// the local cache file wasn't found, so long as its parent dir was found.
DCHECK(succeeded); DCHECK(succeeded);
if (local_store_->GetReadError() == JsonPrefStore::PREF_READ_ERROR_NO_FILE) {
service_->WriteExistingSyncPrefsToLocalCache(); // During startup, we do a precautionary write of the google username,
// encryption tokens and sync prefs to the local cache in order to recover
// from the following cases:
// 1) There is no local credential cache, but the user is signed in. This
// could happen if a signed-in user restarts chrome after upgrading from
// an older version that didn't support credential caching.
// 2) There is a local credential cache, but we missed writing sync credential
// updates to it in the past due to a crash, or due to the user exiting
// chrome in the midst of a sign in, sign out or reconfigure.
// Note: If the local credential cache was already up-to-date, the operations
// below will be no-ops, and won't change the cache's last updated time. Also,
// if the user is not signed in and there is no local credential cache, we
// don't want to create a cache with empty values.
SigninManager* signin =
SigninManagerFactory::GetForProfile(service_->profile_);
if ((local_store_->GetReadError() == JsonPrefStore::PREF_READ_ERROR_NO_FILE &&
!signin->GetAuthenticatedUsername().empty()) ||
(local_store_->GetReadError() == JsonPrefStore::PREF_READ_ERROR_NONE)) {
service_->PackAndUpdateStringPref(prefs::kGoogleServicesUsername,
signin->GetAuthenticatedUsername());
if (!service_->sync_prefs_.GetEncryptionBootstrapToken().empty()) {
service_->PackAndUpdateStringPref(
prefs::kSyncEncryptionBootstrapToken,
service_->sync_prefs_.GetEncryptionBootstrapToken());
}
if (!service_->sync_prefs_.GetKeystoreEncryptionBootstrapToken().empty()) {
service_->PackAndUpdateStringPref(
prefs::kSyncKeystoreEncryptionBootstrapToken,
service_->sync_prefs_.GetKeystoreEncryptionBootstrapToken());
}
service_->WriteSyncPrefsToLocalCache();
} }
// Now that the local credential cache is ready, start listening for events
// associated with various sync config changes.
service_->StartListeningForSyncConfigChanges();
} }
void CredentialCacheService::LocalStoreObserver::OnPrefValueChanged( void CredentialCacheService::LocalStoreObserver::OnPrefValueChanged(
...@@ -504,7 +590,9 @@ void CredentialCacheService::InitializeLocalCredentialCacheWriter() { ...@@ -504,7 +590,9 @@ void CredentialCacheService::InitializeLocalCredentialCacheWriter() {
content::BrowserThread::FILE)); content::BrowserThread::FILE));
local_store_observer_ = new LocalStoreObserver(this, local_store_); local_store_observer_ = new LocalStoreObserver(this, local_store_);
local_store_->ReadPrefsAsync(NULL); local_store_->ReadPrefsAsync(NULL);
}
void CredentialCacheService::StartListeningForSyncConfigChanges() {
// Register for notifications for google sign in and sign out. // Register for notifications for google sign in and sign out.
registrar_.Add(this, registrar_.Add(this,
chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
...@@ -513,19 +601,19 @@ void CredentialCacheService::InitializeLocalCredentialCacheWriter() { ...@@ -513,19 +601,19 @@ void CredentialCacheService::InitializeLocalCredentialCacheWriter() {
chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
content::Source<Profile>(profile_)); content::Source<Profile>(profile_));
// Register for notifications for updates to various sync settings, which are // Register for notifications for sync configuration changes that could occur
// stored in the PrefStore. // during sign in or reconfiguration.
ProfileSyncService* service =
ProfileSyncServiceFactory::GetForProfile(profile_);
registrar_.Add(this,
chrome::NOTIFICATION_SYNC_CONFIGURE_START,
content::Source<ProfileSyncService>(service));
// Register for notifications for updates to the sync encryption tokens, which
// are stored in the PrefStore.
pref_registrar_.Init(profile_->GetPrefs()); pref_registrar_.Init(profile_->GetPrefs());
pref_registrar_.Add(prefs::kSyncEncryptionBootstrapToken, this); pref_registrar_.Add(prefs::kSyncEncryptionBootstrapToken, this);
pref_registrar_.Add(prefs::kSyncKeepEverythingSynced, this); pref_registrar_.Add(prefs::kSyncKeystoreEncryptionBootstrapToken, this);
ModelTypeSet all_types = syncer::ModelTypeSet::All();
for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) {
if (it.Get() == NIGORI) // The NIGORI preference is not persisted.
continue;
pref_registrar_.Add(
browser_sync::SyncPrefs::GetPrefNameForDataType(it.Get()),
this);
}
// Register for notifications for updates to lsid and sid, which are stored in // Register for notifications for updates to lsid and sid, which are stored in
// the TokenService. // the TokenService.
...@@ -567,30 +655,46 @@ bool CredentialCacheService::HasUserSignedOut() { ...@@ -567,30 +655,46 @@ bool CredentialCacheService::HasUserSignedOut() {
void CredentialCacheService::InitiateSignInWithCachedCredentials( void CredentialCacheService::InitiateSignInWithCachedCredentials(
const std::string& google_services_username, const std::string& google_services_username,
const std::string& encryption_bootstrap_token, const std::string& encryption_bootstrap_token,
const std::string& keystore_encryption_bootstrap_token,
bool keep_everything_synced, bool keep_everything_synced,
ModelTypeSet preferred_types) { ModelTypeSet preferred_types) {
// Update the google username in the SigninManager and PrefStore. // Update the google username in the SigninManager and PrefStore. Also update
// its value in the local credential cache, since we will not send out
// NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL in this case.
ProfileSyncService* service = ProfileSyncService* service =
ProfileSyncServiceFactory::GetForProfile(profile_); ProfileSyncServiceFactory::GetForProfile(profile_);
service->signin()->SetAuthenticatedUsername(google_services_username); service->signin()->SetAuthenticatedUsername(google_services_username);
profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
google_services_username); google_services_username);
PackAndUpdateStringPref(prefs::kGoogleServicesUsername,
service->signin()->GetAuthenticatedUsername());
// Update sync encryption tokens after making sure at least one of them is
// non-empty.
DCHECK(!encryption_bootstrap_token.empty() ||
!keystore_encryption_bootstrap_token.empty());
if (!encryption_bootstrap_token.empty()) {
sync_prefs_.SetEncryptionBootstrapToken(encryption_bootstrap_token);
}
if (!keystore_encryption_bootstrap_token.empty()) {
sync_prefs_.SetKeystoreEncryptionBootstrapToken(
keystore_encryption_bootstrap_token);
}
// Update the sync preferences. // Update the sync preferences.
sync_prefs_.SetStartSuppressed(false); sync_prefs_.SetStartSuppressed(false);
sync_prefs_.SetSyncSetupCompleted(); sync_prefs_.SetSyncSetupCompleted();
sync_prefs_.SetEncryptionBootstrapToken(encryption_bootstrap_token);
sync_prefs_.SetKeepEverythingSynced(keep_everything_synced); sync_prefs_.SetKeepEverythingSynced(keep_everything_synced);
sync_prefs_.SetPreferredDataTypes(service->GetRegisteredDataTypes(), sync_prefs_.SetPreferredDataTypes(service->GetRegisteredDataTypes(),
preferred_types); preferred_types);
} }
void CredentialCacheService::UpdateTokenServiceCredentials( void CredentialCacheService::UpdateTokenServiceCredentials(
const std::string& lsid, const std::string& alternate_lsid,
const std::string& sid) { const std::string& alternate_sid) {
GaiaAuthConsumer::ClientLoginResult login_result; GaiaAuthConsumer::ClientLoginResult login_result;
login_result.lsid = lsid; login_result.lsid = alternate_lsid;
login_result.sid = sid; login_result.sid = alternate_sid;
TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
token_service->UpdateCredentials(login_result); token_service->UpdateCredentials(login_result);
DCHECK(token_service->AreCredentialsValid()); DCHECK(token_service->AreCredentialsValid());
...@@ -604,29 +708,51 @@ void CredentialCacheService::InitiateSignOut() { ...@@ -604,29 +708,51 @@ void CredentialCacheService::InitiateSignOut() {
} }
bool CredentialCacheService::HaveSyncPrefsChanged( bool CredentialCacheService::HaveSyncPrefsChanged(
bool keep_everything_synced, bool alternate_keep_everything_synced,
ModelTypeSet preferred_types) const { ModelTypeSet alternate_preferred_types) const {
ProfileSyncService* service = ProfileSyncService* service =
ProfileSyncServiceFactory::GetForProfile(profile_); ProfileSyncServiceFactory::GetForProfile(profile_);
ModelTypeSet local_preferred_types = ModelTypeSet local_preferred_types =
sync_prefs_.GetPreferredDataTypes(service->GetRegisteredDataTypes()); sync_prefs_.GetPreferredDataTypes(service->GetRegisteredDataTypes());
return return
(keep_everything_synced != sync_prefs_.HasKeepEverythingSynced()) || (alternate_keep_everything_synced !=
!Difference(preferred_types, local_preferred_types).Empty(); sync_prefs_.HasKeepEverythingSynced()) ||
!alternate_preferred_types.Equals(local_preferred_types);
}
bool CredentialCacheService::HaveSyncEncryptionTokensChanged(
const std::string& alternate_encryption_bootstrap_token,
const std::string& alternate_keystore_encryption_bootstrap_token) {
std::string local_encryption_bootstrap_token;
if (HasPref(local_store_, prefs::kSyncEncryptionBootstrapToken)) {
local_encryption_bootstrap_token =
GetAndUnpackStringPref(local_store_,
prefs::kSyncEncryptionBootstrapToken);
}
std::string local_keystore_encryption_bootstrap_token;
if (HasPref(local_store_, prefs::kSyncKeystoreEncryptionBootstrapToken)) {
local_keystore_encryption_bootstrap_token =
GetAndUnpackStringPref(local_store_,
prefs::kSyncKeystoreEncryptionBootstrapToken);
}
return (local_encryption_bootstrap_token !=
alternate_encryption_bootstrap_token) ||
(local_keystore_encryption_bootstrap_token !=
alternate_keystore_encryption_bootstrap_token);
} }
bool CredentialCacheService::HaveTokenServiceCredentialsChanged( bool CredentialCacheService::HaveTokenServiceCredentialsChanged(
const std::string& lsid, const std::string& alternate_lsid,
const std::string& sid) { const std::string& alternate_sid) {
std::string local_lsid = std::string local_lsid =
GetAndUnpackStringPref(local_store_, GaiaConstants::kGaiaLsid); GetAndUnpackStringPref(local_store_, GaiaConstants::kGaiaLsid);
std::string local_sid = std::string local_sid =
GetAndUnpackStringPref(local_store_, GaiaConstants::kGaiaSid); GetAndUnpackStringPref(local_store_, GaiaConstants::kGaiaSid);
return local_lsid != lsid || local_sid != sid; return local_lsid != alternate_lsid || local_sid != alternate_sid;
} }
bool CredentialCacheService::ShouldSignOutOfSync( bool CredentialCacheService::ShouldSignOutOfSync(
const std::string& google_services_username) { const std::string& alternate_google_services_username) {
// We must sign out of sync iff: // We must sign out of sync iff:
// 1) The user is signed in to the local profile. // 1) The user is signed in to the local profile.
// 2) The user has never signed out of the local profile in the past. // 2) The user has never signed out of the local profile in the past.
...@@ -637,14 +763,14 @@ bool CredentialCacheService::ShouldSignOutOfSync( ...@@ -637,14 +763,14 @@ bool CredentialCacheService::ShouldSignOutOfSync(
ProfileSyncServiceFactory::GetForProfile(profile_); ProfileSyncServiceFactory::GetForProfile(profile_);
return !service->signin()->GetAuthenticatedUsername().empty() && return !service->signin()->GetAuthenticatedUsername().empty() &&
!HasUserSignedOut() && !HasUserSignedOut() &&
google_services_username.empty() && alternate_google_services_username.empty() &&
!service->setup_in_progress() && !service->setup_in_progress() &&
(GetLastUpdatedTime(alternate_store_) > (GetLastUpdatedTime(alternate_store_) >
GetLastUpdatedTime(local_store_)); GetLastUpdatedTime(local_store_));
} }
bool CredentialCacheService::MayReconfigureSync( bool CredentialCacheService::MayReconfigureSync(
const std::string& google_services_username) { const std::string& alternate_google_services_username) {
// We may attempt to reconfigure sync iff: // We may attempt to reconfigure sync iff:
// 1) The user is signed in to the local profile. // 1) The user is signed in to the local profile.
// 2) The user has never signed out of the local profile in the past. // 2) The user has never signed out of the local profile in the past.
...@@ -655,7 +781,7 @@ bool CredentialCacheService::MayReconfigureSync( ...@@ -655,7 +781,7 @@ bool CredentialCacheService::MayReconfigureSync(
ProfileSyncServiceFactory::GetForProfile(profile_); ProfileSyncServiceFactory::GetForProfile(profile_);
return !service->signin()->GetAuthenticatedUsername().empty() && return !service->signin()->GetAuthenticatedUsername().empty() &&
!HasUserSignedOut() && !HasUserSignedOut() &&
(google_services_username == (alternate_google_services_username ==
service->signin()->GetAuthenticatedUsername()) && service->signin()->GetAuthenticatedUsername()) &&
!service->setup_in_progress() && !service->setup_in_progress() &&
(GetLastUpdatedTime(alternate_store_) > (GetLastUpdatedTime(alternate_store_) >
...@@ -663,10 +789,11 @@ bool CredentialCacheService::MayReconfigureSync( ...@@ -663,10 +789,11 @@ bool CredentialCacheService::MayReconfigureSync(
} }
bool CredentialCacheService::ShouldSignInToSync( bool CredentialCacheService::ShouldSignInToSync(
const std::string& google_services_username, const std::string& alternate_google_services_username,
const std::string& lsid, const std::string& alternate_lsid,
const std::string& sid, const std::string& alternate_sid,
const std::string& encryption_bootstrap_token) { const std::string& alternate_encryption_bootstrap_token,
const std::string& alternate_keystore_encryption_bootstrap_token) {
// We should sign in with cached credentials from the alternate profile iff: // We should sign in with cached credentials from the alternate profile iff:
// 1) The user is not currently signed in to the local profile. // 1) The user is not currently signed in to the local profile.
// 2) The user has never signed out of the local profile in the past. // 2) The user has never signed out of the local profile in the past.
...@@ -676,10 +803,11 @@ bool CredentialCacheService::ShouldSignInToSync( ...@@ -676,10 +803,11 @@ bool CredentialCacheService::ShouldSignInToSync(
ProfileSyncServiceFactory::GetForProfile(profile_); ProfileSyncServiceFactory::GetForProfile(profile_);
return service->signin()->GetAuthenticatedUsername().empty() && return service->signin()->GetAuthenticatedUsername().empty() &&
!HasUserSignedOut() && !HasUserSignedOut() &&
!google_services_username.empty() && !alternate_google_services_username.empty() &&
!lsid.empty() && !alternate_lsid.empty() &&
!sid.empty() && !alternate_sid.empty() &&
!encryption_bootstrap_token.empty() && !(alternate_encryption_bootstrap_token.empty() &&
alternate_keystore_encryption_bootstrap_token.empty()) &&
!service->setup_in_progress(); !service->setup_in_progress();
} }
......
...@@ -56,12 +56,9 @@ class CredentialCacheService : public ProfileKeyedService, ...@@ -56,12 +56,9 @@ class CredentialCacheService : public ProfileKeyedService,
// to the local profile if the load was successful. // to the local profile if the load was successful.
void ReadCachedCredentialsFromAlternateProfile(); void ReadCachedCredentialsFromAlternateProfile();
// Populates a new local credential cache file if the user is already signed // Writes kSyncKeepEverythingSynced and the sync preferences for individual
// in to the local profile, and there is no existing local credential cache. // datatypes to the local cache.
// Used in scenarios where a user upgraded from an older version of Chrome void WriteSyncPrefsToLocalCache();
// that didn't support credential caching. This method is a no-op if local
// sync prefs have already been written to the local cache.
void WriteExistingSyncPrefsToLocalCache();
// Resets |alternate_store_| and schedules the next read from the alternate // Resets |alternate_store_| and schedules the next read from the alternate
// credential cache. // credential cache.
...@@ -87,12 +84,15 @@ class CredentialCacheService : public ProfileKeyedService, ...@@ -87,12 +84,15 @@ class CredentialCacheService : public ProfileKeyedService,
void WriteLastUpdatedTime(); void WriteLastUpdatedTime();
// Updates the value of |pref_name| to |new_value|, unless the user has signed // Updates the value of |pref_name| to |new_value|, unless the user has signed
// out, in which case we write an empty string value to |pref_name|. // out, in which case we write an empty string value to |pref_name|. This
// method is a no-op if |new_value| is the same as the value found in the
// local cache.
void PackAndUpdateStringPref(const std::string& pref_name, void PackAndUpdateStringPref(const std::string& pref_name,
const std::string& new_value); const std::string& new_value);
// Updates the value of |pref_name| to |new_value|, unless the user has signed // Updates the value of |pref_name| to |new_value|, unless the user has signed
// out, in which case we write "false" to |pref_name|. // out, in which case we write "false" to |pref_name|. This method is a no-op
// if |new_value| is the same as the value found in the local cache.
void UpdateBooleanPref(const std::string& pref_name, bool new_value); void UpdateBooleanPref(const std::string& pref_name, bool new_value);
// Returns the time at which the credential cache represented by |store| was // Returns the time at which the credential cache represented by |store| was
...@@ -181,6 +181,10 @@ class CredentialCacheService : public ProfileKeyedService, ...@@ -181,6 +181,10 @@ class CredentialCacheService : public ProfileKeyedService,
// Initializes the JsonPrefStore object for the local profile directory. // Initializes the JsonPrefStore object for the local profile directory.
void InitializeLocalCredentialCacheWriter(); void InitializeLocalCredentialCacheWriter();
// Registers for notifications for events like sync sign in, sign out,
// (re)configuration, encryption and changes to the token service credentials.
void StartListeningForSyncConfigChanges();
// Returns true if there is an empty value for kGoogleServicesUsername in the // Returns true if there is an empty value for kGoogleServicesUsername in the
// credential cache for the local profile (indicating that the user first // credential cache for the local profile (indicating that the user first
// signed in and then signed out). Returns false if there's no value at all // signed in and then signed out). Returns false if there's no value at all
...@@ -196,59 +200,76 @@ class CredentialCacheService : public ProfileKeyedService, ...@@ -196,59 +200,76 @@ class CredentialCacheService : public ProfileKeyedService,
// Initiates sync sign in using credentials read from the alternate profile by // Initiates sync sign in using credentials read from the alternate profile by
// persisting |google_services_username|, |encryption_bootstrap_token|, // persisting |google_services_username|, |encryption_bootstrap_token|,
// |keep_everything_synced| and |preferred_types| to the local pref store, and // |keystore_encryption_bootstrap_token|, |keep_everything_synced| and
// preparing ProfileSyncService for sign in. // |preferred_types| to the local pref store, and preparing ProfileSyncService
// for sign in.
void InitiateSignInWithCachedCredentials( void InitiateSignInWithCachedCredentials(
const std::string& google_services_username, const std::string& google_services_username,
const std::string& encryption_bootstrap_token, const std::string& encryption_bootstrap_token,
const std::string& keystore_encryption_bootstrap_token,
bool keep_everything_synced, bool keep_everything_synced,
ModelTypeSet preferred_types); ModelTypeSet preferred_types);
// Updates the TokenService credentials with |lsid| and |sid| and triggers the // Updates the TokenService credentials with |alternate_lsid| and
// minting of new tokens for all Chrome services. ProfileSyncService is // |alternate_sid| and triggers the minting of new tokens for all Chrome
// automatically notified when tokens are minted, and goes on to consume the // services. ProfileSyncService is automatically notified when tokens are
// updated credentials. // minted, and goes on to consume the updated credentials.
void UpdateTokenServiceCredentials(const std::string& lsid, void UpdateTokenServiceCredentials(const std::string& alternate_lsid,
const std::string& sid); const std::string& alternate_sid);
// Initiates a sign out of sync. Called when we notice that the user has // Initiates a sign out of sync. Called when we notice that the user has
// signed out from the alternate mode by reading its credential cache. // signed out from the alternate mode by reading its credential cache.
void InitiateSignOut(); void InitiateSignOut();
// Compares the sync preferences in the local profile with values that were // Compares the sync preferences in the local profile with values that were
// read from the alternate profile -- |keep_everything_synced| and // read from the alternate profile -- |alternate_keep_everything_synced| and
// |preferred_types|. Returns true if the prefs have changed, and false // |alternate_preferred_types|. Returns true if the prefs have changed, and
// otherwise. // false otherwise.
bool HaveSyncPrefsChanged(bool keep_everything_synced, bool HaveSyncPrefsChanged(bool alternate_keep_everything_synced,
ModelTypeSet preferred_types) const; ModelTypeSet alternate_preferred_types) const;
// Compares the sync encryption tokens in the local profile with values that
// were read from the alternate profile --
// |alternate_encryption_bootstrap_token| and
// |alternate_keystore_encryption_bootstrap_token|. Returns true if the tokens
// have changed, and false otherwise.
bool HaveSyncEncryptionTokensChanged(
const std::string& alternate_encryption_bootstrap_token,
const std::string& alternate_keystore_encryption_bootstrap_token);
// Compares the token service credentials in the local profile with values // Compares the token service credentials in the local profile with values
// that were read from the alternate profile -- |lsid| and |sid|. Returns true // that were read from the alternate profile -- |alternate_lsid| and
// if the credentials have changed, and false otherwise. // |alternate_sid|. Returns true if the credentials have changed, and false
bool HaveTokenServiceCredentialsChanged(const std::string& lsid, // otherwise.
const std::string& sid); bool HaveTokenServiceCredentialsChanged(const std::string& alternate_lsid,
const std::string& alternate_sid);
// Determines if the user must be signed out of the local profile or not. // Determines if the user must be signed out of the local profile or not.
// Called when updated settings are noticed in the alternate credential cache // Called when updated settings are noticed in the alternate credential cache
// for |google_services_username|. Returns true if we should sign out, and // for |alternate_google_services_username|. Returns true if we should sign
// false if not. // out, and false if not.
bool ShouldSignOutOfSync(const std::string& google_services_username); bool ShouldSignOutOfSync(
const std::string& alternate_google_services_username);
// Determines if sync settings may be reconfigured or not. Called when // Determines if sync settings may be reconfigured or not. Called when
// updated settings are noticed in the alternate credential cache for // updated settings are noticed in the alternate credential cache for
// |google_services_username|. Returns true if we may reconfigure, and false // |alternate_google_services_username|. Returns true if we may reconfigure,
// if not. // and false if not.
bool MayReconfigureSync(const std::string& google_services_username); bool MayReconfigureSync(
const std::string& alternate_google_services_username);
// Determines if the user must be signed in to the local profile or not. // Determines if the user must be signed in to the local profile or not.
// Called when updated settings are noticed in the alternate credential cache // Called when updated settings are noticed in the alternate credential cache
// for |google_services_username|, with new values for |lsid|, |sid| and // for |alternate_google_services_username|, with new values for
// |encryption_bootstrap_token|. Returns true if we should sign in, and // |alternate_lsid|, |alternate_sid|, |alternate_encryption_bootstrap_token|
// false if not. // and |alternate_keystore_encryption_bootstrap_token|. Returns true if we
bool ShouldSignInToSync(const std::string& google_services_username, // should sign in, and false if not.
const std::string& lsid, bool ShouldSignInToSync(
const std::string& sid, const std::string& alternate_google_services_username,
const std::string& encryption_bootstrap_token); const std::string& alternate_lsid,
const std::string& alternate_sid,
const std::string& alternate_encryption_bootstrap_token,
const std::string& alternate_keystore_encryption_bootstrap_token);
// Profile for which credentials are being cached. // Profile for which credentials are being cached.
Profile* profile_; Profile* profile_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment