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