1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef CHROME_BROWSER_SYNC_CREDENTIAL_CACHE_SERVICE_WIN_H_
6 #define CHROME_BROWSER_SYNC_CREDENTIAL_CACHE_SERVICE_WIN_H_
10 #include "base/basictypes.h"
11 #include "base/cancelable_callback.h"
12 #include "base/file_path.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/prefs/json_pref_store.h"
16 #include "base/prefs/public/pref_change_registrar.h"
17 #include "base/prefs/public/pref_observer.h"
18 #include "chrome/browser/profiles/profile_keyed_service.h"
19 #include "chrome/browser/sync/sync_prefs.h"
20 #include "content/public/browser/notification_observer.h"
21 #include "content/public/browser/notification_registrar.h"
32 // On Windows 8, Chrome must maintain separate profile directories for Metro and
33 // Desktop modes. When the user signs in to sync in one of the modes, we would
34 // like to automatically start sync in the other mode.
36 // This class implements a caching service for sync credentials. It listens for
37 // updates to the PrefService and TokenService that pertain to the user
38 // signing in and out of sync, and persists the credentials to a separate file
39 // in the default profile directory. It also contains functionality to bootstrap
40 // sync using credentials that were cached due to signing in on the other
42 class CredentialCacheService
: public ProfileKeyedService
,
43 public content::NotificationObserver
,
46 explicit CredentialCacheService(Profile
* profile
);
47 virtual ~CredentialCacheService();
49 // ProfileKeyedService implementation.
50 virtual void Shutdown() OVERRIDE
;
52 // content::NotificationObserver implementation.
53 virtual void Observe(int type
,
54 const content::NotificationSource
& source
,
55 const content::NotificationDetails
& details
) OVERRIDE
;
57 // PrefObserver implementation.
58 virtual void OnPreferenceChanged(PrefServiceBase
* service
,
59 const std::string
& pref_name
) OVERRIDE
;
61 // Loads cached sync credentials from the alternate profile and applies them
62 // to the local profile if the load was successful.
63 void ReadCachedCredentialsFromAlternateProfile();
65 // Writes kSyncKeepEverythingSynced and the sync preferences for individual
66 // datatypes to the local cache.
67 void WriteSyncPrefsToLocalCache();
69 // Resets |alternate_store_| and schedules the next read from the alternate
70 // credential cache in |delay_secs| seconds.
71 void ScheduleNextReadFromAlternateCredentialCache(int delay_secs
);
74 // Returns true if the credential cache represented by |store| contains a
75 // value for |pref_name|.
76 bool HasPref(scoped_refptr
<JsonPrefStore
> store
,
77 const std::string
& pref_name
);
79 // Encrypts and base 64 encodes |credential|, converts the result to a
80 // StringValue, and returns the result. Caller owns the StringValue returned.
81 static base::StringValue
* PackCredential(const std::string
& credential
);
83 // Extracts a string from the Value |packed|, base 64 decodes and decrypts it,
84 // and returns the result.
85 static std::string
UnpackCredential(const base::Value
& packed
);
87 // Writes the timestamp at which the last update was made to the credential
88 // cache of the local profile. Used to make sure that we only copy credentials
89 // from a more recently updated cache to an older cache.
90 void WriteLastCacheUpdateTime();
92 // Updates the value of |pref_name| to |new_value|, unless the user has signed
93 // out, in which case we write an empty string value to |pref_name|. This
94 // method is a no-op if |new_value| is the same as the value found in the
96 void PackAndUpdateStringPref(const std::string
& pref_name
,
97 const std::string
& new_value
);
99 // Updates the value of |pref_name| to |new_value|, unless the user has signed
100 // out, in which case we write "false" to |pref_name|. This method is a no-op
101 // if |new_value| is the same as the value found in the local cache.
102 void UpdateBooleanPref(const std::string
& pref_name
, bool new_value
);
104 // Returns the time at which the credential cache represented by |store| was
105 // last updated. Used to make sure that we only copy credentials from a more
106 // recently updated cache to an older cache.
107 base::Time
GetLastCacheUpdateTime(scoped_refptr
<JsonPrefStore
> store
);
109 // Returns true if the alternate credential cache was updated more recently
110 // than the local cache, and false if not. Used to determine whether to apply
111 // config changes detected in the alternate cache to the local cache.
112 bool AlternateCacheIsMoreRecent();
114 // Returns the string pref value contained in |store| for |pref_name|. Assumes
115 // that |store| contains a value for |pref_name|.
116 std::string
GetAndUnpackStringPref(scoped_refptr
<JsonPrefStore
> store
,
117 const std::string
& pref_name
);
119 // Returns the boolean pref value contained in |store| for |pref_name|.
120 // Assumes that |store| contains a value for |pref_name|.
121 bool GetBooleanPref(scoped_refptr
<JsonPrefStore
> store
,
122 const std::string
& pref_name
);
124 // Getter for unit tests.
125 const scoped_refptr
<JsonPrefStore
>& local_store() const {
129 // Setter for unit tests
130 void set_local_store(JsonPrefStore
* new_local_store
) {
131 local_store_
= new_local_store
;
135 // Used to track the initialization of the local credential cache.
136 class LocalStoreObserver
137 : public base::RefCounted
<LocalStoreObserver
>,
138 public PrefStore::Observer
{
140 LocalStoreObserver(CredentialCacheService
* service
,
141 scoped_refptr
<JsonPrefStore
> local_store
);
142 virtual ~LocalStoreObserver();
144 // PrefStore::Observer implementation.
145 virtual void OnInitializationCompleted(bool succeeded
) OVERRIDE
;
146 virtual void OnPrefValueChanged(const std::string
& key
) OVERRIDE
;
149 friend class base::RefCounted
<LocalStoreObserver
>;
152 CredentialCacheService
* service_
;
153 scoped_refptr
<JsonPrefStore
> local_store_
;
154 DISALLOW_COPY_AND_ASSIGN(LocalStoreObserver
);
157 // Used to track the initialization of the alternate credential cache.
158 class AlternateStoreObserver
159 : public base::RefCounted
<AlternateStoreObserver
>,
160 public PrefStore::Observer
{
162 AlternateStoreObserver(CredentialCacheService
* service
,
163 scoped_refptr
<JsonPrefStore
> alternate_store
);
164 virtual ~AlternateStoreObserver();
166 // PrefStore::Observer implementation.
167 virtual void OnInitializationCompleted(bool succeeded
) OVERRIDE
;
168 virtual void OnPrefValueChanged(const std::string
& key
) OVERRIDE
;
171 friend class base::RefCounted
<AlternateStoreObserver
>;
174 CredentialCacheService
* service_
;
175 scoped_refptr
<JsonPrefStore
> alternate_store_
;
176 DISALLOW_COPY_AND_ASSIGN(AlternateStoreObserver
);
179 // Returns the path to the sync credentials file in the current profile
181 FilePath
GetCredentialPathInCurrentProfile() const;
183 // Returns the path to the sync credentials file in the default Desktop
184 // profile directory if we are running in Metro mode, and vice versa.
185 FilePath
GetCredentialPathInAlternateProfile() const;
187 // Determines if the local credential cache writer should be initialized,
188 // based on the OS version and relevant sync preferences. Returns true if the
189 // writer must be initialized, and false if not.
190 bool ShouldInitializeLocalCredentialCacheWriter() const;
192 // Initializes the JsonPrefStore object for the local profile directory.
193 void InitializeLocalCredentialCacheWriter();
195 // Registers for notifications for events like sync sign in, sign out,
196 // (re)configuration, encryption and changes to the token service credentials.
197 void StartListeningForSyncConfigChanges();
199 // Returns true if there is an empty value for kGoogleServicesUsername in the
200 // credential cache for the local profile (indicating that the user first
201 // signed in and then signed out). Returns false if there's no value at all
202 // (indicating that the user has never signed in) or if there's a non-empty
203 // value (indicating that the user is currently signed in).
204 bool HasUserSignedOut();
206 // Asynchronously looks for a cached credential file in the alternate profile
207 // and initiates start up using cached credentials if the file was found.
208 // Called by ProfileSyncService when it tries to start up on Windows 8 and
209 // cannot auto-start.
210 void LookForCachedCredentialsInAlternateProfile();
212 // Initiates sync sign in using credentials read from the alternate profile by
213 // persisting |google_services_username|, |encryption_bootstrap_token|,
214 // |keystore_encryption_bootstrap_token|, |keep_everything_synced| and
215 // |preferred_types| to the local pref store, and preparing ProfileSyncService
217 void InitiateSignInWithCachedCredentials(
218 const std::string
& google_services_username
,
219 const std::string
& encryption_bootstrap_token
,
220 const std::string
& keystore_encryption_bootstrap_token
,
221 bool keep_everything_synced
,
222 ModelTypeSet preferred_types
);
224 // Updates the TokenService credentials with |alternate_lsid| and
225 // |alternate_sid| and triggers the minting of new tokens for all Chrome
226 // services. ProfileSyncService is automatically notified when tokens are
227 // minted, and goes on to consume the updated credentials.
228 void UpdateTokenServiceCredentials(const std::string
& alternate_lsid
,
229 const std::string
& alternate_sid
);
231 // Initiates a sign out of sync. Called when we notice that the user has
232 // signed out from the alternate mode by reading its credential cache.
233 void InitiateSignOut();
235 // Compares the sync preferences in the local profile with values that were
236 // read from the alternate profile -- |alternate_keep_everything_synced| and
237 // |alternate_preferred_types|. Returns true if the prefs have changed, and
238 // false otherwise. Note: Differences in preferred_types are ignored if the
239 // alternate and local values of keep_everything_synced are both true.
240 bool HaveSyncPrefsChanged(bool alternate_keep_everything_synced
,
241 ModelTypeSet alternate_preferred_types
) const;
243 // Compares the sync encryption tokens in the local profile with values that
244 // were read from the alternate profile --
245 // |alternate_encryption_bootstrap_token| and
246 // |alternate_keystore_encryption_bootstrap_token|. Returns true if the tokens
247 // have changed, and false otherwise.
248 bool HaveSyncEncryptionTokensChanged(
249 const std::string
& alternate_encryption_bootstrap_token
,
250 const std::string
& alternate_keystore_encryption_bootstrap_token
);
252 // Compares the token service credentials in the local profile with values
253 // that were read from the alternate profile -- |alternate_lsid| and
254 // |alternate_sid|. Returns true if the credentials have changed, and false
256 bool HaveTokenServiceCredentialsChanged(const std::string
& alternate_lsid
,
257 const std::string
& alternate_sid
);
259 // Determines if the user must be signed out of the local profile or not.
260 // Called when updated settings are noticed in the alternate credential cache
261 // for |alternate_google_services_username|. Returns true if we should sign
262 // out, and false if not.
263 bool ShouldSignOutOfSync(
264 const std::string
& alternate_google_services_username
);
266 // Determines if sync settings may be reconfigured or not. Called when
267 // updated settings are noticed in the alternate credential cache for
268 // |alternate_google_services_username|. Returns true if we may reconfigure,
270 bool MayReconfigureSync(
271 const std::string
& alternate_google_services_username
);
273 // Determines if the user must be signed in to the local profile or not.
274 // Called when updated settings are noticed in the alternate credential cache
275 // for |alternate_google_services_username|, with new values for
276 // |alternate_lsid|, |alternate_sid|, |alternate_encryption_bootstrap_token|
277 // and |alternate_keystore_encryption_bootstrap_token|. Returns true if we
278 // should sign in, and false if not.
279 bool ShouldSignInToSync(
280 const std::string
& alternate_google_services_username
,
281 const std::string
& alternate_lsid
,
282 const std::string
& alternate_sid
,
283 const std::string
& alternate_encryption_bootstrap_token
,
284 const std::string
& alternate_keystore_encryption_bootstrap_token
);
286 // Profile for which credentials are being cached.
289 // Used to access sync specific preferences in the PrefStore of |profile_|.
290 browser_sync::SyncPrefs sync_prefs_
;
292 // Used for write operations to the credential cache file in the local profile
293 // directory. This is separate from the chrome pref store. Protected so that
294 // it can be accessed by unit tests.
295 scoped_refptr
<JsonPrefStore
> local_store_
;
297 // Used to respond to the initialization of |local_store_|.
298 scoped_refptr
<LocalStoreObserver
> local_store_observer_
;
300 // Used for read operations on the credential cache file in the alternate
301 // profile directory. This is separate from the chrome pref store.
302 scoped_refptr
<JsonPrefStore
> alternate_store_
;
304 // Used to respond to the initialization of |alternate_store_|.
305 scoped_refptr
<AlternateStoreObserver
> alternate_store_observer_
;
307 // Registrar for notifications from the PrefService.
308 PrefChangeRegistrar pref_registrar_
;
310 // Registrar for notifications from the TokenService.
311 content::NotificationRegistrar registrar_
;
313 // WeakPtr implementation.
314 base::WeakPtrFactory
<CredentialCacheService
> weak_factory_
;
316 // Used to make sure that there is always at most one future read scheduled
317 // on the alternate credential cache.
318 base::CancelableClosure next_read_
;
320 DISALLOW_COPY_AND_ASSIGN(CredentialCacheService
);
323 } // namespace syncer
325 #endif // CHROME_BROWSER_SYNC_CREDENTIAL_CACHE_SERVICE_WIN_H_