Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / chromeos / login / supervised / supervised_user_creation_controller_new.cc
blob0e512ffe746c3d4930f4053f505ca29f7f011f66
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.
5 #include "chrome/browser/chromeos/login/supervised/supervised_user_creation_controller_new.h"
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"
37 namespace chromeos {
39 namespace {
41 const int kUserCreationTimeoutSeconds = 30; // 30 seconds.
43 bool 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);
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;
54 } // namespace
56 SupervisedUserCreationControllerNew::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;
67 SupervisedUserCreationControllerNew::~SupervisedUserCreationControllerNew() {}
69 SupervisedUserCreationControllerNew::UserCreationContext::
70 UserCreationContext() {}
72 SupervisedUserCreationControllerNew::UserCreationContext::
73 ~UserCreationContext() {}
75 void SupervisedUserCreationControllerNew::SetManagerProfile(
76 Profile* manager_profile) {
77 creation_context_->manager_profile = manager_profile;
80 Profile* SupervisedUserCreationControllerNew::GetManagerProfile() {
81 return creation_context_->manager_profile;
84 void 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();
96 void 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;
105 creation_context_->display_name = display_name;
106 creation_context_->password = password;
107 creation_context_->avatar_index = avatar_index;
109 creation_context_->sync_user_id = sync_id;
111 creation_context_->master_key = master_key;
112 StartCreationImpl();
115 void 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;
126 creation_context_->display_name = display_name;
128 creation_context_->avatar_index = avatar_index;
130 creation_context_->sync_user_id = sync_id;
132 creation_context_->master_key = master_key;
134 password_data->GetStringWithoutPathExpansion(
135 kEncryptedPassword, &creation_context_->salted_password);
137 creation_context_->signature_key = signature_key;
138 creation_context_->encryption_key = encryption_key;
140 creation_context_->password_data.MergeDictionary(password_data);
142 StartCreationImpl();
145 void 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";
151 SupervisedUserManager* manager =
152 ChromeUserManager::Get()->GetSupervisedUserManager();
153 manager->StartCreationTransaction(creation_context_->display_name);
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();
161 manager->SetCreationTransactionUserId(creation_context_->local_user_id);
163 stage_ = TRANSACTION_STARTED;
165 manager->CreateUserRecord(creation_context_->manager_id,
166 creation_context_->local_user_id,
167 creation_context_->sync_user_id,
168 creation_context_->display_name);
170 SupervisedUserAuthentication* authentication =
171 ChromeUserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
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();
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);
195 authentication->StorePasswordData(creation_context_->local_user_id,
196 creation_context_->password_data);
197 stage_ = KEYS_GENERATED;
199 VLOG(1) << " Phase 2 : Create cryptohome";
201 timeout_timer_.Start(
202 FROM_HERE,
203 base::TimeDelta::FromSeconds(kUserCreationTimeoutSeconds),
204 this,
205 &SupervisedUserCreationControllerNew::CreationTimedOut);
206 authenticator_ = ExtendedAuthenticator::Create(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()));
215 void 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();
220 // Create home dir with two keys.
221 std::vector<cryptohome::KeyDefinition> keys;
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);
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()));
237 void 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();
254 stage_ = STAGE_ERROR;
255 if (consumer_)
256 consumer_->OnCreationError(code);
259 void 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";
265 creation_context_->mount_hash = mount_hash;
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));
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);
294 authenticator_->AddKey(
295 context,
296 password_key,
297 true,
298 base::Bind(&SupervisedUserCreationControllerNew::OnAddKeySuccess,
299 weak_factory_.GetWeakPtr()));
302 void SupervisedUserCreationControllerNew::OnAddKeySuccess() {
303 DCHECK(creation_context_);
304 DCHECK_EQ(KEYS_GENERATED, stage_);
305 stage_ = CRYPTOHOME_CREATED;
307 VLOG(1) << " Phase 3 : Create/update user on chrome.com/manage";
309 ProfileSyncService* sync_service =
310 ProfileSyncServiceFactory::GetInstance()->GetForProfile(
311 creation_context_->manager_profile);
312 ProfileSyncService::SyncStatusSummary status =
313 sync_service->QuerySyncStatusSummary();
315 if (status == ProfileSyncService::DATATYPES_NOT_INITIALIZED)
316 consumer_->OnLongCreationWarning();
318 creation_context_->registration_utility =
319 SupervisedUserRegistrationUtility::Create(
320 creation_context_->manager_profile);
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;
328 info.password_data.MergeDictionary(&creation_context_->password_data);
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()));
338 void SupervisedUserCreationControllerNew::RegistrationCallback(
339 const GoogleServiceAuthError& error,
340 const std::string& token) {
341 DCHECK(creation_context_);
342 DCHECK_EQ(CRYPTOHOME_CREATED, stage_);
344 stage_ = DASHBOARD_CREATED;
346 if (error.state() == GoogleServiceAuthError::NONE) {
347 creation_context_->token = token;
349 PostTaskAndReplyWithResult(
350 content::BrowserThread::GetBlockingPool()
351 ->GetTaskRunnerWithShutdownBehavior(
352 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)
353 .get(),
354 FROM_HERE,
355 base::Bind(&StoreSupervisedUserFiles, creation_context_->token,
356 ProfileHelper::GetProfilePathByUserIdHash(
357 creation_context_->mount_hash)),
358 base::Bind(
359 &SupervisedUserCreationControllerNew::OnSupervisedUserFilesStored,
360 weak_factory_.GetWeakPtr()));
361 } else {
362 stage_ = STAGE_ERROR;
363 LOG(ERROR) << "Supervised user creation failed. Error code "
364 << error.state();
365 if (consumer_)
366 consumer_->OnCreationError(CLOUD_SERVER_ERROR);
370 void SupervisedUserCreationControllerNew::OnSupervisedUserFilesStored(
371 bool success) {
372 DCHECK(creation_context_);
373 DCHECK_EQ(DASHBOARD_CREATED, stage_);
375 if (!success) {
376 stage_ = STAGE_ERROR;
377 if (consumer_)
378 consumer_->OnCreationError(TOKEN_WRITE_FAILED);
379 return;
381 // Assume that new token is valid. It will be automatically invalidated if
382 // sync service fails to use it.
383 user_manager::UserManager::Get()->SaveUserOAuthStatus(
384 creation_context_->local_user_id,
385 user_manager::User::OAUTH2_TOKEN_STATUS_VALID);
387 stage_ = TOKEN_WRITTEN;
389 timeout_timer_.Stop();
390 ChromeUserManager::Get()
391 ->GetSupervisedUserManager()
392 ->CommitCreationTransaction();
393 content::RecordAction(
394 base::UserMetricsAction("ManagedMode_LocallyManagedUserCreated"));
396 stage_ = TRANSACTION_COMMITTED;
398 if (consumer_)
399 consumer_->OnCreationSuccess();
402 void SupervisedUserCreationControllerNew::CreationTimedOut() {
403 LOG(ERROR) << "Supervised user creation timed out. stage = " << stage_;
404 if (consumer_)
405 consumer_->OnCreationTimeout();
408 void SupervisedUserCreationControllerNew::FinishCreation() {
409 chrome::AttemptUserExit();
412 void SupervisedUserCreationControllerNew::CancelCreation() {
413 creation_context_->registration_utility.reset();
414 chrome::AttemptUserExit();
417 std::string SupervisedUserCreationControllerNew::GetSupervisedUserId() {
418 DCHECK(creation_context_);
419 return creation_context_->local_user_id;
422 } // namespace chromeos