Home | History | Annotate | Download | only in enrollment
      1 // Copyright (c) 2012 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/enrollment/enrollment_screen.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/logging.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/metrics/histogram.h"
     12 #include "base/metrics/sparse_histogram.h"
     13 #include "base/timer/elapsed_timer.h"
     14 #include "chrome/browser/browser_process.h"
     15 #include "chrome/browser/browser_process_platform_part.h"
     16 #include "chrome/browser/chromeos/login/login_utils.h"
     17 #include "chrome/browser/chromeos/login/screen_manager.h"
     18 #include "chrome/browser/chromeos/login/screens/screen_observer.h"
     19 #include "chrome/browser/chromeos/login/startup_utils.h"
     20 #include "chrome/browser/chromeos/login/wizard_controller.h"
     21 #include "chrome/browser/chromeos/policy/auto_enrollment_client.h"
     22 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
     23 #include "chrome/browser/chromeos/policy/device_cloud_policy_initializer.h"
     24 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
     25 #include "chromeos/dbus/cryptohome_client.h"
     26 #include "chromeos/dbus/dbus_method_call_status.h"
     27 #include "chromeos/dbus/dbus_thread_manager.h"
     28 #include "chromeos/dbus/session_manager_client.h"
     29 #include "components/pairing/controller_pairing_controller.h"
     30 #include "google_apis/gaia/gaia_auth_util.h"
     31 #include "google_apis/gaia/google_service_auth_error.h"
     32 #include "policy/proto/device_management_backend.pb.h"
     33 
     34 using namespace pairing_chromeos;
     35 
     36 // Do not change the UMA histogram parameters without renaming the histograms!
     37 #define UMA_ENROLLMENT_TIME(histogram_name, elapsed_timer) \
     38   do {                                                     \
     39     UMA_HISTOGRAM_CUSTOM_TIMES(                            \
     40       (histogram_name),                                    \
     41       (elapsed_timer)->Elapsed(),                          \
     42       base::TimeDelta::FromMilliseconds(100) /* min */,    \
     43       base::TimeDelta::FromMinutes(15) /* max */,          \
     44       100 /* bucket_count */);                             \
     45   } while (0)
     46 
     47 namespace chromeos {
     48 
     49 // static
     50 EnrollmentScreen* EnrollmentScreen::Get(ScreenManager* manager) {
     51   return static_cast<EnrollmentScreen*>(
     52       manager->GetScreen(WizardController::kEnrollmentScreenName));
     53 }
     54 
     55 EnrollmentScreen::EnrollmentScreen(
     56     ScreenObserver* observer,
     57     EnrollmentScreenActor* actor)
     58     : WizardScreen(observer),
     59       shark_controller_(NULL),
     60       remora_controller_(NULL),
     61       actor_(actor),
     62       enrollment_mode_(EnrollmentScreenActor::ENROLLMENT_MODE_MANUAL),
     63       enrollment_failed_once_(false),
     64       remora_token_sent_(false),
     65       lockbox_init_duration_(0),
     66       weak_ptr_factory_(this) {
     67   // Init the TPM if it has not been done until now (in debug build we might
     68   // have not done that yet).
     69   DBusThreadManager::Get()->GetCryptohomeClient()->TpmCanAttemptOwnership(
     70       EmptyVoidDBusMethodCallback());
     71 }
     72 
     73 EnrollmentScreen::~EnrollmentScreen() {
     74   if (remora_controller_)
     75     remora_controller_->RemoveObserver(this);
     76 }
     77 
     78 void EnrollmentScreen::SetParameters(
     79     EnrollmentScreenActor::EnrollmentMode enrollment_mode,
     80     const std::string& management_domain,
     81     const std::string& user,
     82     const std::string& auth_token,
     83     pairing_chromeos::ControllerPairingController* shark_controller,
     84     pairing_chromeos::HostPairingController* remora_controller) {
     85   enrollment_mode_ = enrollment_mode;
     86   user_ = user.empty() ? user : gaia::CanonicalizeEmail(user);
     87   auth_token_ = auth_token;
     88   shark_controller_ = shark_controller;
     89   if (remora_controller_)
     90     remora_controller_->RemoveObserver(this);
     91   remora_controller_ = remora_controller;
     92   if (remora_controller_)
     93     remora_controller_->AddObserver(this);
     94   actor_->SetParameters(this, enrollment_mode_, management_domain);
     95 }
     96 
     97 void EnrollmentScreen::PrepareToShow() {
     98   actor_->PrepareToShow();
     99 }
    100 
    101 void EnrollmentScreen::Show() {
    102   if (is_auto_enrollment() && !enrollment_failed_once_) {
    103     actor_->Show();
    104     UMA(policy::kMetricEnrollmentAutoStarted);
    105     actor_->ShowEnrollmentSpinnerScreen();
    106     actor_->FetchOAuthToken();
    107   } else if (auth_token_.empty()) {
    108     UMA(policy::kMetricEnrollmentTriggered);
    109     actor_->ResetAuth(base::Bind(&EnrollmentScreen::ShowSigninScreen,
    110                                  weak_ptr_factory_.GetWeakPtr()));
    111   } else {
    112     actor_->Show();
    113     actor_->ShowEnrollmentSpinnerScreen();
    114     OnOAuthTokenAvailable(auth_token_);
    115   }
    116 }
    117 
    118 void EnrollmentScreen::Hide() {
    119   actor_->Hide();
    120   weak_ptr_factory_.InvalidateWeakPtrs();
    121 }
    122 
    123 std::string EnrollmentScreen::GetName() const {
    124   return WizardController::kEnrollmentScreenName;
    125 }
    126 
    127 void EnrollmentScreen::PairingStageChanged(Stage new_stage) {
    128   DCHECK(remora_controller_);
    129   if (new_stage == HostPairingController::STAGE_FINISHED) {
    130     remora_controller_->RemoveObserver(this);
    131     remora_controller_ = NULL;
    132     // TODO(zork): Check that this is the best exit status. crbug.com/412798
    133     get_screen_observer()->OnExit(
    134         WizardController::ENTERPRISE_AUTO_MAGIC_ENROLLMENT_COMPLETED);
    135   }
    136 }
    137 
    138 void EnrollmentScreen::ConfigureHost(bool accepted_eula,
    139                                      const std::string& lang,
    140                                      const std::string& timezone,
    141                                      bool send_reports,
    142                                      const std::string& keyboard_layout) {
    143 }
    144 
    145 void EnrollmentScreen::EnrollHost(const std::string& auth_token) {
    146 }
    147 
    148 void EnrollmentScreen::OnLoginDone(const std::string& user) {
    149   elapsed_timer_.reset(new base::ElapsedTimer());
    150   user_ = gaia::CanonicalizeEmail(user);
    151 
    152   if (is_auto_enrollment())
    153     UMA(policy::kMetricEnrollmentAutoRestarted);
    154   else if (enrollment_failed_once_)
    155     UMA(policy::kMetricEnrollmentRestarted);
    156   else
    157     UMA(policy::kMetricEnrollmentStarted);
    158 
    159   actor_->ShowEnrollmentSpinnerScreen();
    160   actor_->FetchOAuthToken();
    161 }
    162 
    163 void EnrollmentScreen::OnAuthError(const GoogleServiceAuthError& error) {
    164   switch (error.state()) {
    165     case GoogleServiceAuthError::NONE:
    166     case GoogleServiceAuthError::CAPTCHA_REQUIRED:
    167     case GoogleServiceAuthError::TWO_FACTOR:
    168     case GoogleServiceAuthError::HOSTED_NOT_ALLOWED:
    169     case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
    170     case GoogleServiceAuthError::REQUEST_CANCELED:
    171     case GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE:
    172     case GoogleServiceAuthError::SERVICE_ERROR:
    173       UMAFailure(policy::kMetricEnrollmentLoginFailed);
    174       LOG(ERROR) << "Auth error " << error.state();
    175       break;
    176     case GoogleServiceAuthError::USER_NOT_SIGNED_UP:
    177       UMAFailure(policy::kMetricEnrollmentAccountNotSignedUp);
    178       LOG(ERROR) << "Account not signed up " << error.state();
    179       break;
    180     case GoogleServiceAuthError::ACCOUNT_DELETED:
    181       UMAFailure(policy::kMetricEnrollmentAccountDeleted);
    182       LOG(ERROR) << "Account deleted " << error.state();
    183       break;
    184     case GoogleServiceAuthError::ACCOUNT_DISABLED:
    185       UMAFailure(policy::kMetricEnrollmentAccountDisabled);
    186       LOG(ERROR) << "Account disabled " << error.state();
    187       break;
    188     case GoogleServiceAuthError::CONNECTION_FAILED:
    189     case GoogleServiceAuthError::SERVICE_UNAVAILABLE:
    190       UMAFailure(policy::kMetricEnrollmentNetworkFailed);
    191       LOG(WARNING) << "Network error " << error.state();
    192       break;
    193     case GoogleServiceAuthError::NUM_STATES:
    194       NOTREACHED();
    195       break;
    196   }
    197 
    198   enrollment_failed_once_ = true;
    199   actor_->ShowAuthError(error);
    200 }
    201 
    202 void EnrollmentScreen::OnOAuthTokenAvailable(const std::string& token) {
    203   VLOG(1) << "OnOAuthTokenAvailable " << token;
    204   const bool is_shark =
    205       g_browser_process->platform_part()->browser_policy_connector_chromeos()->
    206           GetDeviceCloudPolicyManager()->IsSharkRequisition();
    207 
    208   if (is_shark && !remora_token_sent_) {
    209     // Fetch a second token for shark devices.
    210     remora_token_sent_ = true;
    211     SendEnrollmentAuthToken(token);
    212     actor_->FetchOAuthToken();
    213   } else {
    214     RegisterForDevicePolicy(token);
    215   }
    216 }
    217 
    218 void EnrollmentScreen::OnRetry() {
    219   actor_->ResetAuth(base::Bind(&EnrollmentScreen::ShowSigninScreen,
    220                                weak_ptr_factory_.GetWeakPtr()));
    221 }
    222 
    223 void EnrollmentScreen::OnCancel() {
    224   UMA(is_auto_enrollment() ? policy::kMetricEnrollmentAutoCancelled
    225                            : policy::kMetricEnrollmentCancelled);
    226   if (elapsed_timer_)
    227     UMA_ENROLLMENT_TIME("Enterprise.EnrollmentTime.Cancel", elapsed_timer_);
    228   if (enrollment_mode_ == EnrollmentScreenActor::ENROLLMENT_MODE_FORCED ||
    229       enrollment_mode_ == EnrollmentScreenActor::ENROLLMENT_MODE_RECOVERY) {
    230     actor_->ResetAuth(
    231         base::Bind(&ScreenObserver::OnExit,
    232                    base::Unretained(get_screen_observer()),
    233                    ScreenObserver::ENTERPRISE_ENROLLMENT_BACK));
    234     return;
    235   }
    236 
    237   if (is_auto_enrollment())
    238     policy::AutoEnrollmentClient::CancelAutoEnrollment();
    239   actor_->ResetAuth(
    240       base::Bind(&ScreenObserver::OnExit,
    241                  base::Unretained(get_screen_observer()),
    242                  ScreenObserver::ENTERPRISE_ENROLLMENT_COMPLETED));
    243 }
    244 
    245 void EnrollmentScreen::OnConfirmationClosed() {
    246   // If the machine has been put in KIOSK mode we have to restart the session
    247   // here to go in the proper KIOSK mode login screen.
    248   policy::BrowserPolicyConnectorChromeOS* connector =
    249       g_browser_process->platform_part()->browser_policy_connector_chromeos();
    250   if (connector->GetDeviceMode() == policy::DEVICE_MODE_RETAIL_KIOSK) {
    251     DBusThreadManager::Get()->GetSessionManagerClient()->StopSession();
    252     return;
    253   }
    254 
    255   if (is_auto_enrollment() &&
    256       !enrollment_failed_once_ &&
    257       !user_.empty() &&
    258       LoginUtils::IsWhitelisted(user_, NULL)) {
    259     actor_->ShowLoginSpinnerScreen();
    260     get_screen_observer()->OnExit(
    261         ScreenObserver::ENTERPRISE_AUTO_MAGIC_ENROLLMENT_COMPLETED);
    262   } else {
    263     actor_->ResetAuth(
    264         base::Bind(&ScreenObserver::OnExit,
    265                    base::Unretained(get_screen_observer()),
    266                    ScreenObserver::ENTERPRISE_ENROLLMENT_COMPLETED));
    267   }
    268 }
    269 
    270 void EnrollmentScreen::RegisterForDevicePolicy(const std::string& token) {
    271   policy::BrowserPolicyConnectorChromeOS* connector =
    272       g_browser_process->platform_part()->browser_policy_connector_chromeos();
    273   if (connector->IsEnterpriseManaged() &&
    274       connector->GetEnterpriseDomain() != gaia::ExtractDomainName(user_)) {
    275     LOG(ERROR) << "Trying to re-enroll to a different domain than "
    276                << connector->GetEnterpriseDomain();
    277     UMAFailure(policy::kMetricEnrollmentPrecheckDomainMismatch);
    278     actor_->ShowUIError(
    279         EnrollmentScreenActor::UI_ERROR_DOMAIN_MISMATCH);
    280     return;
    281   }
    282 
    283   policy::DeviceCloudPolicyInitializer::AllowedDeviceModes device_modes;
    284   device_modes[policy::DEVICE_MODE_ENTERPRISE] = true;
    285   device_modes[policy::DEVICE_MODE_RETAIL_KIOSK] =
    286       enrollment_mode_ == EnrollmentScreenActor::ENROLLMENT_MODE_MANUAL;
    287   connector->ScheduleServiceInitialization(0);
    288 
    289   policy::DeviceCloudPolicyInitializer* dcp_initializer =
    290       connector->GetDeviceCloudPolicyInitializer();
    291   CHECK(dcp_initializer);
    292   dcp_initializer->StartEnrollment(
    293       enterprise_management::PolicyData::ENTERPRISE_MANAGED,
    294       connector->device_management_service(),
    295       token, is_auto_enrollment(), device_modes,
    296       base::Bind(&EnrollmentScreen::ReportEnrollmentStatus,
    297                  weak_ptr_factory_.GetWeakPtr()));
    298 }
    299 
    300 void EnrollmentScreen::SendEnrollmentAuthToken(const std::string& token) {
    301   // TODO(achuith, zork): Extract and send domain.
    302   if (shark_controller_)
    303     shark_controller_->OnAuthenticationDone("", token);
    304 }
    305 
    306 void EnrollmentScreen::ShowEnrollmentStatusOnSuccess(
    307     const policy::EnrollmentStatus& status) {
    308   StartupUtils::MarkOobeCompleted();
    309   if (elapsed_timer_)
    310     UMA_ENROLLMENT_TIME("Enterprise.EnrollmentTime.Success", elapsed_timer_);
    311   actor_->ShowEnrollmentStatus(status);
    312 }
    313 
    314 void EnrollmentScreen::ReportEnrollmentStatus(policy::EnrollmentStatus status) {
    315   switch (status.status()) {
    316     case policy::EnrollmentStatus::STATUS_SUCCESS:
    317       StartupUtils::MarkDeviceRegistered(
    318           base::Bind(&EnrollmentScreen::ShowEnrollmentStatusOnSuccess,
    319                      weak_ptr_factory_.GetWeakPtr(),
    320                      status));
    321       UMA(is_auto_enrollment() ? policy::kMetricEnrollmentAutoOK
    322                                : policy::kMetricEnrollmentOK);
    323       if (remora_controller_)
    324         remora_controller_->SetEnrollmentComplete(true);
    325       return;
    326     case policy::EnrollmentStatus::STATUS_REGISTRATION_FAILED:
    327     case policy::EnrollmentStatus::STATUS_POLICY_FETCH_FAILED:
    328       switch (status.client_status()) {
    329         case policy::DM_STATUS_SUCCESS:
    330           NOTREACHED();
    331           break;
    332         case policy::DM_STATUS_REQUEST_INVALID:
    333           UMAFailure(policy::kMetricEnrollmentRegisterPolicyPayloadInvalid);
    334           break;
    335         case policy::DM_STATUS_SERVICE_DEVICE_NOT_FOUND:
    336           UMAFailure(policy::kMetricEnrollmentRegisterPolicyDeviceNotFound);
    337           break;
    338         case policy::DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID:
    339           UMAFailure(policy::kMetricEnrollmentRegisterPolicyDMTokenInvalid);
    340           break;
    341         case policy::DM_STATUS_SERVICE_ACTIVATION_PENDING:
    342           UMAFailure(policy::kMetricEnrollmentRegisterPolicyActivationPending);
    343           break;
    344         case policy::DM_STATUS_SERVICE_DEVICE_ID_CONFLICT:
    345           UMAFailure(policy::kMetricEnrollmentRegisterPolicyDeviceIdConflict);
    346           break;
    347         case policy::DM_STATUS_SERVICE_POLICY_NOT_FOUND:
    348           UMAFailure(policy::kMetricEnrollmentRegisterPolicyNotFound);
    349           break;
    350         case policy::DM_STATUS_REQUEST_FAILED:
    351           UMAFailure(policy::kMetricEnrollmentRegisterPolicyRequestFailed);
    352           break;
    353         case policy::DM_STATUS_TEMPORARY_UNAVAILABLE:
    354           UMAFailure(policy::kMetricEnrollmentRegisterPolicyTempUnavailable);
    355           break;
    356         case policy::DM_STATUS_HTTP_STATUS_ERROR:
    357           UMAFailure(policy::kMetricEnrollmentRegisterPolicyHttpError);
    358           break;
    359         case policy::DM_STATUS_RESPONSE_DECODING_ERROR:
    360           UMAFailure(policy::kMetricEnrollmentRegisterPolicyResponseInvalid);
    361           break;
    362         case policy::DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED:
    363           UMAFailure(policy::kMetricEnrollmentNotSupported);
    364           break;
    365         case policy::DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER:
    366           UMAFailure(policy::kMetricEnrollmentRegisterPolicyInvalidSerial);
    367           break;
    368         case policy::DM_STATUS_SERVICE_MISSING_LICENSES:
    369           UMAFailure(policy::kMetricEnrollmentRegisterPolicyMissingLicenses);
    370           break;
    371         case policy::DM_STATUS_SERVICE_DEPROVISIONED:
    372           UMAFailure(policy::kMetricEnrollmentRegisterPolicyDeprovisioned);
    373           break;
    374         case policy::DM_STATUS_SERVICE_DOMAIN_MISMATCH:
    375           UMAFailure(policy::kMetricEnrollmentRegisterPolicyDomainMismatch);
    376           break;
    377       }
    378       break;
    379     case policy::EnrollmentStatus::STATUS_REGISTRATION_BAD_MODE:
    380       UMAFailure(policy::kMetricEnrollmentInvalidEnrollmentMode);
    381       break;
    382     case policy::EnrollmentStatus::STATUS_LOCK_TIMEOUT:
    383       UMAFailure(policy::kMetricEnrollmentLockboxTimeoutError);
    384       break;
    385     case policy::EnrollmentStatus::STATUS_LOCK_WRONG_USER:
    386       UMAFailure(policy::kMetricEnrollmentLockDomainMismatch);
    387       break;
    388     case policy::EnrollmentStatus::STATUS_NO_STATE_KEYS:
    389       UMAFailure(policy::kMetricEnrollmentNoStateKeys);
    390       break;
    391     case policy::EnrollmentStatus::STATUS_VALIDATION_FAILED:
    392       UMAFailure(policy::kMetricEnrollmentPolicyValidationFailed);
    393       break;
    394     case policy::EnrollmentStatus::STATUS_STORE_ERROR:
    395       UMAFailure(policy::kMetricEnrollmentCloudPolicyStoreError);
    396       break;
    397     case policy::EnrollmentStatus::STATUS_LOCK_ERROR:
    398       UMAFailure(policy::kMetricEnrollmentLockBackendError);
    399       break;
    400     case policy::EnrollmentStatus::STATUS_ROBOT_AUTH_FETCH_FAILED:
    401       UMAFailure(policy::kMetricEnrollmentRobotAuthCodeFetchFailed);
    402       break;
    403     case policy::EnrollmentStatus::STATUS_ROBOT_REFRESH_FETCH_FAILED:
    404       UMAFailure(policy::kMetricEnrollmentRobotRefreshTokenFetchFailed);
    405       break;
    406     case policy::EnrollmentStatus::STATUS_ROBOT_REFRESH_STORE_FAILED:
    407       UMAFailure(policy::kMetricEnrollmentRobotRefreshTokenStoreFailed);
    408       break;
    409     case policy::EnrollmentStatus::STATUS_STORE_TOKEN_AND_ID_FAILED:
    410       // This error should not happen for enterprise enrollment, it only affects
    411       // consumer enrollment.
    412       UMAFailure(policy::kMetricEnrollmentStoreTokenAndIdFailed);
    413       NOTREACHED();
    414       break;
    415   }
    416 
    417   if (remora_controller_)
    418     remora_controller_->SetEnrollmentComplete(false);
    419   enrollment_failed_once_ = true;
    420   if (elapsed_timer_)
    421     UMA_ENROLLMENT_TIME("Enterprise.EnrollmentTime.Failure", elapsed_timer_);
    422   actor_->ShowEnrollmentStatus(status);
    423 }
    424 
    425 void EnrollmentScreen::UMA(policy::MetricEnrollment sample) {
    426   switch (enrollment_mode_) {
    427     case EnrollmentScreenActor::ENROLLMENT_MODE_MANUAL:
    428     case EnrollmentScreenActor::ENROLLMENT_MODE_AUTO:
    429       UMA_HISTOGRAM_SPARSE_SLOWLY("Enterprise.Enrollment", sample);
    430       break;
    431     case EnrollmentScreenActor::ENROLLMENT_MODE_FORCED:
    432       UMA_HISTOGRAM_SPARSE_SLOWLY("Enterprise.EnrollmentForced", sample);
    433       break;
    434     case EnrollmentScreenActor::ENROLLMENT_MODE_RECOVERY:
    435       UMA_HISTOGRAM_SPARSE_SLOWLY("Enterprise.EnrollmentRecovery", sample);
    436       break;
    437     case EnrollmentScreenActor::ENROLLMENT_MODE_COUNT:
    438       NOTREACHED();
    439       break;
    440   }
    441 }
    442 
    443 void EnrollmentScreen::UMAFailure(policy::MetricEnrollment sample) {
    444   if (is_auto_enrollment())
    445     sample = policy::kMetricEnrollmentAutoFailed;
    446   UMA(sample);
    447 }
    448 
    449 void EnrollmentScreen::ShowSigninScreen() {
    450   actor_->Show();
    451   actor_->ShowSigninScreen();
    452 }
    453 
    454 }  // namespace chromeos
    455