OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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. |
| 4 |
| 5 #include "components/user_manager/known_user.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "base/memory/scoped_ptr.h" |
| 9 #include "base/prefs/pref_registry_simple.h" |
| 10 #include "base/prefs/scoped_user_pref_update.h" |
| 11 #include "base/values.h" |
| 12 #include "chromeos/login/user_names.h" |
| 13 #include "components/user_manager/user_manager.h" |
| 14 #include "google_apis/gaia/gaia_auth_util.h" |
| 15 |
| 16 namespace user_manager { |
| 17 namespace known_user { |
| 18 namespace { |
| 19 |
| 20 // A vector pref of preferences of known users. All new preferences should be |
| 21 // placed in this list. |
| 22 const char kKnownUsers[] = "KnownUsers"; |
| 23 |
| 24 // Known user preferences keys (stored in Local State). |
| 25 |
| 26 // Key of canonical e-mail value. |
| 27 const char kCanonicalEmail[] = "email"; |
| 28 |
| 29 // Key of obfuscated GAIA id value. |
| 30 const char kGAIAIdKey[] = "gaia_id"; |
| 31 |
| 32 // Key of whether this user ID refers to a SAML user. |
| 33 const char kUsingSAMLKey[] = "using_saml"; |
| 34 |
| 35 // Key of Device Id. |
| 36 const char kDeviceId[] = "device_id"; |
| 37 |
| 38 // Key of GAPS cookie. |
| 39 const char kGAPSCookie[] = "gaps_cookie"; |
| 40 |
| 41 // Key of the reason for re-auth. |
| 42 const char kReauthReasonKey[] = "reauth_reason"; |
| 43 |
| 44 PrefService* GetLocalState() { |
| 45 UserManager* user_manager = UserManager::Get(); |
| 46 if (user_manager) |
| 47 return user_manager->GetLocalState(); |
| 48 |
| 49 return nullptr; |
| 50 } |
| 51 |
| 52 // Checks if values in |dict| correspond with |account_id| identity. |
| 53 bool UserMatches(const AccountId& account_id, |
| 54 const base::DictionaryValue& dict) { |
| 55 std::string value; |
| 56 |
| 57 // TODO(alemate): update code once user id is really a struct. |
| 58 bool has_gaia_id = dict.GetString(kGAIAIdKey, &value); |
| 59 if (has_gaia_id && account_id.GetGaiaId() == value) |
| 60 return true; |
| 61 |
| 62 bool has_email = dict.GetString(kCanonicalEmail, &value); |
| 63 if (has_email && account_id.GetUserEmail() == value) |
| 64 return true; |
| 65 |
| 66 return false; |
| 67 } |
| 68 |
| 69 // Fills relevant |dict| values based on |account_id|. |
| 70 void UpdateIdentity(const AccountId& account_id, base::DictionaryValue& dict) { |
| 71 dict.SetString(kCanonicalEmail, account_id.GetUserEmail()); |
| 72 } |
| 73 |
| 74 } // namespace |
| 75 |
| 76 bool FindKnownUserPrefs(const AccountId& account_id, |
| 77 const base::DictionaryValue** out_value) { |
| 78 PrefService* local_state = GetLocalState(); |
| 79 |
| 80 // Local State may not be initialized in tests. |
| 81 if (!local_state) |
| 82 return false; |
| 83 |
| 84 // UserManager is usually NULL in unit tests. |
| 85 UserManager* user_manager = UserManager::Get(); |
| 86 if (user_manager && |
| 87 user_manager->IsUserNonCryptohomeDataEphemeral(account_id)) |
| 88 return false; |
| 89 |
| 90 const base::ListValue* known_users = local_state->GetList(kKnownUsers); |
| 91 for (size_t i = 0; i < known_users->GetSize(); ++i) { |
| 92 const base::DictionaryValue* element = nullptr; |
| 93 if (known_users->GetDictionary(i, &element)) { |
| 94 if (UserMatches(account_id, *element)) { |
| 95 known_users->GetDictionary(i, out_value); |
| 96 return true; |
| 97 } |
| 98 } |
| 99 } |
| 100 return false; |
| 101 } |
| 102 |
| 103 void UpdateKnownUserPrefs(const AccountId& account_id, |
| 104 const base::DictionaryValue& values, |
| 105 bool clear) { |
| 106 PrefService* local_state = GetLocalState(); |
| 107 |
| 108 // Local State may not be initialized in tests. |
| 109 if (!local_state) |
| 110 return; |
| 111 |
| 112 // UserManager is usually NULL in unit tests. |
| 113 UserManager* user_manager = UserManager::Get(); |
| 114 if (user_manager && |
| 115 user_manager->IsUserNonCryptohomeDataEphemeral(account_id)) |
| 116 return; |
| 117 |
| 118 ListPrefUpdate update(local_state, kKnownUsers); |
| 119 for (size_t i = 0; i < update->GetSize(); ++i) { |
| 120 base::DictionaryValue* element = nullptr; |
| 121 if (update->GetDictionary(i, &element)) { |
| 122 if (UserMatches(account_id, *element)) { |
| 123 if (clear) |
| 124 element->Clear(); |
| 125 element->MergeDictionary(&values); |
| 126 UpdateIdentity(account_id, *element); |
| 127 return; |
| 128 } |
| 129 } |
| 130 } |
| 131 scoped_ptr<base::DictionaryValue> new_value(new base::DictionaryValue()); |
| 132 new_value->MergeDictionary(&values); |
| 133 UpdateIdentity(account_id, *new_value); |
| 134 update->Append(new_value.release()); |
| 135 } |
| 136 |
| 137 bool GetKnownUserStringPref(const AccountId& account_id, |
| 138 const std::string& path, |
| 139 std::string* out_value) { |
| 140 const base::DictionaryValue* user_pref_dict = nullptr; |
| 141 if (!FindKnownUserPrefs(account_id, &user_pref_dict)) |
| 142 return false; |
| 143 |
| 144 return user_pref_dict->GetString(path, out_value); |
| 145 } |
| 146 |
| 147 void SetKnownUserStringPref(const AccountId& account_id, |
| 148 const std::string& path, |
| 149 const std::string& in_value) { |
| 150 PrefService* local_state = GetLocalState(); |
| 151 |
| 152 // Local State may not be initialized in tests. |
| 153 if (!local_state) |
| 154 return; |
| 155 |
| 156 ListPrefUpdate update(local_state, kKnownUsers); |
| 157 base::DictionaryValue dict; |
| 158 dict.SetString(path, in_value); |
| 159 UpdateKnownUserPrefs(account_id, dict, false); |
| 160 } |
| 161 |
| 162 bool GetKnownUserBooleanPref(const AccountId& account_id, |
| 163 const std::string& path, |
| 164 bool* out_value) { |
| 165 const base::DictionaryValue* user_pref_dict = nullptr; |
| 166 if (!FindKnownUserPrefs(account_id, &user_pref_dict)) |
| 167 return false; |
| 168 |
| 169 return user_pref_dict->GetBoolean(path, out_value); |
| 170 } |
| 171 |
| 172 void SetKnownUserBooleanPref(const AccountId& account_id, |
| 173 const std::string& path, |
| 174 const bool in_value) { |
| 175 PrefService* local_state = GetLocalState(); |
| 176 |
| 177 // Local State may not be initialized in tests. |
| 178 if (!local_state) |
| 179 return; |
| 180 |
| 181 ListPrefUpdate update(local_state, kKnownUsers); |
| 182 base::DictionaryValue dict; |
| 183 dict.SetBoolean(path, in_value); |
| 184 UpdateKnownUserPrefs(account_id, dict, false); |
| 185 } |
| 186 |
| 187 bool GetKnownUserIntegerPref(const AccountId& account_id, |
| 188 const std::string& path, |
| 189 int* out_value) { |
| 190 const base::DictionaryValue* user_pref_dict = nullptr; |
| 191 if (!FindKnownUserPrefs(account_id, &user_pref_dict)) |
| 192 return false; |
| 193 return user_pref_dict->GetInteger(path, out_value); |
| 194 } |
| 195 |
| 196 void SetKnownUserIntegerPref(const AccountId& account_id, |
| 197 const std::string& path, |
| 198 const int in_value) { |
| 199 PrefService* local_state = GetLocalState(); |
| 200 |
| 201 // Local State may not be initialized in tests. |
| 202 if (!local_state) |
| 203 return; |
| 204 |
| 205 ListPrefUpdate update(local_state, kKnownUsers); |
| 206 base::DictionaryValue dict; |
| 207 dict.SetInteger(path, in_value); |
| 208 UpdateKnownUserPrefs(account_id, dict, false); |
| 209 } |
| 210 |
| 211 AccountId GetKnownUserAccountId(const std::string& user_email, |
| 212 const std::string& gaia_id) { |
| 213 // In tests empty accounts are possible. |
| 214 if (user_email.empty() && gaia_id.empty()) |
| 215 return EmptyAccountId(); |
| 216 |
| 217 if (user_email == chromeos::login::kStubUser) |
| 218 return chromeos::login::StubAccountId(); |
| 219 |
| 220 if (user_email == chromeos::login::kGuestUserName) |
| 221 return chromeos::login::GuestAccountId(); |
| 222 |
| 223 // We can have several users with the same gaia_id but different e-mails. |
| 224 // The opposite case is not possible. |
| 225 std::string stored_gaia_id; |
| 226 const std::string sanitized_email = |
| 227 user_email.empty() |
| 228 ? std::string() |
| 229 : gaia::CanonicalizeEmail(gaia::SanitizeEmail(user_email)); |
| 230 |
| 231 if (!sanitized_email.empty() && |
| 232 GetKnownUserStringPref(AccountId::FromUserEmail(sanitized_email), |
| 233 kGAIAIdKey, &stored_gaia_id)) { |
| 234 if (!gaia_id.empty() && gaia_id != stored_gaia_id) |
| 235 LOG(ERROR) << "User gaia id has changed. Sync will not work."; |
| 236 |
| 237 // gaia_id is associated with cryptohome. |
| 238 return AccountId::FromUserEmailGaiaId(sanitized_email, stored_gaia_id); |
| 239 } |
| 240 |
| 241 std::string stored_email; |
| 242 // GetKnownUserStringPref() returns the first user record that matches |
| 243 // given ID. So we will get the first one if there are multiples. |
| 244 if (!gaia_id.empty() && |
| 245 GetKnownUserStringPref(AccountId::FromGaiaId(gaia_id), kCanonicalEmail, |
| 246 &stored_email)) { |
| 247 return AccountId::FromUserEmailGaiaId(stored_email, gaia_id); |
| 248 } |
| 249 |
| 250 return (gaia_id.empty() |
| 251 ? AccountId::FromUserEmail(user_email) |
| 252 : AccountId::FromUserEmailGaiaId(user_email, gaia_id)); |
| 253 } |
| 254 |
| 255 void UpdateGaiaID(const AccountId& account_id, const std::string& gaia_id) { |
| 256 SetKnownUserStringPref(account_id, kGAIAIdKey, gaia_id); |
| 257 } |
| 258 |
| 259 bool FindGaiaID(const AccountId& account_id, std::string* out_value) { |
| 260 return GetKnownUserStringPref(account_id, kGAIAIdKey, out_value); |
| 261 } |
| 262 |
| 263 void SetKnownUserDeviceId(const AccountId& account_id, |
| 264 const std::string& device_id) { |
| 265 const std::string known_device_id = GetKnownUserDeviceId(account_id); |
| 266 if (!known_device_id.empty() && device_id != known_device_id) { |
| 267 NOTREACHED() << "Trying to change device ID for known user."; |
| 268 } |
| 269 SetKnownUserStringPref(account_id, kDeviceId, device_id); |
| 270 } |
| 271 |
| 272 std::string GetKnownUserDeviceId(const AccountId& account_id) { |
| 273 std::string device_id; |
| 274 if (GetKnownUserStringPref(account_id, kDeviceId, &device_id)) { |
| 275 return device_id; |
| 276 } |
| 277 return std::string(); |
| 278 } |
| 279 |
| 280 void SetKnownUserGAPSCookie(const AccountId& account_id, |
| 281 const std::string& gaps_cookie) { |
| 282 SetKnownUserStringPref(account_id, kGAPSCookie, gaps_cookie); |
| 283 } |
| 284 |
| 285 std::string GetKnownUserGAPSCookie(const AccountId& account_id) { |
| 286 std::string gaps_cookie; |
| 287 if (GetKnownUserStringPref(account_id, kGAPSCookie, &gaps_cookie)) { |
| 288 return gaps_cookie; |
| 289 } |
| 290 return std::string(); |
| 291 } |
| 292 |
| 293 void UpdateUsingSAML(const AccountId& account_id, const bool using_saml) { |
| 294 SetKnownUserBooleanPref(account_id, kUsingSAMLKey, using_saml); |
| 295 } |
| 296 |
| 297 bool FindUsingSAML(const AccountId& account_id) { |
| 298 bool using_saml; |
| 299 if (GetKnownUserBooleanPref(account_id, kUsingSAMLKey, &using_saml)) |
| 300 return using_saml; |
| 301 return false; |
| 302 } |
| 303 |
| 304 void UpdateReauthReason(const AccountId& account_id, const int reauth_reason) { |
| 305 SetKnownUserIntegerPref(account_id, kReauthReasonKey, reauth_reason); |
| 306 } |
| 307 |
| 308 bool FindReauthReason(const AccountId& account_id, int* out_value) { |
| 309 return GetKnownUserIntegerPref(account_id, kReauthReasonKey, out_value); |
| 310 } |
| 311 |
| 312 void RemoveKnownUserPrefs(const AccountId& account_id) { |
| 313 PrefService* local_state = GetLocalState(); |
| 314 |
| 315 // Local State may not be initialized in tests. |
| 316 if (!local_state) |
| 317 return; |
| 318 |
| 319 ListPrefUpdate update(local_state, kKnownUsers); |
| 320 for (size_t i = 0; i < update->GetSize(); ++i) { |
| 321 base::DictionaryValue* element = nullptr; |
| 322 if (update->GetDictionary(i, &element)) { |
| 323 if (UserMatches(account_id, *element)) { |
| 324 update->Remove(i, nullptr); |
| 325 break; |
| 326 } |
| 327 } |
| 328 } |
| 329 } |
| 330 |
| 331 void RegisterPrefs(PrefRegistrySimple* registry) { |
| 332 registry->RegisterListPref(kKnownUsers); |
| 333 } |
| 334 |
| 335 } // namespace known_user |
| 336 } // namespace user_manager |
OLD | NEW |