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"
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"
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());
56 SupervisedUserCreationControllerNew::SupervisedUserCreationControllerNew(
57 SupervisedUserCreationControllerNew::StatusConsumer
* consumer
,
58 const std::string
& manager_id
)
59 : SupervisedUserCreationController(consumer
),
60 stage_(STAGE_INITIAL
),
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
,
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
;
96 void SupervisedUserCreationControllerNew::StartImport(
97 const base::string16
& display_name
,
98 const std::string
& password
,
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
;
115 void SupervisedUserCreationControllerNew::StartImport(
116 const base::string16
& display_name
,
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
);
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
,
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(
203 base::TimeDelta::FromSeconds(kUserCreationTimeoutSeconds
),
205 &SupervisedUserCreationControllerNew::CreationTimedOut
);
206 authenticator_
= ExtendedAuthenticator::Create(this);
207 UserContext user_context
;
208 user_context
.SetKey(Key(creation_context_
->master_key
));
209 authenticator_
->TransformKeyIfNeeded(
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
,
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
;
242 case SupervisedUserAuthenticator::NO_MOUNT
:
243 code
= CRYPTOHOME_NO_MOUNT
;
245 case SupervisedUserAuthenticator::FAILED_MOUNT
:
246 code
= CRYPTOHOME_FAILED_MOUNT
;
248 case SupervisedUserAuthenticator::FAILED_TPM
:
249 code
= CRYPTOHOME_FAILED_TPM
;
254 stage_
= STAGE_ERROR
;
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 */,
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 */,
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
);
292 context
.SetIsUsingOAuth(false);
294 authenticator_
->AddKey(
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
,
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
)
355 base::Bind(&StoreSupervisedUserFiles
, creation_context_
->token
,
356 ProfileHelper::GetProfilePathByUserIdHash(
357 creation_context_
->mount_hash
)),
359 &SupervisedUserCreationControllerNew::OnSupervisedUserFilesStored
,
360 weak_factory_
.GetWeakPtr()));
362 stage_
= STAGE_ERROR
;
363 LOG(ERROR
) << "Supervised user creation failed. Error code "
366 consumer_
->OnCreationError(CLOUD_SERVER_ERROR
);
370 void SupervisedUserCreationControllerNew::OnSupervisedUserFilesStored(
372 DCHECK(creation_context_
);
373 DCHECK_EQ(DASHBOARD_CREATED
, stage_
);
376 stage_
= STAGE_ERROR
;
378 consumer_
->OnCreationError(TOKEN_WRITE_FAILED
);
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
;
399 consumer_
->OnCreationSuccess();
402 void SupervisedUserCreationControllerNew::CreationTimedOut() {
403 LOG(ERROR
) << "Supervised user creation timed out. stage = " << stage_
;
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