Home | History | Annotate | Download | only in supervised
      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 
     37 namespace chromeos {
     38 
     39 namespace {
     40 
     41 const int kUserCreationTimeoutSeconds = 30;  // 30 seconds.
     42 
     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);
     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 
     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;
     65 }
     66 
     67 SupervisedUserCreationControllerNew::~SupervisedUserCreationControllerNew() {}
     68 
     69 SupervisedUserCreationControllerNew::UserCreationContext::
     70     UserCreationContext() {}
     71 
     72 SupervisedUserCreationControllerNew::UserCreationContext::
     73     ~UserCreationContext() {}
     74 
     75 void SupervisedUserCreationControllerNew::SetManagerProfile(
     76     Profile* manager_profile) {
     77   creation_context_->manager_profile = manager_profile;
     78 }
     79 
     80 Profile* SupervisedUserCreationControllerNew::GetManagerProfile() {
     81   return creation_context_->manager_profile;
     82 }
     83 
     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();
     94 }
     95 
     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;
    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 
    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;
    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 
    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";
    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_ = 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()));
    213 }
    214 
    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();
    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 
    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();
    253   }
    254   stage_ = STAGE_ERROR;
    255   if (consumer_)
    256     consumer_->OnCreationError(code);
    257 }
    258 
    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";
    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 
    302 void 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 
    338 void 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 
    368 void 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 
    400 void SupervisedUserCreationControllerNew::CreationTimedOut() {
    401   LOG(ERROR) << "Supervised user creation timed out. stage = " << stage_;
    402   if (consumer_)
    403     consumer_->OnCreationTimeout();
    404 }
    405 
    406 void SupervisedUserCreationControllerNew::FinishCreation() {
    407   chrome::AttemptUserExit();
    408 }
    409 
    410 void SupervisedUserCreationControllerNew::CancelCreation() {
    411   creation_context_->registration_utility.reset();
    412   chrome::AttemptUserExit();
    413 }
    414 
    415 std::string SupervisedUserCreationControllerNew::GetSupervisedUserId() {
    416   DCHECK(creation_context_);
    417   return creation_context_->local_user_id;
    418 }
    419 
    420 }  // namespace chromeos
    421