1// Copyright 2014 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 "chrome/browser/chromeos/login/users/supervised_user_manager_impl.h"
6
7#include "base/files/file_path.h"
8#include "base/files/file_util.h"
9#include "base/prefs/pref_registry_simple.h"
10#include "base/prefs/pref_service.h"
11#include "base/prefs/scoped_user_pref_update.h"
12#include "base/strings/string_util.h"
13#include "base/strings/stringprintf.h"
14#include "base/strings/utf_string_conversions.h"
15#include "base/threading/sequenced_worker_pool.h"
16#include "base/values.h"
17#include "chrome/browser/browser_process.h"
18#include "chrome/browser/chromeos/login/supervised/supervised_user_authentication.h"
19#include "chrome/browser/chromeos/login/supervised/supervised_user_constants.h"
20#include "chrome/browser/chromeos/login/users/chrome_user_manager_impl.h"
21#include "chrome/browser/chromeos/profiles/profile_helper.h"
22#include "chrome/browser/supervised_user/supervised_user_service.h"
23#include "chrome/browser/supervised_user/supervised_user_service_factory.h"
24#include "chromeos/login/user_names.h"
25#include "chromeos/settings/cros_settings_names.h"
26#include "components/user_manager/user_type.h"
27#include "content/public/browser/browser_thread.h"
28#include "google_apis/gaia/gaia_auth_util.h"
29
30using content::BrowserThread;
31
32namespace {
33
34// Names for pref keys in Local State.
35// A map from supervised user local user id to sync user id.
36const char kSupervisedUserSyncId[] = "ManagedUserSyncId";
37
38// A map from supervised user id to manager user id.
39const char kSupervisedUserManagers[] = "ManagedUserManagers";
40
41// A map from supervised user id to manager display name.
42const char kSupervisedUserManagerNames[] = "ManagedUserManagerNames";
43
44// A map from supervised user id to manager display e-mail.
45const char kSupervisedUserManagerDisplayEmails[] =
46    "ManagedUserManagerDisplayEmails";
47
48// A vector pref of the supervised accounts defined on this device, that had
49// not logged in yet.
50const char kSupervisedUsersFirstRun[] = "LocallyManagedUsersFirstRun";
51
52// A pref of the next id for supervised users generation.
53const char kSupervisedUsersNextId[] = "LocallyManagedUsersNextId";
54
55// A pref of the next id for supervised users generation.
56const char kSupervisedUserCreationTransactionDisplayName[] =
57    "LocallyManagedUserCreationTransactionDisplayName";
58
59// A pref of the next id for supervised users generation.
60const char kSupervisedUserCreationTransactionUserId[] =
61    "LocallyManagedUserCreationTransactionUserId";
62
63// A map from user id to password schema id.
64const char kSupervisedUserPasswordSchema[] =
65    "SupervisedUserPasswordSchema";
66
67// A map from user id to password salt.
68const char kSupervisedUserPasswordSalt[] =
69    "SupervisedUserPasswordSalt";
70
71// A map from user id to password revision.
72const char kSupervisedUserPasswordRevision[] =
73    "SupervisedUserPasswordRevision";
74
75// A map from user id to flag indicating if password should be updated upon
76// signin.
77const char kSupervisedUserNeedPasswordUpdate[] =
78    "SupervisedUserNeedPasswordUpdate";
79
80// A map from user id to flag indicating if cryptohome does not have signature
81// key.
82const char kSupervisedUserIncompleteKey[] = "SupervisedUserHasIncompleteKey";
83
84std::string LoadSyncToken(base::FilePath profile_dir) {
85  std::string token;
86  base::FilePath token_file =
87      profile_dir.Append(chromeos::kSupervisedUserTokenFilename);
88  VLOG(1) << "Loading" << token_file.value();
89  if (!base::ReadFileToString(token_file, &token))
90    return std::string();
91  return token;
92}
93
94} // namespace
95
96namespace chromeos {
97
98const char kSchemaVersion[] = "SchemaVersion";
99const char kPasswordRevision[] = "PasswordRevision";
100const char kSalt[] = "PasswordSalt";
101const char kPasswordSignature[] = "PasswordSignature";
102const char kEncryptedPassword[] = "EncryptedPassword";
103const char kRequirePasswordUpdate[] = "RequirePasswordUpdate";
104const char kHasIncompleteKey[] = "HasIncompleteKey";
105const char kPasswordEncryptionKey[] = "password.hmac.encryption";
106const char kPasswordSignatureKey[] = "password.hmac.signature";
107
108const char kPasswordUpdateFile[] = "password.update";
109const int kMinPasswordRevision = 1;
110
111// static
112void SupervisedUserManager::RegisterPrefs(PrefRegistrySimple* registry) {
113  registry->RegisterListPref(kSupervisedUsersFirstRun);
114  registry->RegisterIntegerPref(kSupervisedUsersNextId, 0);
115  registry->RegisterStringPref(
116      kSupervisedUserCreationTransactionDisplayName, "");
117  registry->RegisterStringPref(
118      kSupervisedUserCreationTransactionUserId, "");
119  registry->RegisterDictionaryPref(kSupervisedUserSyncId);
120  registry->RegisterDictionaryPref(kSupervisedUserManagers);
121  registry->RegisterDictionaryPref(kSupervisedUserManagerNames);
122  registry->RegisterDictionaryPref(kSupervisedUserManagerDisplayEmails);
123
124  registry->RegisterDictionaryPref(kSupervisedUserPasswordSchema);
125  registry->RegisterDictionaryPref(kSupervisedUserPasswordSalt);
126  registry->RegisterDictionaryPref(kSupervisedUserPasswordRevision);
127
128  registry->RegisterDictionaryPref(kSupervisedUserNeedPasswordUpdate);
129  registry->RegisterDictionaryPref(kSupervisedUserIncompleteKey);
130}
131
132SupervisedUserManagerImpl::SupervisedUserManagerImpl(
133    ChromeUserManagerImpl* owner)
134    : owner_(owner), cros_settings_(CrosSettings::Get()) {
135  // SupervisedUserManager instance should be used only on UI thread.
136  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
137  authentication_.reset(new SupervisedUserAuthentication(this));
138}
139
140SupervisedUserManagerImpl::~SupervisedUserManagerImpl() {
141}
142
143std::string SupervisedUserManagerImpl::GenerateUserId() {
144  int counter = g_browser_process->local_state()->
145      GetInteger(kSupervisedUsersNextId);
146  std::string id;
147  bool user_exists;
148  do {
149    id = base::StringPrintf(
150        "%d@%s", counter, chromeos::login::kSupervisedUserDomain);
151    counter++;
152    user_exists = (NULL != owner_->FindUser(id));
153    DCHECK(!user_exists);
154    if (user_exists) {
155      LOG(ERROR) << "Supervised user with id " << id << " already exists.";
156    }
157  } while (user_exists);
158
159  g_browser_process->local_state()->
160      SetInteger(kSupervisedUsersNextId, counter);
161
162  g_browser_process->local_state()->CommitPendingWrite();
163  return id;
164}
165
166bool SupervisedUserManagerImpl::HasSupervisedUsers(
167      const std::string& manager_id) const {
168  const user_manager::UserList& users = owner_->GetUsers();
169  for (user_manager::UserList::const_iterator it = users.begin();
170       it != users.end();
171       ++it) {
172    if ((*it)->GetType() == user_manager::USER_TYPE_SUPERVISED) {
173      if (manager_id == GetManagerUserId((*it)->email()))
174        return true;
175    }
176  }
177  return false;
178}
179
180const user_manager::User* SupervisedUserManagerImpl::CreateUserRecord(
181    const std::string& manager_id,
182    const std::string& local_user_id,
183    const std::string& sync_user_id,
184    const base::string16& display_name) {
185  const user_manager::User* user = FindByDisplayName(display_name);
186  DCHECK(!user);
187  if (user)
188    return user;
189  const user_manager::User* manager = owner_->FindUser(manager_id);
190  CHECK(manager);
191
192  PrefService* local_state = g_browser_process->local_state();
193
194  user_manager::User* new_user =
195      user_manager::User::CreateSupervisedUser(local_user_id);
196
197  owner_->AddUserRecord(new_user);
198
199  ListPrefUpdate prefs_new_users_update(local_state,
200                                        kSupervisedUsersFirstRun);
201  DictionaryPrefUpdate sync_id_update(local_state, kSupervisedUserSyncId);
202  DictionaryPrefUpdate manager_update(local_state, kSupervisedUserManagers);
203  DictionaryPrefUpdate manager_name_update(local_state,
204                                           kSupervisedUserManagerNames);
205  DictionaryPrefUpdate manager_email_update(
206      local_state,
207      kSupervisedUserManagerDisplayEmails);
208
209  prefs_new_users_update->Insert(0, new base::StringValue(local_user_id));
210
211  sync_id_update->SetWithoutPathExpansion(local_user_id,
212      new base::StringValue(sync_user_id));
213  manager_update->SetWithoutPathExpansion(local_user_id,
214      new base::StringValue(manager->email()));
215  manager_name_update->SetWithoutPathExpansion(local_user_id,
216      new base::StringValue(manager->GetDisplayName()));
217  manager_email_update->SetWithoutPathExpansion(local_user_id,
218      new base::StringValue(manager->display_email()));
219
220  owner_->SaveUserDisplayName(local_user_id, display_name);
221
222  g_browser_process->local_state()->CommitPendingWrite();
223  return new_user;
224}
225
226std::string SupervisedUserManagerImpl::GetUserSyncId(const std::string& user_id)
227    const {
228  std::string result;
229  GetUserStringValue(user_id, kSupervisedUserSyncId, &result);
230  return result;
231}
232
233base::string16 SupervisedUserManagerImpl::GetManagerDisplayName(
234    const std::string& user_id) const {
235  PrefService* local_state = g_browser_process->local_state();
236  const base::DictionaryValue* manager_names =
237      local_state->GetDictionary(kSupervisedUserManagerNames);
238  base::string16 result;
239  if (manager_names->GetStringWithoutPathExpansion(user_id, &result) &&
240      !result.empty())
241    return result;
242  return base::UTF8ToUTF16(GetManagerDisplayEmail(user_id));
243}
244
245std::string SupervisedUserManagerImpl::GetManagerUserId(
246      const std::string& user_id) const {
247  std::string result;
248  GetUserStringValue(user_id, kSupervisedUserManagers, &result);
249  return result;
250}
251
252std::string SupervisedUserManagerImpl::GetManagerDisplayEmail(
253      const std::string& user_id) const {
254  std::string result;
255  if (GetUserStringValue(user_id,
256                         kSupervisedUserManagerDisplayEmails,
257                         &result) &&
258      !result.empty())
259    return result;
260  return GetManagerUserId(user_id);
261}
262
263void SupervisedUserManagerImpl::GetPasswordInformation(
264    const std::string& user_id,
265    base::DictionaryValue* result) {
266  int value;
267  if (GetUserIntegerValue(user_id, kSupervisedUserPasswordSchema, &value))
268    result->SetIntegerWithoutPathExpansion(kSchemaVersion, value);
269  if (GetUserIntegerValue(user_id, kSupervisedUserPasswordRevision, &value))
270    result->SetIntegerWithoutPathExpansion(kPasswordRevision, value);
271
272  bool flag;
273  if (GetUserBooleanValue(user_id, kSupervisedUserNeedPasswordUpdate, &flag))
274    result->SetBooleanWithoutPathExpansion(kRequirePasswordUpdate, flag);
275  if (GetUserBooleanValue(user_id, kSupervisedUserIncompleteKey, &flag))
276    result->SetBooleanWithoutPathExpansion(kHasIncompleteKey, flag);
277
278  std::string salt;
279  if (GetUserStringValue(user_id, kSupervisedUserPasswordSalt, &salt))
280    result->SetStringWithoutPathExpansion(kSalt, salt);
281}
282
283void SupervisedUserManagerImpl::SetPasswordInformation(
284      const std::string& user_id,
285      const base::DictionaryValue* password_info) {
286  int value;
287  if (password_info->GetIntegerWithoutPathExpansion(kSchemaVersion, &value))
288    SetUserIntegerValue(user_id, kSupervisedUserPasswordSchema, value);
289  if (password_info->GetIntegerWithoutPathExpansion(kPasswordRevision, &value))
290    SetUserIntegerValue(user_id, kSupervisedUserPasswordRevision, value);
291
292  bool flag;
293  if (password_info->GetBooleanWithoutPathExpansion(kRequirePasswordUpdate,
294                                                    &flag)) {
295    SetUserBooleanValue(user_id, kSupervisedUserNeedPasswordUpdate, flag);
296  }
297  if (password_info->GetBooleanWithoutPathExpansion(kHasIncompleteKey, &flag))
298    SetUserBooleanValue(user_id, kSupervisedUserIncompleteKey, flag);
299
300  std::string salt;
301  if (password_info->GetStringWithoutPathExpansion(kSalt, &salt))
302    SetUserStringValue(user_id, kSupervisedUserPasswordSalt, salt);
303  g_browser_process->local_state()->CommitPendingWrite();
304}
305
306bool SupervisedUserManagerImpl::GetUserStringValue(
307    const std::string& user_id,
308    const char* key,
309    std::string* out_value) const {
310  PrefService* local_state = g_browser_process->local_state();
311  const base::DictionaryValue* dictionary = local_state->GetDictionary(key);
312  return dictionary->GetStringWithoutPathExpansion(user_id, out_value);
313}
314
315bool SupervisedUserManagerImpl::GetUserIntegerValue(
316    const std::string& user_id,
317    const char* key,
318    int* out_value) const {
319  PrefService* local_state = g_browser_process->local_state();
320  const base::DictionaryValue* dictionary = local_state->GetDictionary(key);
321  return dictionary->GetIntegerWithoutPathExpansion(user_id, out_value);
322}
323
324bool SupervisedUserManagerImpl::GetUserBooleanValue(const std::string& user_id,
325                                                    const char* key,
326                                                    bool* out_value) const {
327  PrefService* local_state = g_browser_process->local_state();
328  const base::DictionaryValue* dictionary = local_state->GetDictionary(key);
329  return dictionary->GetBooleanWithoutPathExpansion(user_id, out_value);
330}
331
332void SupervisedUserManagerImpl::SetUserStringValue(
333    const std::string& user_id,
334    const char* key,
335    const std::string& value) {
336  PrefService* local_state = g_browser_process->local_state();
337  DictionaryPrefUpdate update(local_state, key);
338  update->SetStringWithoutPathExpansion(user_id, value);
339}
340
341void SupervisedUserManagerImpl::SetUserIntegerValue(
342    const std::string& user_id,
343    const char* key,
344    const int value) {
345  PrefService* local_state = g_browser_process->local_state();
346  DictionaryPrefUpdate update(local_state, key);
347  update->SetIntegerWithoutPathExpansion(user_id, value);
348}
349
350void SupervisedUserManagerImpl::SetUserBooleanValue(const std::string& user_id,
351                                                    const char* key,
352                                                    const bool value) {
353  PrefService* local_state = g_browser_process->local_state();
354  DictionaryPrefUpdate update(local_state, key);
355  update->SetBooleanWithoutPathExpansion(user_id, value);
356}
357
358const user_manager::User* SupervisedUserManagerImpl::FindByDisplayName(
359    const base::string16& display_name) const {
360  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
361  const user_manager::UserList& users = owner_->GetUsers();
362  for (user_manager::UserList::const_iterator it = users.begin();
363       it != users.end();
364       ++it) {
365    if (((*it)->GetType() == user_manager::USER_TYPE_SUPERVISED) &&
366        ((*it)->display_name() == display_name)) {
367      return *it;
368    }
369  }
370  return NULL;
371}
372
373const user_manager::User* SupervisedUserManagerImpl::FindBySyncId(
374    const std::string& sync_id) const {
375  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
376  const user_manager::UserList& users = owner_->GetUsers();
377  for (user_manager::UserList::const_iterator it = users.begin();
378       it != users.end();
379       ++it) {
380    if (((*it)->GetType() == user_manager::USER_TYPE_SUPERVISED) &&
381        (GetUserSyncId((*it)->email()) == sync_id)) {
382      return *it;
383    }
384  }
385  return NULL;
386}
387
388void SupervisedUserManagerImpl::StartCreationTransaction(
389      const base::string16& display_name) {
390  g_browser_process->local_state()->
391      SetString(kSupervisedUserCreationTransactionDisplayName,
392                base::UTF16ToASCII(display_name));
393  g_browser_process->local_state()->CommitPendingWrite();
394}
395
396void SupervisedUserManagerImpl::SetCreationTransactionUserId(
397      const std::string& email) {
398  g_browser_process->local_state()->
399      SetString(kSupervisedUserCreationTransactionUserId,
400                email);
401  g_browser_process->local_state()->CommitPendingWrite();
402}
403
404void SupervisedUserManagerImpl::CommitCreationTransaction() {
405  g_browser_process->local_state()->
406      ClearPref(kSupervisedUserCreationTransactionDisplayName);
407  g_browser_process->local_state()->
408      ClearPref(kSupervisedUserCreationTransactionUserId);
409  g_browser_process->local_state()->CommitPendingWrite();
410}
411
412bool SupervisedUserManagerImpl::HasFailedUserCreationTransaction() {
413  return !(g_browser_process->local_state()->
414               GetString(kSupervisedUserCreationTransactionDisplayName).
415                   empty());
416}
417
418void SupervisedUserManagerImpl::RollbackUserCreationTransaction() {
419  PrefService* prefs = g_browser_process->local_state();
420
421  std::string display_name = prefs->
422      GetString(kSupervisedUserCreationTransactionDisplayName);
423  std::string user_id = prefs->
424      GetString(kSupervisedUserCreationTransactionUserId);
425
426  LOG(WARNING) << "Cleaning up transaction for "
427               << display_name << "/" << user_id;
428
429  if (user_id.empty()) {
430    // Not much to do - just remove transaction.
431    prefs->ClearPref(kSupervisedUserCreationTransactionDisplayName);
432    prefs->CommitPendingWrite();
433    return;
434  }
435
436  if (gaia::ExtractDomainName(user_id) !=
437      chromeos::login::kSupervisedUserDomain) {
438    LOG(WARNING) << "Clean up transaction for  non-supervised user found :"
439                 << user_id << ", will not remove data";
440    prefs->ClearPref(kSupervisedUserCreationTransactionDisplayName);
441    prefs->ClearPref(kSupervisedUserCreationTransactionUserId);
442    prefs->CommitPendingWrite();
443    return;
444  }
445  owner_->RemoveNonOwnerUserInternal(user_id, NULL);
446
447  prefs->ClearPref(kSupervisedUserCreationTransactionDisplayName);
448  prefs->ClearPref(kSupervisedUserCreationTransactionUserId);
449  prefs->CommitPendingWrite();
450}
451
452void SupervisedUserManagerImpl::RemoveNonCryptohomeData(
453    const std::string& user_id) {
454  PrefService* prefs = g_browser_process->local_state();
455  ListPrefUpdate prefs_new_users_update(prefs, kSupervisedUsersFirstRun);
456  prefs_new_users_update->Remove(base::StringValue(user_id), NULL);
457
458  CleanPref(user_id, kSupervisedUserSyncId);
459  CleanPref(user_id, kSupervisedUserManagers);
460  CleanPref(user_id, kSupervisedUserManagerNames);
461  CleanPref(user_id, kSupervisedUserManagerDisplayEmails);
462  CleanPref(user_id, kSupervisedUserPasswordSalt);
463  CleanPref(user_id, kSupervisedUserPasswordSchema);
464  CleanPref(user_id, kSupervisedUserPasswordRevision);
465  CleanPref(user_id, kSupervisedUserNeedPasswordUpdate);
466  CleanPref(user_id, kSupervisedUserIncompleteKey);
467}
468
469void SupervisedUserManagerImpl::CleanPref(const std::string& user_id,
470                                          const char* key) {
471  PrefService* prefs = g_browser_process->local_state();
472  DictionaryPrefUpdate dict_update(prefs, key);
473  dict_update->RemoveWithoutPathExpansion(user_id, NULL);
474}
475
476bool SupervisedUserManagerImpl::CheckForFirstRun(const std::string& user_id) {
477  ListPrefUpdate prefs_new_users_update(g_browser_process->local_state(),
478                                        kSupervisedUsersFirstRun);
479  return prefs_new_users_update->Remove(base::StringValue(user_id), NULL);
480}
481
482void SupervisedUserManagerImpl::UpdateManagerName(const std::string& manager_id,
483    const base::string16& new_display_name) {
484  PrefService* local_state = g_browser_process->local_state();
485
486  const base::DictionaryValue* manager_ids =
487      local_state->GetDictionary(kSupervisedUserManagers);
488
489  DictionaryPrefUpdate manager_name_update(local_state,
490                                           kSupervisedUserManagerNames);
491  for (base::DictionaryValue::Iterator it(*manager_ids); !it.IsAtEnd();
492      it.Advance()) {
493    std::string user_id;
494    bool has_manager_id = it.value().GetAsString(&user_id);
495    DCHECK(has_manager_id);
496    if (user_id == manager_id) {
497      manager_name_update->SetWithoutPathExpansion(
498          it.key(),
499          new base::StringValue(new_display_name));
500    }
501  }
502}
503
504SupervisedUserAuthentication* SupervisedUserManagerImpl::GetAuthentication() {
505  return authentication_.get();
506}
507
508void SupervisedUserManagerImpl::LoadSupervisedUserToken(
509    Profile* profile,
510    const LoadTokenCallback& callback) {
511  // TODO(antrim): use profile->GetPath() once we sure it is safe.
512  base::FilePath profile_dir = ProfileHelper::GetProfilePathByUserIdHash(
513      ProfileHelper::Get()->GetUserByProfile(profile)->username_hash());
514  PostTaskAndReplyWithResult(
515      content::BrowserThread::GetBlockingPool(),
516      FROM_HERE,
517      base::Bind(&LoadSyncToken, profile_dir),
518      callback);
519}
520
521void SupervisedUserManagerImpl::ConfigureSyncWithToken(
522    Profile* profile,
523    const std::string& token) {
524  if (!token.empty())
525    SupervisedUserServiceFactory::GetForProfile(profile)->InitSync(token);
526}
527
528}  // namespace chromeos
529