supervised_user_creation_controller_new.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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/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 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 ProfileHelper::GetProfilePathByUserIdHash( 347 creation_context_->mount_hash)), 348 base::Bind( 349 &SupervisedUserCreationControllerNew::OnSupervisedUserFilesStored, 350 weak_factory_.GetWeakPtr())); 351 } else { 352 stage_ = STAGE_ERROR; 353 LOG(ERROR) << "Supervised user creation failed. Error code " 354 << error.state(); 355 if (consumer_) 356 consumer_->OnCreationError(CLOUD_SERVER_ERROR); 357 } 358} 359 360void SupervisedUserCreationControllerNew::OnSupervisedUserFilesStored( 361 bool success) { 362 DCHECK(creation_context_); 363 DCHECK_EQ(DASHBOARD_CREATED, stage_); 364 365 if (!success) { 366 stage_ = STAGE_ERROR; 367 if (consumer_) 368 consumer_->OnCreationError(TOKEN_WRITE_FAILED); 369 return; 370 } 371 // Assume that new token is valid. It will be automatically invalidated if 372 // sync service fails to use it. 373 user_manager::UserManager::Get()->SaveUserOAuthStatus( 374 creation_context_->local_user_id, 375 user_manager::User::OAUTH2_TOKEN_STATUS_VALID); 376 377 stage_ = TOKEN_WRITTEN; 378 379 timeout_timer_.Stop(); 380 ChromeUserManager::Get() 381 ->GetSupervisedUserManager() 382 ->CommitCreationTransaction(); 383 content::RecordAction( 384 base::UserMetricsAction("ManagedMode_LocallyManagedUserCreated")); 385 386 stage_ = TRANSACTION_COMMITTED; 387 388 if (consumer_) 389 consumer_->OnCreationSuccess(); 390} 391 392void SupervisedUserCreationControllerNew::CreationTimedOut() { 393 LOG(ERROR) << "Supervised user creation timed out. stage = " << stage_; 394 if (consumer_) 395 consumer_->OnCreationTimeout(); 396} 397 398void SupervisedUserCreationControllerNew::FinishCreation() { 399 chrome::AttemptUserExit(); 400} 401 402void SupervisedUserCreationControllerNew::CancelCreation() { 403 creation_context_->registration_utility.reset(); 404 chrome::AttemptUserExit(); 405} 406 407std::string SupervisedUserCreationControllerNew::GetSupervisedUserId() { 408 DCHECK(creation_context_); 409 return creation_context_->local_user_id; 410} 411 412} // namespace chromeos 413