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

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

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

Powered by Google App Engine
This is Rietveld 408576698