Home | History | Annotate | Download | only in managed
      1 // Copyright 2013 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/managed/supervised_user_login_flow.h"
      6 
      7 #include "base/base64.h"
      8 #include "base/logging.h"
      9 #include "base/metrics/histogram.h"
     10 #include "base/prefs/pref_registry_simple.h"
     11 #include "base/prefs/pref_service.h"
     12 #include "base/values.h"
     13 #include "chrome/browser/chromeos/login/auth/key.h"
     14 #include "chrome/browser/chromeos/login/login_utils.h"
     15 #include "chrome/browser/chromeos/login/managed/locally_managed_user_constants.h"
     16 #include "chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h"
     17 #include "chrome/browser/chromeos/login/managed/supervised_user_authentication.h"
     18 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
     19 #include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
     20 #include "chrome/browser/chromeos/login/users/user_manager.h"
     21 #include "chrome/browser/chromeos/login/wizard_controller.h"
     22 #include "content/public/browser/browser_thread.h"
     23 
     24 using content::BrowserThread;
     25 
     26 namespace chromeos {
     27 
     28 SupervisedUserLoginFlow::SupervisedUserLoginFlow(
     29     const std::string& user_id)
     30     : ExtendedUserFlow(user_id),
     31       data_loaded_(false),
     32       weak_factory_(this) {
     33 }
     34 
     35 SupervisedUserLoginFlow::~SupervisedUserLoginFlow() {}
     36 
     37 bool SupervisedUserLoginFlow::CanLockScreen() {
     38   return true;
     39 }
     40 
     41 bool SupervisedUserLoginFlow::ShouldLaunchBrowser() {
     42   return data_loaded_;
     43 }
     44 
     45 bool SupervisedUserLoginFlow::ShouldSkipPostLoginScreens() {
     46   return true;
     47 }
     48 
     49 bool SupervisedUserLoginFlow::HandleLoginFailure(
     50     const LoginFailure& failure) {
     51   return false;
     52 }
     53 
     54 bool SupervisedUserLoginFlow::HandlePasswordChangeDetected() {
     55   return false;
     56 }
     57 
     58 void SupervisedUserLoginFlow::HandleOAuthTokenStatusChange(
     59     User::OAuthTokenStatus status) {
     60 }
     61 
     62 void SupervisedUserLoginFlow::OnSyncSetupDataLoaded(
     63     const std::string& token) {
     64   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     65   ConfigureSync(token);
     66 }
     67 
     68 void SupervisedUserLoginFlow::ConfigureSync(const std::string& token) {
     69   data_loaded_ = true;
     70 
     71   // TODO(antrim): add error handling (no token loaded).
     72   // See also: http://crbug.com/312751
     73   UserManager::Get()->GetSupervisedUserManager()->ConfigureSyncWithToken(
     74       profile_, token);
     75   SupervisedUserAuthentication* auth =
     76       UserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
     77 
     78   if (auth->HasScheduledPasswordUpdate(user_id())) {
     79     auth->LoadPasswordUpdateData(
     80         user_id(),
     81         base::Bind(&SupervisedUserLoginFlow::OnPasswordChangeDataLoaded,
     82                    weak_factory_.GetWeakPtr()),
     83         base::Bind(&SupervisedUserLoginFlow::OnPasswordChangeDataLoadFailed,
     84                    weak_factory_.GetWeakPtr()));
     85     return;
     86   }
     87   Finish();
     88 }
     89 
     90 void SupervisedUserLoginFlow::HandleLoginSuccess(
     91     const UserContext& login_context) {
     92   context_ = login_context;
     93 }
     94 
     95 void SupervisedUserLoginFlow::OnPasswordChangeDataLoaded(
     96     const base::DictionaryValue* password_data) {
     97   // Edge case, when manager has signed in and already updated the password.
     98   SupervisedUserAuthentication* auth =
     99       UserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
    100   if (!auth->NeedPasswordChange(user_id(), password_data)) {
    101     VLOG(1) << "Password already changed for " << user_id();
    102     auth->ClearScheduledPasswordUpdate(user_id());
    103     Finish();
    104     return;
    105   }
    106 
    107   // Two cases now - we can currently have either old-style password, or new
    108   // password.
    109   std::string base64_signature;
    110   std::string signature;
    111   std::string password;
    112   int revision = 0;
    113   int schema = 0;
    114   bool success = password_data->GetStringWithoutPathExpansion(
    115       kPasswordSignature, &base64_signature);
    116   success &= password_data->GetIntegerWithoutPathExpansion(kPasswordRevision,
    117                                                            &revision);
    118   success &=
    119       password_data->GetIntegerWithoutPathExpansion(kSchemaVersion, &schema);
    120   success &= password_data->GetStringWithoutPathExpansion(kEncryptedPassword,
    121                                                           &password);
    122   if (!success) {
    123     LOG(ERROR) << "Incomplete data for password change";
    124 
    125     UMA_HISTOGRAM_ENUMERATION(
    126         "ManagedUsers.ChromeOS.PasswordChange",
    127         SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_INCOMPLETE_DATA,
    128         SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
    129     Finish();
    130     return;
    131   }
    132   base::Base64Decode(base64_signature, &signature);
    133   scoped_ptr<base::DictionaryValue> data_copy(password_data->DeepCopy());
    134   cryptohome::KeyDefinition key(password,
    135                                 kCryptohomeSupervisedUserKeyLabel,
    136                                 kCryptohomeSupervisedUserKeyPrivileges);
    137 
    138   authenticator_ = new ExtendedAuthenticator(this);
    139   SupervisedUserAuthentication::Schema current_schema =
    140       auth->GetPasswordSchema(user_id());
    141 
    142   key.revision = revision;
    143 
    144   if (SupervisedUserAuthentication::SCHEMA_PLAIN == current_schema) {
    145     // We need to add new key, and block old one. As we don't actually have
    146     // signature key, use Migrate privilege instead of AuthorizedUpdate.
    147     key.privileges = kCryptohomeSupervisedUserIncompleteKeyPrivileges;
    148 
    149     VLOG(1) << "Adding new schema key";
    150     DCHECK(context_.GetKey()->GetLabel().empty());
    151     authenticator_->AddKey(context_,
    152                            key,
    153                            false /* no key exists */,
    154                            base::Bind(&SupervisedUserLoginFlow::OnNewKeyAdded,
    155                                       weak_factory_.GetWeakPtr(),
    156                                       Passed(&data_copy)));
    157   } else if (SupervisedUserAuthentication::SCHEMA_SALT_HASHED ==
    158              current_schema) {
    159     VLOG(1) << "Updating the key";
    160 
    161     if (auth->HasIncompleteKey(user_id())) {
    162       // We need to use Migrate instead of Authorized Update privilege.
    163       key.privileges = kCryptohomeSupervisedUserIncompleteKeyPrivileges;
    164     }
    165     // Just update the key.
    166     DCHECK_EQ(context_.GetKey()->GetLabel(), kCryptohomeSupervisedUserKeyLabel);
    167     authenticator_->UpdateKeyAuthorized(
    168         context_,
    169         key,
    170         signature,
    171         base::Bind(&SupervisedUserLoginFlow::OnPasswordUpdated,
    172                    weak_factory_.GetWeakPtr(),
    173                    Passed(&data_copy)));
    174   } else {
    175     NOTREACHED() << "Unsupported password schema";
    176   }
    177 }
    178 
    179 void SupervisedUserLoginFlow::OnNewKeyAdded(
    180     scoped_ptr<base::DictionaryValue> password_data) {
    181   VLOG(1) << "New key added";
    182   SupervisedUserAuthentication* auth =
    183       UserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
    184   auth->StorePasswordData(user_id(), *password_data.get());
    185   auth->MarkKeyIncomplete(user_id(), true /* incomplete */);
    186   authenticator_->RemoveKey(
    187       context_,
    188       kLegacyCryptohomeSupervisedUserKeyLabel,
    189       base::Bind(&SupervisedUserLoginFlow::OnOldKeyRemoved,
    190                  weak_factory_.GetWeakPtr()));
    191 }
    192 
    193 void SupervisedUserLoginFlow::OnOldKeyRemoved() {
    194   UMA_HISTOGRAM_ENUMERATION(
    195       "ManagedUsers.ChromeOS.PasswordChange",
    196       SupervisedUserAuthentication::PASSWORD_CHANGED_IN_USER_SESSION,
    197       SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
    198   Finish();
    199 }
    200 
    201 void SupervisedUserLoginFlow::OnPasswordChangeDataLoadFailed() {
    202   LOG(ERROR) << "Could not load data for password change";
    203 
    204   UMA_HISTOGRAM_ENUMERATION(
    205       "ManagedUsers.ChromeOS.PasswordChange",
    206       SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_LOADING_DATA,
    207       SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
    208   Finish();
    209 }
    210 
    211 void SupervisedUserLoginFlow::OnAuthenticationFailure(
    212     ExtendedAuthenticator::AuthState state) {
    213   LOG(ERROR) << "Authentication error during password change";
    214 
    215   UMA_HISTOGRAM_ENUMERATION(
    216       "ManagedUsers.ChromeOS.PasswordChange",
    217       SupervisedUserAuthentication::
    218           PASSWORD_CHANGE_FAILED_AUTHENTICATION_FAILURE,
    219       SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
    220   Finish();
    221 }
    222 
    223 void SupervisedUserLoginFlow::OnPasswordUpdated(
    224     scoped_ptr<base::DictionaryValue> password_data) {
    225   VLOG(1) << "Updated password for supervised user";
    226 
    227   SupervisedUserAuthentication* auth =
    228       UserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
    229 
    230   // Incomplete state is not there in password_data, carry it from old state.
    231   bool was_incomplete = auth->HasIncompleteKey(user_id());
    232   auth->StorePasswordData(user_id(), *password_data.get());
    233   if (was_incomplete)
    234     auth->MarkKeyIncomplete(user_id(), true /* incomplete */);
    235 
    236   UMA_HISTOGRAM_ENUMERATION(
    237       "ManagedUsers.ChromeOS.PasswordChange",
    238       SupervisedUserAuthentication::PASSWORD_CHANGED_IN_USER_SESSION,
    239       SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
    240   Finish();
    241 }
    242 
    243 void SupervisedUserLoginFlow::Finish() {
    244   LoginUtils::Get()->DoBrowserLaunch(profile_, host());
    245   profile_ = NULL;
    246   UnregisterFlowSoon();
    247 }
    248 
    249 void SupervisedUserLoginFlow::LaunchExtraSteps(
    250     Profile* profile) {
    251   profile_ = profile;
    252   UserManager::Get()->GetSupervisedUserManager()->LoadSupervisedUserToken(
    253       profile,
    254       base::Bind(
    255            &SupervisedUserLoginFlow::OnSyncSetupDataLoaded,
    256            weak_factory_.GetWeakPtr()));
    257 }
    258 
    259 }  // namespace chromeos
    260