Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(244)

Side by Side Diff: chrome/browser/sync/credential_cache_service_win.cc

Issue 10830239: [sync] Auto-create credential cache for users who are already signed in and go on to upgrade Chrome (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/sync/credential_cache_service_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/string_number_conversions.h" 12 #include "base/string_number_conversions.h"
13 #include "base/time.h" 13 #include "base/time.h"
14 #include "base/values.h" 14 #include "base/values.h"
15 #include "base/win/windows_version.h" 15 #include "base/win/windows_version.h"
16 #include "chrome/browser/prefs/pref_service.h" 16 #include "chrome/browser/prefs/pref_service.h"
17 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/profiles/profile_manager.h" 18 #include "chrome/browser/profiles/profile_manager.h"
19 #include "chrome/browser/signin/signin_manager.h" 19 #include "chrome/browser/signin/signin_manager.h"
20 #include "chrome/browser/signin/signin_manager_factory.h"
20 #include "chrome/browser/signin/token_service.h" 21 #include "chrome/browser/signin/token_service.h"
21 #include "chrome/browser/signin/token_service_factory.h" 22 #include "chrome/browser/signin/token_service_factory.h"
22 #include "chrome/browser/sync/glue/chrome_encryptor.h" 23 #include "chrome/browser/sync/glue/chrome_encryptor.h"
23 #include "chrome/browser/sync/profile_sync_service.h" 24 #include "chrome/browser/sync/profile_sync_service.h"
24 #include "chrome/browser/sync/profile_sync_service_factory.h" 25 #include "chrome/browser/sync/profile_sync_service_factory.h"
25 #include "chrome/common/chrome_constants.h" 26 #include "chrome/common/chrome_constants.h"
26 #include "chrome/common/chrome_notification_types.h" 27 #include "chrome/common/chrome_notification_types.h"
27 #include "chrome/common/chrome_paths_internal.h" 28 #include "chrome/common/chrome_paths_internal.h"
28 #include "chrome/common/net/gaia/gaia_auth_consumer.h" 29 #include "chrome/common/net/gaia/gaia_auth_consumer.h"
29 #include "chrome/common/net/gaia/gaia_constants.h" 30 #include "chrome/common/net/gaia/gaia_constants.h"
(...skipping 18 matching lines...) Expand all
48 using base::TimeDelta; 49 using base::TimeDelta;
49 using content::BrowserThread; 50 using content::BrowserThread;
50 51
51 CredentialCacheService::CredentialCacheService(Profile* profile) 52 CredentialCacheService::CredentialCacheService(Profile* profile)
52 : profile_(profile), 53 : profile_(profile),
53 // |profile_| is null in unit tests. 54 // |profile_| is null in unit tests.
54 sync_prefs_(profile_ ? profile_->GetPrefs() : NULL), 55 sync_prefs_(profile_ ? profile_->GetPrefs() : NULL),
55 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { 56 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
56 if (profile_) { 57 if (profile_) {
57 InitializeLocalCredentialCacheWriter(); 58 InitializeLocalCredentialCacheWriter();
58 if (ShouldLookForCachedCredentialsInAlternateProfile()) 59 // If sync is not disabled, look for credentials in the alternate profile.
60 // Note that we do want to look for credentials in the alternate profile
61 // even if the local user is signed in, so that we can detect a sign out or
62 // reconfigure originating from the alternate profile.
63 if (!sync_prefs_.IsManaged())
59 LookForCachedCredentialsInAlternateProfile(); 64 LookForCachedCredentialsInAlternateProfile();
60 } 65 }
61 } 66 }
62 67
63 CredentialCacheService::~CredentialCacheService() { 68 CredentialCacheService::~CredentialCacheService() {
64 Shutdown(); 69 Shutdown();
65 } 70 }
66 71
67 void CredentialCacheService::Shutdown() { 72 void CredentialCacheService::Shutdown() {
68 if (local_store_.get()) { 73 if (local_store_.get()) {
74 local_store_observer_.release();
69 local_store_.release(); 75 local_store_.release();
70 } 76 }
71 77
72 if (alternate_store_.get()) { 78 if (alternate_store_.get()) {
73 alternate_store_->RemoveObserver(this); 79 alternate_store_observer_.release();
74 alternate_store_.release(); 80 alternate_store_.release();
75 } 81 }
76 } 82 }
77 83
78 void CredentialCacheService::OnInitializationCompleted(bool succeeded) {
79 DCHECK(succeeded);
80 // When the local and alternate credential stores become available, begin
81 // consuming the alternate cached credentials. We must also wait for the local
82 // credential store because the credentials read from the alternate cache and
83 // applied locally must eventually get stored in the local cache.
84 if (alternate_store_.get() &&
85 alternate_store_->IsInitializationComplete() &&
86 local_store_.get() &&
87 local_store_->IsInitializationComplete()) {
88 ReadCachedCredentialsFromAlternateProfile();
89 }
90 }
91
92 void CredentialCacheService::OnPrefValueChanged(const std::string& key) {
93 // Nothing to do here, since credentials are cached silently.
94 }
95
96 void CredentialCacheService::Observe( 84 void CredentialCacheService::Observe(
97 int type, 85 int type,
98 const content::NotificationSource& source, 86 const content::NotificationSource& source,
99 const content::NotificationDetails& details) { 87 const content::NotificationDetails& details) {
100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 88 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
101 DCHECK(local_store_.get()); 89 DCHECK(local_store_.get());
102 switch (type) { 90 switch (type) {
103 case chrome::NOTIFICATION_PREF_CHANGED: { 91 case chrome::NOTIFICATION_PREF_CHANGED: {
104 const std::string pref_name = 92 const std::string pref_name =
105 *(content::Details<const std::string>(details).ptr()); 93 *(content::Details<const std::string>(details).ptr());
106 if (pref_name == prefs::kGoogleServicesUsername || 94 if (pref_name == prefs::kGoogleServicesUsername) {
107 pref_name == prefs::kSyncEncryptionBootstrapToken) { 95 SigninManager* signin = SigninManagerFactory::GetForProfile(profile_);
108 PackAndUpdateStringPref( 96 PackAndUpdateStringPref(pref_name, signin->GetAuthenticatedUsername());
109 pref_name, 97 break;
110 profile_->GetPrefs()->GetString(pref_name.c_str()));
111 } else {
112 UpdateBooleanPref(pref_name,
113 profile_->GetPrefs()->GetBoolean(pref_name.c_str()));
114 } 98 }
99 if (pref_name == prefs::kSyncEncryptionBootstrapToken) {
100 PackAndUpdateStringPref(pref_name,
101 sync_prefs_.GetEncryptionBootstrapToken());
102 break;
103 }
104 UpdateBooleanPref(pref_name,
105 profile_->GetPrefs()->GetBoolean(pref_name.c_str()));
115 break; 106 break;
116 } 107 }
117 108
118 case chrome::NOTIFICATION_TOKEN_SERVICE_CREDENTIALS_UPDATED: { 109 case chrome::NOTIFICATION_TOKEN_SERVICE_CREDENTIALS_UPDATED: {
119 const TokenService::CredentialsUpdatedDetails& token_details = 110 const TokenService::CredentialsUpdatedDetails& token_details =
120 *(content::Details<const TokenService::CredentialsUpdatedDetails>( 111 *(content::Details<const TokenService::CredentialsUpdatedDetails>(
121 details).ptr()); 112 details).ptr());
122 PackAndUpdateStringPref(GaiaConstants::kGaiaLsid, token_details.lsid()); 113 PackAndUpdateStringPref(GaiaConstants::kGaiaLsid, token_details.lsid());
123 PackAndUpdateStringPref(GaiaConstants::kGaiaSid, token_details.sid()); 114 PackAndUpdateStringPref(GaiaConstants::kGaiaSid, token_details.sid());
124 break; 115 break;
125 } 116 }
126 117
127 case chrome::NOTIFICATION_TOKENS_CLEARED: { 118 case chrome::NOTIFICATION_TOKENS_CLEARED: {
128 PackAndUpdateStringPref(GaiaConstants::kGaiaLsid, std::string()); 119 PackAndUpdateStringPref(GaiaConstants::kGaiaLsid, std::string());
129 PackAndUpdateStringPref(GaiaConstants::kGaiaSid, std::string()); 120 PackAndUpdateStringPref(GaiaConstants::kGaiaSid, std::string());
130 break; 121 break;
131 } 122 }
132 123
124 case chrome::NOTIFICATION_TOKEN_LOADING_FINISHED: {
125 // If there is no existing local credential cache, and the token service
126 // already has valid credentials as a result of the user having signed in,
127 // write them to the cache. Used in cases where the user was already
128 // signed in and then upgraded from a version of chrome that didn't
129 // support credential caching.
130 if (local_store_.get() &&
131 local_store_->IsInitializationComplete() &&
132 local_store_->GetReadError() ==
133 JsonPrefStore::PREF_READ_ERROR_NO_FILE) {
134 TokenService* token_service =
135 TokenServiceFactory::GetForProfile(profile_);
136 if (token_service->AreCredentialsValid()) {
137 GaiaAuthConsumer::ClientLoginResult credentials =
138 token_service->credentials();
139 PackAndUpdateStringPref(GaiaConstants::kGaiaLsid, credentials.lsid);
140 PackAndUpdateStringPref(GaiaConstants::kGaiaSid, credentials.sid);
141 }
142 }
143 break;
144 }
145
133 default: { 146 default: {
134 NOTREACHED(); 147 NOTREACHED();
135 break; 148 break;
136 } 149 }
137 } 150 }
138 } 151 }
139 152
153 void CredentialCacheService::ReadCachedCredentialsFromAlternateProfile() {
Raghu Simha 2012/08/09 06:10:40 ReadCachedCredentialsFromAlternateProfile() was me
154 // If the local user has signed in and signed out, we do not consume cached
155 // credentials from the alternate profile. There is nothing more to do, now or
156 // later on.
157 if (HasUserSignedOut())
158 return;
159
160 // Sanity check the alternate credential cache. If any string credentials
161 // are outright missing even though the file exists, something is awry with
162 // the alternate profile store. There is no sense in flagging an error as the
163 // problem lies in a different profile directory. There is nothing to do now.
164 // We schedule a future read from the alternate credential cache and return.
165 DCHECK(alternate_store_.get());
166 if (!HasPref(alternate_store_, prefs::kGoogleServicesUsername) ||
167 !HasPref(alternate_store_, GaiaConstants::kGaiaLsid) ||
168 !HasPref(alternate_store_, GaiaConstants::kGaiaSid) ||
169 !HasPref(alternate_store_, prefs::kSyncEncryptionBootstrapToken) ||
170 !HasPref(alternate_store_, prefs::kSyncKeepEverythingSynced)) {
171 VLOG(1) << "Could not find cached credentials in \""
172 << GetCredentialPathInAlternateProfile().value() << "\".";
173 ScheduleNextReadFromAlternateCredentialCache();
174 return;
175 }
176
177 // Extract cached credentials from the alternate credential cache.
178 std::string google_services_username =
179 GetAndUnpackStringPref(alternate_store_, prefs::kGoogleServicesUsername);
180 std::string lsid =
181 GetAndUnpackStringPref(alternate_store_, GaiaConstants::kGaiaLsid);
182 std::string sid =
183 GetAndUnpackStringPref(alternate_store_, GaiaConstants::kGaiaSid);
184 std::string encryption_bootstrap_token =
185 GetAndUnpackStringPref(alternate_store_,
186 prefs::kSyncEncryptionBootstrapToken);
187
188 // Sign out of sync if the alternate profile has signed out the same user.
189 // There is no need to schedule any more reads of the alternate profile
190 // cache because we only apply cached credentials for first-time sign-ins.
191 if (ShouldSignOutOfSync(google_services_username)) {
192 VLOG(1) << "User has signed out on the other profile. Signing out.";
193 InitiateSignOut();
194 return;
195 }
196
197 // Extract cached sync prefs from the alternate credential cache.
198 bool keep_everything_synced =
199 GetBooleanPref(alternate_store_, prefs::kSyncKeepEverythingSynced);
200 ProfileSyncService* service =
201 ProfileSyncServiceFactory::GetForProfile(profile_);
202 ModelTypeSet registered_types = service->GetRegisteredDataTypes();
203 ModelTypeSet preferred_types;
204 for (ModelTypeSet::Iterator it = registered_types.First();
205 it.Good();
206 it.Inc()) {
207 std::string datatype_pref_name =
208 browser_sync::SyncPrefs::GetPrefNameForDataType(it.Get());
209 if (!HasPref(alternate_store_, datatype_pref_name)) {
210 // If there is no cached pref for a specific data type, it means that the
211 // user originally signed in with an older version of Chrome, and then
212 // upgraded to a version with a new datatype. In such cases, we leave the
213 // default initial datatype setting as false while reading cached
214 // credentials, just like we do in SyncPrefs::RegisterPreferences.
215 VLOG(1) << "Could not find cached datatype pref for "
216 << datatype_pref_name << " in "
217 << GetCredentialPathInAlternateProfile().value() << ".";
218 continue;
219 }
220 if (GetBooleanPref(alternate_store_, datatype_pref_name))
221 preferred_types.Put(it.Get());
222 }
223
224 // Reconfigure if sync settings or credentials have changed in the alternate
225 // profile, but for the same user that is signed in to the local profile.
226 if (MayReconfigureSync(google_services_username)) {
227 if (HaveSyncPrefsChanged(keep_everything_synced, preferred_types)) {
228 VLOG(1) << "Sync prefs have changed in other profile. Reconfiguring.";
229 service->OnUserChoseDatatypes(keep_everything_synced, preferred_types);
230 }
231 if (HaveTokenServiceCredentialsChanged(lsid, sid)) {
232 VLOG(1) << "Token service credentials have changed in other profile.";
233 UpdateTokenServiceCredentials(lsid, sid);
234 }
235 }
236
237 // Sign in if we notice new cached credentials in the alternate profile.
238 if (ShouldSignInToSync(google_services_username,
239 lsid,
240 sid,
241 encryption_bootstrap_token)) {
242 InitiateSignInWithCachedCredentials(google_services_username,
243 encryption_bootstrap_token,
244 keep_everything_synced,
245 preferred_types);
246 UpdateTokenServiceCredentials(lsid, sid);
247 }
248
249 // Schedule the next read from the alternate credential cache so that we can
250 // detect future reconfigures or sign outs.
251 ScheduleNextReadFromAlternateCredentialCache();
252 }
253
254 void CredentialCacheService::WriteExistingSyncPrefsToLocalCache() {
255 // If the local user is already signed in and there is no local credential
256 // cache file, write all the existing sync prefs to the local cache.
257 DCHECK(local_store_.get() &&
258 local_store_->GetReadError() ==
259 JsonPrefStore::PREF_READ_ERROR_NO_FILE);
260 SigninManager* signin = SigninManagerFactory::GetForProfile(profile_);
261 if (!signin->GetAuthenticatedUsername().empty() &&
262 !HasPref(local_store_, prefs::kGoogleServicesUsername)) {
263 PackAndUpdateStringPref(prefs::kGoogleServicesUsername,
264 signin->GetAuthenticatedUsername());
265 PackAndUpdateStringPref(prefs::kSyncEncryptionBootstrapToken,
266 sync_prefs_.GetEncryptionBootstrapToken());
267 UpdateBooleanPref(prefs::kSyncKeepEverythingSynced,
268 sync_prefs_.HasKeepEverythingSynced());
269 ProfileSyncService* service =
270 ProfileSyncServiceFactory::GetForProfile(profile_);
271 ModelTypeSet registered_types = service->GetRegisteredDataTypes();
272 for (ModelTypeSet::Iterator it = registered_types.First();
273 it.Good();
274 it.Inc()) {
275 std::string datatype_pref_name =
276 browser_sync::SyncPrefs::GetPrefNameForDataType(it.Get());
277 UpdateBooleanPref(
278 datatype_pref_name,
279 profile_->GetPrefs()->GetBoolean(datatype_pref_name.c_str()));
280 }
281 }
282 }
283
284 void CredentialCacheService::ScheduleNextReadFromAlternateCredentialCache() {
285 // We must reinitialize |alternate_store_| here because the underlying
286 // credential file in the alternate profile might have changed, and we must
287 // re-read it afresh.
288 if (alternate_store_.get()) {
289 alternate_store_observer_.release();
290 alternate_store_.release();
291 }
292 next_read_.Reset(base::Bind(
293 &CredentialCacheService::LookForCachedCredentialsInAlternateProfile,
294 weak_factory_.GetWeakPtr()));
295 MessageLoop::current()->PostDelayedTask(
296 FROM_HERE,
297 next_read_.callback(),
298 TimeDelta::FromSeconds(kCredentialCachePollIntervalSecs));
299 }
300
140 bool CredentialCacheService::HasPref(scoped_refptr<JsonPrefStore> store, 301 bool CredentialCacheService::HasPref(scoped_refptr<JsonPrefStore> store,
141 const std::string& pref_name) { 302 const std::string& pref_name) {
142 return (store->GetValue(pref_name, NULL) == PrefStore::READ_OK); 303 return (store->GetValue(pref_name, NULL) == PrefStore::READ_OK);
143 } 304 }
144 305
145 // static 306 // static
146 base::StringValue* CredentialCacheService::PackCredential( 307 base::StringValue* CredentialCacheService::PackCredential(
147 const std::string& credential) { 308 const std::string& credential) {
148 // Do nothing for empty credentials. 309 // Do nothing for empty credentials.
149 if (credential.empty()) 310 if (credential.empty())
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 bool CredentialCacheService::GetBooleanPref( 417 bool CredentialCacheService::GetBooleanPref(
257 scoped_refptr<JsonPrefStore> store, 418 scoped_refptr<JsonPrefStore> store,
258 const std::string& pref_name) { 419 const std::string& pref_name) {
259 const base::Value* pref_value = NULL; 420 const base::Value* pref_value = NULL;
260 store->GetValue(pref_name, &pref_value); 421 store->GetValue(pref_name, &pref_value);
261 bool pref; 422 bool pref;
262 pref_value->GetAsBoolean(&pref); 423 pref_value->GetAsBoolean(&pref);
263 return pref; 424 return pref;
264 } 425 }
265 426
427 CredentialCacheService::LocalStoreObserver::LocalStoreObserver(
428 CredentialCacheService* service,
429 scoped_refptr<JsonPrefStore> local_store)
430 : service_(service),
431 local_store_(local_store) {
432 local_store_->AddObserver(this);
433 }
434
435 CredentialCacheService::LocalStoreObserver::~LocalStoreObserver() {
436 local_store_->RemoveObserver(this);
437 }
438
439 void CredentialCacheService::LocalStoreObserver::OnInitializationCompleted(
440 bool succeeded) {
441 // If there is no existing local credential cache, write any existing sync
442 // prefs to the local cache. This could happen if the user was already signed
443 // in and restarts chrome after upgrading from an older version that didn't
444 // support credential caching. Note that |succeeded| will be true even if
445 // the local cache file wasn't found, so long as its parent dir was found.
446 DCHECK(succeeded);
447 if (local_store_->GetReadError() == JsonPrefStore::PREF_READ_ERROR_NO_FILE) {
448 service_->WriteExistingSyncPrefsToLocalCache();
449 }
450 }
451
452 void CredentialCacheService::LocalStoreObserver::OnPrefValueChanged(
453 const std::string& key) {
454 // Nothing to do here, since credentials are cached silently.
455 }
456
457 CredentialCacheService::AlternateStoreObserver::AlternateStoreObserver(
458 CredentialCacheService* service,
459 scoped_refptr<JsonPrefStore> alternate_store)
460 : service_(service),
461 alternate_store_(alternate_store) {
462 alternate_store_->AddObserver(this);
463 }
464
465 CredentialCacheService::AlternateStoreObserver::~AlternateStoreObserver() {
466 alternate_store_->RemoveObserver(this);
467 }
468
469 void CredentialCacheService::AlternateStoreObserver::OnInitializationCompleted(
470 bool succeeded) {
471 // If an alternate credential cache was found, begin consuming its contents.
472 // If not, schedule a future read.
473 if (succeeded &&
474 alternate_store_->GetReadError() == JsonPrefStore::PREF_READ_ERROR_NONE) {
475 service_->ReadCachedCredentialsFromAlternateProfile();
476 } else {
477 service_->ScheduleNextReadFromAlternateCredentialCache();
478 }
479 }
480
481 void CredentialCacheService::AlternateStoreObserver::OnPrefValueChanged(
482 const std::string& key) {
483 // Nothing to do here, since credentials are cached silently.
484 }
485
266 FilePath CredentialCacheService::GetCredentialPathInCurrentProfile() const { 486 FilePath CredentialCacheService::GetCredentialPathInCurrentProfile() const {
267 // The sync credential path in the default Desktop profile is 487 // The sync credential path in the default Desktop profile is
268 // "%Appdata%\Local\Google\Chrome\User Data\Default\Sync Credentials", while 488 // "%Appdata%\Local\Google\Chrome\User Data\Default\Sync Credentials", while
269 // the sync credential path in the default Metro profile is 489 // the sync credential path in the default Metro profile is
270 // "%Appdata%\Local\Google\Chrome\Metro\User Data\Default\Sync Credentials". 490 // "%Appdata%\Local\Google\Chrome\Metro\User Data\Default\Sync Credentials".
271 DCHECK(profile_); 491 DCHECK(profile_);
272 return profile_->GetPath().Append(chrome::kSyncCredentialsFilename); 492 return profile_->GetPath().Append(chrome::kSyncCredentialsFilename);
273 } 493 }
274 494
275 FilePath CredentialCacheService::GetCredentialPathInAlternateProfile() const { 495 FilePath CredentialCacheService::GetCredentialPathInAlternateProfile() const {
276 DCHECK(profile_); 496 DCHECK(profile_);
277 FilePath alternate_user_data_dir; 497 FilePath alternate_user_data_dir;
278 chrome::GetAlternateUserDataDirectory(&alternate_user_data_dir); 498 chrome::GetAlternateUserDataDirectory(&alternate_user_data_dir);
279 FilePath alternate_default_profile_dir = 499 FilePath alternate_default_profile_dir =
280 ProfileManager::GetDefaultProfileDir(alternate_user_data_dir); 500 ProfileManager::GetDefaultProfileDir(alternate_user_data_dir);
281 return alternate_default_profile_dir.Append(chrome::kSyncCredentialsFilename); 501 return alternate_default_profile_dir.Append(chrome::kSyncCredentialsFilename);
282 } 502 }
283 503
284 bool CredentialCacheService::ShouldLookForCachedCredentialsInAlternateProfile()
285 const {
286 // We must look for credentials in the alternate profile iff the following are
287 // true:
288 // 1) Sync is not disabled by policy.
289 // 2) Sync startup is not suppressed.
290 // Note that we do want to look for credentials in the alternate profile even
291 // if the local user is signed in, so we can detect a sign out originating
292 // from the alternate profile.
293 return !sync_prefs_.IsManaged() && !sync_prefs_.IsStartSuppressed();
294 }
295
296 void CredentialCacheService::InitializeLocalCredentialCacheWriter() { 504 void CredentialCacheService::InitializeLocalCredentialCacheWriter() {
297 local_store_ = new JsonPrefStore( 505 local_store_ = new JsonPrefStore(
298 GetCredentialPathInCurrentProfile(), 506 GetCredentialPathInCurrentProfile(),
299 content::BrowserThread::GetMessageLoopProxyForThread( 507 content::BrowserThread::GetMessageLoopProxyForThread(
300 content::BrowserThread::FILE)); 508 content::BrowserThread::FILE));
301 local_store_->AddObserver(this); 509 local_store_observer_ = new LocalStoreObserver(this, local_store_);
302 local_store_->ReadPrefsAsync(NULL); 510 local_store_->ReadPrefsAsync(NULL);
303 511
304 // Register for notifications for updates to the sync credentials, which are 512 // Register for notifications for updates to the sync credentials, which are
305 // stored in the PrefStore. 513 // stored in the PrefStore.
306 pref_registrar_.Init(profile_->GetPrefs()); 514 pref_registrar_.Init(profile_->GetPrefs());
307 pref_registrar_.Add(prefs::kSyncEncryptionBootstrapToken, this); 515 pref_registrar_.Add(prefs::kSyncEncryptionBootstrapToken, this);
308 pref_registrar_.Add(prefs::kGoogleServicesUsername, this); 516 pref_registrar_.Add(prefs::kGoogleServicesUsername, this);
309 pref_registrar_.Add(prefs::kSyncKeepEverythingSynced, this); 517 pref_registrar_.Add(prefs::kSyncKeepEverythingSynced, this);
310 ModelTypeSet all_types = syncer::ModelTypeSet::All(); 518 ModelTypeSet all_types = syncer::ModelTypeSet::All();
311 for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) { 519 for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) {
312 if (it.Get() == NIGORI) // The NIGORI preference is not persisted. 520 if (it.Get() == NIGORI) // The NIGORI preference is not persisted.
313 continue; 521 continue;
314 pref_registrar_.Add( 522 pref_registrar_.Add(
315 browser_sync::SyncPrefs::GetPrefNameForDataType(it.Get()), 523 browser_sync::SyncPrefs::GetPrefNameForDataType(it.Get()),
316 this); 524 this);
317 } 525 }
318 526
319 // Register for notifications for updates to lsid and sid, which are stored in 527 // Register for notifications for updates to lsid and sid, which are stored in
320 // the TokenService. 528 // the TokenService.
321 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); 529 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
322 registrar_.Add(this, 530 registrar_.Add(this,
323 chrome::NOTIFICATION_TOKEN_SERVICE_CREDENTIALS_UPDATED, 531 chrome::NOTIFICATION_TOKEN_SERVICE_CREDENTIALS_UPDATED,
324 content::Source<TokenService>(token_service)); 532 content::Source<TokenService>(token_service));
325 registrar_.Add(this, 533 registrar_.Add(this,
326 chrome::NOTIFICATION_TOKENS_CLEARED, 534 chrome::NOTIFICATION_TOKENS_CLEARED,
327 content::Source<TokenService>(token_service)); 535 content::Source<TokenService>(token_service));
536 registrar_.Add(this,
537 chrome::NOTIFICATION_TOKEN_LOADING_FINISHED,
538 content::Source<TokenService>(token_service));
328 } 539 }
329 540
330 void CredentialCacheService::InitializeAlternateCredentialCacheReader( 541 void CredentialCacheService::LookForCachedCredentialsInAlternateProfile() {
331 bool* should_initialize) { 542 // Attempt to read cached credentials from the alternate profile. If no file
332 // If |should_initialize| is false, there was no credential cache in the 543 // exists, ReadPrefsAsync() will cause PREF_READ_ERROR_NO_FILE to be returned
333 // alternate profile directory, and there is nothing to do right now. Schedule 544 // after initialization is complete.
334 // another read in the future and exit.
335 DCHECK(should_initialize);
336 if (!*should_initialize) {
337 ScheduleNextReadFromAlternateCredentialCache();
338 return;
339 }
340
341 // A credential cache file was found in the alternate profile. Prepare to
342 // consume its contents.
343 alternate_store_ = new JsonPrefStore( 545 alternate_store_ = new JsonPrefStore(
344 GetCredentialPathInAlternateProfile(), 546 GetCredentialPathInAlternateProfile(),
345 content::BrowserThread::GetMessageLoopProxyForThread( 547 content::BrowserThread::GetMessageLoopProxyForThread(
346 content::BrowserThread::FILE)); 548 content::BrowserThread::FILE));
347 alternate_store_->AddObserver(this); 549 alternate_store_observer_ = new AlternateStoreObserver(this,
550 alternate_store_);
348 alternate_store_->ReadPrefsAsync(NULL); 551 alternate_store_->ReadPrefsAsync(NULL);
349 } 552 }
350 553
351 bool CredentialCacheService::HasUserSignedOut() { 554 bool CredentialCacheService::HasUserSignedOut() {
352 DCHECK(local_store_.get()); 555 DCHECK(local_store_.get());
353 // If HasPref() is false, the user never signed in, since there are no 556 // If HasPref() is false, the user never signed in, since there are no
354 // previously cached credentials. If the kGoogleServicesUsername pref is 557 // previously cached credentials. If the kGoogleServicesUsername pref is
355 // empty, it means that the user signed in and subsequently signed out. 558 // empty, it means that the user signed in and subsequently signed out.
356 return HasPref(local_store_, prefs::kGoogleServicesUsername) && 559 return HasPref(local_store_, prefs::kGoogleServicesUsername) &&
357 GetAndUnpackStringPref(local_store_, 560 GetAndUnpackStringPref(local_store_,
358 prefs::kGoogleServicesUsername).empty(); 561 prefs::kGoogleServicesUsername).empty();
359 } 562 }
360 563
361 namespace {
362
363 // Determines if there is a sync credential cache in the alternate profile.
364 // Returns true via |result| if there is a credential cache file in the
365 // alternate profile. Returns false otherwise.
366 void AlternateCredentialCacheExists(
367 const FilePath& credential_path_in_alternate_profile,
368 bool* result) {
369 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
370 DCHECK(result);
371 *result = file_util::PathExists(credential_path_in_alternate_profile);
372 }
373
374 } // namespace
375
376 void CredentialCacheService::LookForCachedCredentialsInAlternateProfile() {
377 bool* should_initialize = new bool(false);
378 content::BrowserThread::PostTaskAndReply(
379 content::BrowserThread::FILE,
380 FROM_HERE,
381 base::Bind(&AlternateCredentialCacheExists,
382 GetCredentialPathInAlternateProfile(),
383 should_initialize),
384 base::Bind(
385 &CredentialCacheService::InitializeAlternateCredentialCacheReader,
386 weak_factory_.GetWeakPtr(),
387 base::Owned(should_initialize)));
388 }
389
390 void CredentialCacheService::ReadCachedCredentialsFromAlternateProfile() {
391 // If the local user has signed in and signed out, we do not consume cached
392 // credentials from the alternate profile. There is nothing more to do, now or
393 // later on.
394 if (HasUserSignedOut())
395 return;
396
397 // Sanity check the alternate credential cache. If any string credentials
398 // are outright missing even though the file exists, something is awry with
399 // the alternate profile store. There is no sense in flagging an error as the
400 // problem lies in a different profile directory. There is nothing to do now.
401 // We schedule a future read from the alternate credential cache and return.
402 DCHECK(alternate_store_.get());
403 if (!HasPref(alternate_store_, prefs::kGoogleServicesUsername) ||
404 !HasPref(alternate_store_, GaiaConstants::kGaiaLsid) ||
405 !HasPref(alternate_store_, GaiaConstants::kGaiaSid) ||
406 !HasPref(alternate_store_, prefs::kSyncEncryptionBootstrapToken) ||
407 !HasPref(alternate_store_, prefs::kSyncKeepEverythingSynced)) {
408 VLOG(1) << "Could not find cached credentials in \""
409 << GetCredentialPathInAlternateProfile().value() << "\".";
410 ScheduleNextReadFromAlternateCredentialCache();
411 return;
412 }
413
414 // Extract cached credentials from the alternate credential cache.
415 std::string google_services_username =
416 GetAndUnpackStringPref(alternate_store_, prefs::kGoogleServicesUsername);
417 std::string lsid =
418 GetAndUnpackStringPref(alternate_store_, GaiaConstants::kGaiaLsid);
419 std::string sid =
420 GetAndUnpackStringPref(alternate_store_, GaiaConstants::kGaiaSid);
421 std::string encryption_bootstrap_token =
422 GetAndUnpackStringPref(alternate_store_,
423 prefs::kSyncEncryptionBootstrapToken);
424
425 // Sign out of sync if the alternate profile has signed out the same user.
426 // There is no need to schedule any more reads of the alternate profile
427 // cache because we only apply cached credentials for first-time sign-ins.
428 if (ShouldSignOutOfSync(google_services_username)) {
429 VLOG(1) << "User has signed out on the other profile. Signing out.";
430 InitiateSignOut();
431 return;
432 }
433
434 // Extract cached sync prefs from the alternate credential cache.
435 bool keep_everything_synced =
436 GetBooleanPref(alternate_store_, prefs::kSyncKeepEverythingSynced);
437 ProfileSyncService* service =
438 ProfileSyncServiceFactory::GetForProfile(profile_);
439 ModelTypeSet registered_types = service->GetRegisteredDataTypes();
440 ModelTypeSet preferred_types;
441 for (ModelTypeSet::Iterator it = registered_types.First();
442 it.Good();
443 it.Inc()) {
444 std::string datatype_pref_name =
445 browser_sync::SyncPrefs::GetPrefNameForDataType(it.Get());
446 if (!HasPref(alternate_store_, datatype_pref_name)) {
447 // If there is no cached pref for a specific data type, it means that the
448 // user originally signed in with an older version of Chrome, and then
449 // upgraded to a version with a new datatype. In such cases, we leave the
450 // default initial datatype setting as false while reading cached
451 // credentials, just like we do in SyncPrefs::RegisterPreferences.
452 VLOG(1) << "Could not find cached datatype pref for "
453 << datatype_pref_name << " in "
454 << GetCredentialPathInAlternateProfile().value() << ".";
455 continue;
456 }
457 if (GetBooleanPref(alternate_store_, datatype_pref_name))
458 preferred_types.Put(it.Get());
459 }
460
461 // Reconfigure if sync settings or credentials have changed in the alternate
462 // profile, but for the same user that is signed in to the local profile.
463 if (MayReconfigureSync(google_services_username)) {
464 if (HaveSyncPrefsChanged(keep_everything_synced, preferred_types)) {
465 VLOG(1) << "Sync prefs have changed in other profile. Reconfiguring.";
466 service->OnUserChoseDatatypes(keep_everything_synced, preferred_types);
467 }
468 if (HaveTokenServiceCredentialsChanged(lsid, sid)) {
469 VLOG(1) << "Token service credentials have changed in other profile.";
470 UpdateTokenServiceCredentials(lsid, sid);
471 }
472 }
473
474 // Sign in if we notice new cached credentials in the alternate profile.
475 if (ShouldSignInToSync(google_services_username,
476 lsid,
477 sid,
478 encryption_bootstrap_token)) {
479 InitiateSignInWithCachedCredentials(google_services_username,
480 encryption_bootstrap_token,
481 keep_everything_synced,
482 preferred_types);
483 UpdateTokenServiceCredentials(lsid, sid);
484 }
485
486 // Schedule the next read from the alternate credential cache so that we can
487 // detect future reconfigures or sign outs.
488 ScheduleNextReadFromAlternateCredentialCache();
489 }
490
491 void CredentialCacheService::InitiateSignInWithCachedCredentials( 564 void CredentialCacheService::InitiateSignInWithCachedCredentials(
492 const std::string& google_services_username, 565 const std::string& google_services_username,
493 const std::string& encryption_bootstrap_token, 566 const std::string& encryption_bootstrap_token,
494 bool keep_everything_synced, 567 bool keep_everything_synced,
495 ModelTypeSet preferred_types) { 568 ModelTypeSet preferred_types) {
496 // Update the google username in the SigninManager and PrefStore. 569 // Update the google username in the SigninManager and PrefStore.
497 ProfileSyncService* service = 570 ProfileSyncService* service =
498 ProfileSyncServiceFactory::GetForProfile(profile_); 571 ProfileSyncServiceFactory::GetForProfile(profile_);
499 service->signin()->SetAuthenticatedUsername(google_services_username); 572 service->signin()->SetAuthenticatedUsername(google_services_username);
500 profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, 573 profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
600 ProfileSyncServiceFactory::GetForProfile(profile_); 673 ProfileSyncServiceFactory::GetForProfile(profile_);
601 return service->signin()->GetAuthenticatedUsername().empty() && 674 return service->signin()->GetAuthenticatedUsername().empty() &&
602 !HasUserSignedOut() && 675 !HasUserSignedOut() &&
603 !google_services_username.empty() && 676 !google_services_username.empty() &&
604 !lsid.empty() && 677 !lsid.empty() &&
605 !sid.empty() && 678 !sid.empty() &&
606 !encryption_bootstrap_token.empty() && 679 !encryption_bootstrap_token.empty() &&
607 !service->setup_in_progress(); 680 !service->setup_in_progress();
608 } 681 }
609 682
610 void CredentialCacheService::ScheduleNextReadFromAlternateCredentialCache() {
611 // We must reinitialize |alternate_store_| here because the underlying
612 // credential file in the alternate profile might have changed, and we must
613 // re-read it afresh.
614 if (alternate_store_.get()) {
615 alternate_store_->RemoveObserver(this);
616 alternate_store_.release();
617 }
618 next_read_.Reset(base::Bind(
619 &CredentialCacheService::LookForCachedCredentialsInAlternateProfile,
620 weak_factory_.GetWeakPtr()));
621 MessageLoop::current()->PostDelayedTask(
622 FROM_HERE,
623 next_read_.callback(),
624 TimeDelta::FromSeconds(kCredentialCachePollIntervalSecs));
625 }
626
627 } // namespace syncer 683 } // namespace syncer
OLDNEW
« no previous file with comments | « chrome/browser/sync/credential_cache_service_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698