supervised_user_creation_controller_new.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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/supervised/supervised_user_creation_controller_new.h"
6
7#include "base/base64.h"
8#include "base/bind.h"
9#include "base/files/file_path.h"
10#include "base/files/file_util.h"
11#include "base/strings/string_number_conversions.h"
12#include "base/strings/string_util.h"
13#include "base/sys_info.h"
14#include "base/task_runner_util.h"
15#include "base/threading/sequenced_worker_pool.h"
16#include "base/values.h"
17#include "chrome/browser/chromeos/login/supervised/supervised_user_authentication.h"
18#include "chrome/browser/chromeos/login/supervised/supervised_user_constants.h"
19#include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
20#include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
21#include "chrome/browser/chromeos/profiles/profile_helper.h"
22#include "chrome/browser/lifetime/application_lifetime.h"
23#include "chrome/browser/sync/profile_sync_service.h"
24#include "chrome/browser/sync/profile_sync_service_factory.h"
25#include "chromeos/cryptohome/cryptohome_parameters.h"
26#include "chromeos/dbus/dbus_thread_manager.h"
27#include "chromeos/dbus/session_manager_client.h"
28#include "chromeos/login/auth/key.h"
29#include "chromeos/login/auth/user_context.h"
30#include "components/user_manager/user.h"
31#include "components/user_manager/user_manager.h"
32#include "content/public/browser/browser_thread.h"
33#include "content/public/browser/user_metrics.h"
34#include "crypto/random.h"
35#include "google_apis/gaia/google_service_auth_error.h"
36
37namespace chromeos {
38
39namespace {
40
41const int kUserCreationTimeoutSeconds = 30;  // 30 seconds.
42
43bool StoreSupervisedUserFiles(const std::string& token,
44                              const base::FilePath& base_path) {
45  if (!base::SysInfo::IsRunningOnChromeOS()) {
46    // If running on desktop, cryptohome stub does not create home directory.
47    base::CreateDirectory(base_path);
48  }
49  base::FilePath token_file = base_path.Append(kSupervisedUserTokenFilename);
50  int bytes = base::WriteFile(token_file, token.c_str(), token.length());
51  return bytes >= 0;
52}
53
54}  // namespace
55
56SupervisedUserCreationControllerNew::SupervisedUserCreationControllerNew(
57    SupervisedUserCreationControllerNew::StatusConsumer* consumer,
58    const std::string& manager_id)
59    : SupervisedUserCreationController(consumer),
60      stage_(STAGE_INITIAL),
61      weak_factory_(this) {
62  creation_context_.reset(
63      new SupervisedUserCreationControllerNew::UserCreationContext());
64  creation_context_->manager_id = manager_id;
65}
66
67SupervisedUserCreationControllerNew::~SupervisedUserCreationControllerNew() {}
68
69SupervisedUserCreationControllerNew::UserCreationContext::
70    UserCreationContext() {}
71
72SupervisedUserCreationControllerNew::UserCreationContext::
73    ~UserCreationContext() {}
74
75void SupervisedUserCreationControllerNew::SetManagerProfile(
76    Profile* manager_profile) {
77  creation_context_->manager_profile = manager_profile;
78}
79
80Profile* SupervisedUserCreationControllerNew::GetManagerProfile() {
81  return creation_context_->manager_profile;
82}
83
84void SupervisedUserCreationControllerNew::StartCreation(
85    const base::string16& display_name,
86    const std::string& password,
87    int avatar_index) {
88  DCHECK(creation_context_);
89  creation_context_->creation_type = NEW_USER;
90  creation_context_->display_name = display_name;
91  creation_context_->password = password;
92  creation_context_->avatar_index = avatar_index;
93  StartCreationImpl();
94}
95
96void SupervisedUserCreationControllerNew::StartImport(
97    const base::string16& display_name,
98    const std::string& password,
99    int avatar_index,
100    const std::string& sync_id,
101    const std::string& master_key) {
102  DCHECK(creation_context_);
103  creation_context_->creation_type = USER_IMPORT_OLD;
104
105  creation_context_->display_name = display_name;
106  creation_context_->password = password;
107  creation_context_->avatar_index = avatar_index;
108
109  creation_context_->sync_user_id = sync_id;
110
111  creation_context_->master_key = master_key;
112  StartCreationImpl();
113}
114
115void SupervisedUserCreationControllerNew::StartImport(
116    const base::string16& display_name,
117    int avatar_index,
118    const std::string& sync_id,
119    const std::string& master_key,
120    const base::DictionaryValue* password_data,
121    const std::string& encryption_key,
122    const std::string& signature_key) {
123  DCHECK(creation_context_);
124  creation_context_->creation_type = USER_IMPORT_NEW;
125
126  creation_context_->display_name = display_name;
127
128  creation_context_->avatar_index = avatar_index;
129
130  creation_context_->sync_user_id = sync_id;
131
132  creation_context_->master_key = master_key;
133
134  password_data->GetStringWithoutPathExpansion(
135      kEncryptedPassword, &creation_context_->salted_password);
136
137  creation_context_->signature_key = signature_key;
138  creation_context_->encryption_key = encryption_key;
139
140  creation_context_->password_data.MergeDictionary(password_data);
141
142  StartCreationImpl();
143}
144
145void SupervisedUserCreationControllerNew::StartCreationImpl() {
146  DCHECK(creation_context_);
147  DCHECK_EQ(STAGE_INITIAL, stage_);
148  VLOG(1) << "Starting supervised user creation";
149  VLOG(1) << " Phase 1 : Prepare keys";
150
151  SupervisedUserManager* manager =
152      ChromeUserManager::Get()->GetSupervisedUserManager();
153  manager->StartCreationTransaction(creation_context_->display_name);
154
155  creation_context_->local_user_id = manager->GenerateUserId();
156  if (creation_context_->creation_type == NEW_USER) {
157    creation_context_->sync_user_id =
158        SupervisedUserRegistrationUtility::GenerateNewSupervisedUserId();
159  }
160
161  manager->SetCreationTransactionUserId(creation_context_->local_user_id);
162
163  stage_ = TRANSACTION_STARTED;
164
165  manager->CreateUserRecord(creation_context_->manager_id,
166                            creation_context_->local_user_id,
167                            creation_context_->sync_user_id,
168                            creation_context_->display_name);
169
170  SupervisedUserAuthentication* authentication =
171      ChromeUserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
172
173  // When importing M35+ users we need only to store data, for all other cases
174  // we need to create some keys.
175  if (creation_context_->creation_type != USER_IMPORT_NEW) {
176    // Of all required keys old imported users have only master key.
177    // Otherwise they are the same as newly created users in terms of keys.
178    if (creation_context_->creation_type == NEW_USER) {
179      creation_context_->master_key = authentication->GenerateMasterKey();
180    }
181
182    base::DictionaryValue extra;
183    authentication->FillDataForNewUser(creation_context_->local_user_id,
184                                       creation_context_->password,
185                                       &creation_context_->password_data,
186                                       &extra);
187    creation_context_->password_data.GetStringWithoutPathExpansion(
188        kEncryptedPassword, &creation_context_->salted_password);
189    extra.GetStringWithoutPathExpansion(kPasswordEncryptionKey,
190                                        &creation_context_->encryption_key);
191    extra.GetStringWithoutPathExpansion(kPasswordSignatureKey,
192                                        &creation_context_->signature_key);
193  }
194
195  authentication->StorePasswordData(creation_context_->local_user_id,
196                                    creation_context_->password_data);
197  stage_ = KEYS_GENERATED;
198
199  VLOG(1) << " Phase 2 : Create cryptohome";
200
201  timeout_timer_.Start(
202      FROM_HERE,
203      base::TimeDelta::FromSeconds(kUserCreationTimeoutSeconds),
204      this,
205      &SupervisedUserCreationControllerNew::CreationTimedOut);
206  authenticator_ = new ExtendedAuthenticator(this);
207  UserContext user_context;
208  user_context.SetKey(Key(creation_context_->master_key));
209  authenticator_->TransformKeyIfNeeded(
210      user_context,
211      base::Bind(&SupervisedUserCreationControllerNew::OnKeyTransformedIfNeeded,
212                 weak_factory_.GetWeakPtr()));
213}
214
215void SupervisedUserCreationControllerNew::OnKeyTransformedIfNeeded(
216    const UserContext& user_context) {
217  VLOG(1) << " Phase 2.1 : Got hashed master key";
218  creation_context_->salted_master_key = user_context.GetKey()->GetSecret();
219
220  // Create home dir with two keys.
221  std::vector<cryptohome::KeyDefinition> keys;
222
223  // Main key is the master key. Just as keys for plain GAIA users, it is salted
224  // with system salt. It has all usual privileges.
225  cryptohome::KeyDefinition master_key(creation_context_->salted_master_key,
226                                       kCryptohomeMasterKeyLabel,
227                                       cryptohome::PRIV_DEFAULT);
228
229  keys.push_back(master_key);
230  authenticator_->CreateMount(
231      creation_context_->local_user_id,
232      keys,
233      base::Bind(&SupervisedUserCreationControllerNew::OnMountSuccess,
234                 weak_factory_.GetWeakPtr()));
235}
236
237void SupervisedUserCreationControllerNew::OnAuthenticationFailure(
238    ExtendedAuthenticator::AuthState error) {
239  timeout_timer_.Stop();
240  ErrorCode code = NO_ERROR;
241  switch (error) {
242    case SupervisedUserAuthenticator::NO_MOUNT:
243      code = CRYPTOHOME_NO_MOUNT;
244      break;
245    case SupervisedUserAuthenticator::FAILED_MOUNT:
246      code = CRYPTOHOME_FAILED_MOUNT;
247      break;
248    case SupervisedUserAuthenticator::FAILED_TPM:
249      code = CRYPTOHOME_FAILED_TPM;
250      break;
251    default:
252      NOTREACHED();
253  }
254  stage_ = STAGE_ERROR;
255  if (consumer_)
256    consumer_->OnCreationError(code);
257}
258
259void SupervisedUserCreationControllerNew::OnMountSuccess(
260    const std::string& mount_hash) {
261  DCHECK(creation_context_);
262  DCHECK_EQ(KEYS_GENERATED, stage_);
263  VLOG(1) << " Phase 2.2 : Created home dir with master key";
264
265  creation_context_->mount_hash = mount_hash;
266
267  // Plain text password, hashed and salted with individual salt.
268  // It can be used for mounting homedir, and can be replaced only when signed.
269  cryptohome::KeyDefinition password_key(
270      creation_context_->salted_password,
271      kCryptohomeSupervisedUserKeyLabel,
272      kCryptohomeSupervisedUserKeyPrivileges);
273  std::string encryption_key;
274  base::Base64Decode(creation_context_->encryption_key, &encryption_key);
275  password_key.authorization_data.push_back(
276      cryptohome::KeyDefinition::AuthorizationData(true /* encrypt */,
277                                                   false /* sign */,
278                                                   encryption_key));
279  std::string signature_key;
280  base::Base64Decode(creation_context_->signature_key, &signature_key);
281  password_key.authorization_data.push_back(
282      cryptohome::KeyDefinition::AuthorizationData(false /* encrypt */,
283                                                   true /* sign */,
284                                                   signature_key));
285
286  Key key(Key::KEY_TYPE_SALTED_PBKDF2_AES256_1234,
287          std::string(),  // The salt is stored elsewhere.
288          creation_context_->salted_master_key);
289  key.SetLabel(kCryptohomeMasterKeyLabel);
290  UserContext context(creation_context_->local_user_id);
291  context.SetKey(key);
292  context.SetIsUsingOAuth(false);
293
294  authenticator_->AddKey(
295      context,
296      password_key,
297      true,
298      base::Bind(&SupervisedUserCreationControllerNew::OnAddKeySuccess,
299                 weak_factory_.GetWeakPtr()));
300}
301
302void SupervisedUserCreationControllerNew::OnAddKeySuccess() {
303  DCHECK(creation_context_);
304  DCHECK_EQ(KEYS_GENERATED, stage_);
305  stage_ = CRYPTOHOME_CREATED;
306
307  VLOG(1) << " Phase 3 : Create/update user on chrome.com/manage";
308
309  ProfileSyncService* sync_service =
310      ProfileSyncServiceFactory::GetInstance()->GetForProfile(
311          creation_context_->manager_profile);
312  ProfileSyncService::SyncStatusSummary status =
313      sync_service->QuerySyncStatusSummary();
314
315  if (status == ProfileSyncService::DATATYPES_NOT_INITIALIZED)
316    consumer_->OnLongCreationWarning();
317
318  creation_context_->registration_utility =
319      SupervisedUserRegistrationUtility::Create(
320          creation_context_->manager_profile);
321
322  SupervisedUserRegistrationInfo info(creation_context_->display_name,
323                                      creation_context_->avatar_index);
324  info.master_key = creation_context_->master_key;
325  info.password_signature_key = creation_context_->signature_key;
326  info.password_encryption_key = creation_context_->encryption_key;
327
328  info.password_data.MergeDictionary(&creation_context_->password_data);
329
330  // Registration utility will update user data if user already exist.
331  creation_context_->registration_utility->Register(
332      creation_context_->sync_user_id,
333      info,
334      base::Bind(&SupervisedUserCreationControllerNew::RegistrationCallback,
335                 weak_factory_.GetWeakPtr()));
336}
337
338void SupervisedUserCreationControllerNew::RegistrationCallback(
339    const GoogleServiceAuthError& error,
340    const std::string& token) {
341  DCHECK(creation_context_);
342  DCHECK_EQ(CRYPTOHOME_CREATED, stage_);
343
344  stage_ = DASHBOARD_CREATED;
345
346  if (error.state() == GoogleServiceAuthError::NONE) {
347    creation_context_->token = token;
348
349    PostTaskAndReplyWithResult(
350        content::BrowserThread::GetBlockingPool(),
351        FROM_HERE,
352        base::Bind(&StoreSupervisedUserFiles,
353                   creation_context_->token,
354                   ProfileHelper::GetProfilePathByUserIdHash(
355                       creation_context_->mount_hash)),
356        base::Bind(
357            &SupervisedUserCreationControllerNew::OnSupervisedUserFilesStored,
358            weak_factory_.GetWeakPtr()));
359  } else {
360    stage_ = STAGE_ERROR;
361    LOG(ERROR) << "Supervised user creation failed. Error code "
362               << error.state();
363    if (consumer_)
364      consumer_->OnCreationError(CLOUD_SERVER_ERROR);
365  }
366}
367
368void SupervisedUserCreationControllerNew::OnSupervisedUserFilesStored(
369    bool success) {
370  DCHECK(creation_context_);
371  DCHECK_EQ(DASHBOARD_CREATED, stage_);
372
373  if (!success) {
374    stage_ = STAGE_ERROR;
375    if (consumer_)
376      consumer_->OnCreationError(TOKEN_WRITE_FAILED);
377    return;
378  }
379  // Assume that new token is valid. It will be automatically invalidated if
380  // sync service fails to use it.
381  user_manager::UserManager::Get()->SaveUserOAuthStatus(
382      creation_context_->local_user_id,
383      user_manager::User::OAUTH2_TOKEN_STATUS_VALID);
384
385  stage_ = TOKEN_WRITTEN;
386
387  timeout_timer_.Stop();
388  ChromeUserManager::Get()
389      ->GetSupervisedUserManager()
390      ->CommitCreationTransaction();
391  content::RecordAction(
392      base::UserMetricsAction("ManagedMode_LocallyManagedUserCreated"));
393
394  stage_ = TRANSACTION_COMMITTED;
395
396  if (consumer_)
397    consumer_->OnCreationSuccess();
398}
399
400void SupervisedUserCreationControllerNew::CreationTimedOut() {
401  LOG(ERROR) << "Supervised user creation timed out. stage = " << stage_;
402  if (consumer_)
403    consumer_->OnCreationTimeout();
404}
405
406void SupervisedUserCreationControllerNew::FinishCreation() {
407  chrome::AttemptUserExit();
408}
409
410void SupervisedUserCreationControllerNew::CancelCreation() {
411  creation_context_->registration_utility.reset();
412  chrome::AttemptUserExit();
413}
414
415std::string SupervisedUserCreationControllerNew::GetSupervisedUserId() {
416  DCHECK(creation_context_);
417  return creation_context_->local_user_id;
418}
419
420}  // namespace chromeos
421