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