supervised_user_creation_controller_new.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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/file_util.h"
10#include "base/files/file_path.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/auth/mount_manager.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.h"
21#include "chrome/browser/chromeos/login/users/supervised_user_manager.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  base::Base64Decode(creation_context_->encryption_key,
274                     &password_key.encryption_key);
275  base::Base64Decode(creation_context_->signature_key,
276                     &password_key.signature_key);
277
278  Key key(Key::KEY_TYPE_SALTED_PBKDF2_AES256_1234,
279          std::string(),  // The salt is stored elsewhere.
280          creation_context_->salted_master_key);
281  key.SetLabel(kCryptohomeMasterKeyLabel);
282  UserContext context(creation_context_->local_user_id);
283  context.SetKey(key);
284  context.SetIsUsingOAuth(false);
285
286  authenticator_->AddKey(
287      context,
288      password_key,
289      true,
290      base::Bind(&SupervisedUserCreationControllerNew::OnAddKeySuccess,
291                 weak_factory_.GetWeakPtr()));
292}
293
294void SupervisedUserCreationControllerNew::OnAddKeySuccess() {
295  DCHECK(creation_context_);
296  DCHECK_EQ(KEYS_GENERATED, stage_);
297  stage_ = CRYPTOHOME_CREATED;
298
299  VLOG(1) << " Phase 3 : Create/update user on chrome.com/manage";
300
301  ProfileSyncService* sync_service =
302      ProfileSyncServiceFactory::GetInstance()->GetForProfile(
303          creation_context_->manager_profile);
304  ProfileSyncService::SyncStatusSummary status =
305      sync_service->QuerySyncStatusSummary();
306
307  if (status == ProfileSyncService::DATATYPES_NOT_INITIALIZED)
308    consumer_->OnLongCreationWarning();
309
310  creation_context_->registration_utility =
311      SupervisedUserRegistrationUtility::Create(
312          creation_context_->manager_profile);
313
314  SupervisedUserRegistrationInfo info(creation_context_->display_name,
315                                      creation_context_->avatar_index);
316  info.master_key = creation_context_->master_key;
317  info.password_signature_key = creation_context_->signature_key;
318  info.password_encryption_key = creation_context_->encryption_key;
319
320  info.password_data.MergeDictionary(&creation_context_->password_data);
321
322  // Registration utility will update user data if user already exist.
323  creation_context_->registration_utility->Register(
324      creation_context_->sync_user_id,
325      info,
326      base::Bind(&SupervisedUserCreationControllerNew::RegistrationCallback,
327                 weak_factory_.GetWeakPtr()));
328}
329
330void SupervisedUserCreationControllerNew::RegistrationCallback(
331    const GoogleServiceAuthError& error,
332    const std::string& token) {
333  DCHECK(creation_context_);
334  DCHECK_EQ(CRYPTOHOME_CREATED, stage_);
335
336  stage_ = DASHBOARD_CREATED;
337
338  if (error.state() == GoogleServiceAuthError::NONE) {
339    creation_context_->token = token;
340
341    PostTaskAndReplyWithResult(
342        content::BrowserThread::GetBlockingPool(),
343        FROM_HERE,
344        base::Bind(&StoreSupervisedUserFiles,
345                   creation_context_->token,
346                   MountManager::GetHomeDir(creation_context_->mount_hash)),
347        base::Bind(&SupervisedUserCreationControllerNew::
348                        OnSupervisedUserFilesStored,
349                   weak_factory_.GetWeakPtr()));
350  } else {
351    stage_ = STAGE_ERROR;
352    LOG(ERROR) << "Supervised user creation failed. Error code "
353               << error.state();
354    if (consumer_)
355      consumer_->OnCreationError(CLOUD_SERVER_ERROR);
356  }
357}
358
359void SupervisedUserCreationControllerNew::OnSupervisedUserFilesStored(
360    bool success) {
361  DCHECK(creation_context_);
362  DCHECK_EQ(DASHBOARD_CREATED, stage_);
363
364  if (!success) {
365    stage_ = STAGE_ERROR;
366    if (consumer_)
367      consumer_->OnCreationError(TOKEN_WRITE_FAILED);
368    return;
369  }
370  // Assume that new token is valid. It will be automatically invalidated if
371  // sync service fails to use it.
372  user_manager::UserManager::Get()->SaveUserOAuthStatus(
373      creation_context_->local_user_id,
374      user_manager::User::OAUTH2_TOKEN_STATUS_VALID);
375
376  stage_ = TOKEN_WRITTEN;
377
378  timeout_timer_.Stop();
379  ChromeUserManager::Get()
380      ->GetSupervisedUserManager()
381      ->CommitCreationTransaction();
382  content::RecordAction(
383      base::UserMetricsAction("ManagedMode_LocallyManagedUserCreated"));
384
385  stage_ = TRANSACTION_COMMITTED;
386
387  if (consumer_)
388    consumer_->OnCreationSuccess();
389}
390
391void SupervisedUserCreationControllerNew::CreationTimedOut() {
392  LOG(ERROR) << "Supervised user creation timed out. stage = " << stage_;
393  if (consumer_)
394    consumer_->OnCreationTimeout();
395}
396
397void SupervisedUserCreationControllerNew::FinishCreation() {
398  chrome::AttemptUserExit();
399}
400
401void SupervisedUserCreationControllerNew::CancelCreation() {
402  creation_context_->registration_utility.reset();
403  chrome::AttemptUserExit();
404}
405
406std::string SupervisedUserCreationControllerNew::GetSupervisedUserId() {
407  DCHECK(creation_context_);
408  return creation_context_->local_user_id;
409}
410
411}  // namespace chromeos
412