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 "chrome/browser/browser_process.h"
     13 #include "chrome/browser/chromeos/login/login_utils.h"
     14 #include "chrome/browser/chromeos/login/screens/screen_observer.h"
     15 #include "chrome/browser/chromeos/login/startup_utils.h"
     16 #include "chrome/browser/chromeos/login/wizard_controller.h"
     17 #include "chrome/browser/chromeos/policy/auto_enrollment_client.h"
     18 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
     19 #include "chrome/browser/policy/browser_policy_connector.h"
     20 #include "chrome/browser/policy/cloud/enterprise_metrics.h"
     21 #include "chromeos/dbus/cryptohome_client.h"
     22 #include "chromeos/dbus/dbus_thread_manager.h"
     23 #include "chromeos/dbus/session_manager_client.h"
     24 #include "google_apis/gaia/gaia_auth_util.h"
     25 #include "google_apis/gaia/google_service_auth_error.h"
     26 
     27 namespace chromeos {
     28 
     29 namespace {
     30 
     31 void UMA(int sample) {
     32   UMA_HISTOGRAM_ENUMERATION(policy::kMetricEnrollment,
     33                             sample,
     34                             policy::kMetricEnrollmentSize);
     35 }
     36 
     37 // Does nothing.  Used as a VoidDBusMethodCallback.
     38 void EmptyVoidDBusMethodCallback(DBusMethodCallStatus result) {}
     39 
     40 }  // namespace
     41 
     42 EnrollmentScreen::EnrollmentScreen(
     43     ScreenObserver* observer,
     44     EnrollmentScreenActor* actor)
     45     : WizardScreen(observer),
     46       actor_(actor),
     47       is_auto_enrollment_(false),
     48       can_exit_enrollment_(true),
     49       enrollment_failed_once_(false),
     50       lockbox_init_duration_(0),
     51       weak_ptr_factory_(this) {
     52   // Init the TPM if it has not been done until now (in debug build we might
     53   // have not done that yet).
     54   DBusThreadManager::Get()->GetCryptohomeClient()->TpmCanAttemptOwnership(
     55       base::Bind(&EmptyVoidDBusMethodCallback));
     56 }
     57 
     58 EnrollmentScreen::~EnrollmentScreen() {}
     59 
     60 void EnrollmentScreen::SetParameters(bool is_auto_enrollment,
     61                                      bool can_exit_enrollment,
     62                                      const std::string& user) {
     63   is_auto_enrollment_ = is_auto_enrollment;
     64   can_exit_enrollment_ = can_exit_enrollment;
     65   user_ = user.empty() ? user : gaia::CanonicalizeEmail(user);
     66   actor_->SetParameters(this, is_auto_enrollment_, can_exit_enrollment, user_);
     67 }
     68 
     69 void EnrollmentScreen::PrepareToShow() {
     70   actor_->PrepareToShow();
     71 }
     72 
     73 void EnrollmentScreen::Show() {
     74   if (is_auto_enrollment_ && !enrollment_failed_once_) {
     75     actor_->Show();
     76     UMA(policy::kMetricEnrollmentAutoStarted);
     77     actor_->ShowEnrollmentSpinnerScreen();
     78     actor_->FetchOAuthToken();
     79   } else {
     80     actor_->ResetAuth(base::Bind(&EnrollmentScreen::ShowSigninScreen,
     81                                  weak_ptr_factory_.GetWeakPtr()));
     82   }
     83 }
     84 
     85 void EnrollmentScreen::Hide() {
     86   actor_->Hide();
     87   weak_ptr_factory_.InvalidateWeakPtrs();
     88 }
     89 
     90 std::string EnrollmentScreen::GetName() const {
     91   return WizardController::kEnrollmentScreenName;
     92 }
     93 
     94 void EnrollmentScreen::OnLoginDone(const std::string& user) {
     95   user_ = gaia::CanonicalizeEmail(user);
     96 
     97   UMA(is_auto_enrollment_ ? policy::kMetricEnrollmentAutoRetried
     98                           : policy::kMetricEnrollmentStarted);
     99 
    100   actor_->ShowEnrollmentSpinnerScreen();
    101   actor_->FetchOAuthToken();
    102 }
    103 
    104 void EnrollmentScreen::OnAuthError(
    105     const GoogleServiceAuthError& error) {
    106   enrollment_failed_once_ = true;
    107   actor_->ShowAuthError(error);
    108 
    109   switch (error.state()) {
    110     case GoogleServiceAuthError::NONE:
    111     case GoogleServiceAuthError::CAPTCHA_REQUIRED:
    112     case GoogleServiceAuthError::TWO_FACTOR:
    113     case GoogleServiceAuthError::HOSTED_NOT_ALLOWED:
    114     case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
    115     case GoogleServiceAuthError::REQUEST_CANCELED:
    116     case GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE:
    117     case GoogleServiceAuthError::SERVICE_ERROR:
    118       UMAFailure(policy::kMetricEnrollmentLoginFailed);
    119       LOG(ERROR) << "Auth error " << error.state();
    120       return;
    121     case GoogleServiceAuthError::USER_NOT_SIGNED_UP:
    122     case GoogleServiceAuthError::ACCOUNT_DELETED:
    123     case GoogleServiceAuthError::ACCOUNT_DISABLED:
    124       UMAFailure(policy::kMetricEnrollmentNotSupported);
    125       LOG(ERROR) << "Account error " << error.state();
    126       return;
    127     case GoogleServiceAuthError::CONNECTION_FAILED:
    128     case GoogleServiceAuthError::SERVICE_UNAVAILABLE:
    129       UMAFailure(policy::kMetricEnrollmentNetworkFailed);
    130       LOG(WARNING) << "Network error " << error.state();
    131       return;
    132     case GoogleServiceAuthError::NUM_STATES:
    133       break;
    134   }
    135 
    136   NOTREACHED();
    137   UMAFailure(policy::kMetricEnrollmentOtherFailed);
    138 }
    139 
    140 void EnrollmentScreen::OnOAuthTokenAvailable(
    141     const std::string& token) {
    142   RegisterForDevicePolicy(token);
    143 }
    144 
    145 void EnrollmentScreen::OnRetry() {
    146   actor_->ResetAuth(base::Bind(&EnrollmentScreen::ShowSigninScreen,
    147                                weak_ptr_factory_.GetWeakPtr()));
    148 }
    149 
    150 void EnrollmentScreen::OnCancel() {
    151   if (!can_exit_enrollment_) {
    152     NOTREACHED() << "Cancellation should not be permitted";
    153     return;
    154   }
    155 
    156   if (is_auto_enrollment_)
    157     policy::AutoEnrollmentClient::CancelAutoEnrollment();
    158   UMA(is_auto_enrollment_ ? policy::kMetricEnrollmentAutoCancelled
    159                           : policy::kMetricEnrollmentCancelled);
    160   actor_->ResetAuth(
    161       base::Bind(&ScreenObserver::OnExit,
    162                  base::Unretained(get_screen_observer()),
    163                  ScreenObserver::ENTERPRISE_ENROLLMENT_COMPLETED));
    164 }
    165 
    166 void EnrollmentScreen::OnConfirmationClosed() {
    167   // If the machine has been put in KIOSK mode we have to restart the session
    168   // here to go in the proper KIOSK mode login screen.
    169   if (g_browser_process->browser_policy_connector()->GetDeviceMode() ==
    170           policy::DEVICE_MODE_RETAIL_KIOSK) {
    171     DBusThreadManager::Get()->GetSessionManagerClient()->StopSession();
    172     return;
    173   }
    174 
    175   if (is_auto_enrollment_ &&
    176       !enrollment_failed_once_ &&
    177       !user_.empty() &&
    178       LoginUtils::IsWhitelisted(user_)) {
    179     actor_->ShowLoginSpinnerScreen();
    180     get_screen_observer()->OnExit(
    181         ScreenObserver::ENTERPRISE_AUTO_MAGIC_ENROLLMENT_COMPLETED);
    182   } else {
    183     actor_->ResetAuth(
    184         base::Bind(&ScreenObserver::OnExit,
    185                    base::Unretained(get_screen_observer()),
    186                    ScreenObserver::ENTERPRISE_ENROLLMENT_COMPLETED));
    187   }
    188 }
    189 
    190 void EnrollmentScreen::RegisterForDevicePolicy(
    191     const std::string& token) {
    192   policy::BrowserPolicyConnector* connector =
    193       g_browser_process->browser_policy_connector();
    194   if (connector->IsEnterpriseManaged() &&
    195       connector->GetEnterpriseDomain() != gaia::ExtractDomainName(user_)) {
    196     LOG(ERROR) << "Trying to re-enroll to a different domain than "
    197                << connector->GetEnterpriseDomain();
    198     UMAFailure(policy::kMetricEnrollmentWrongUserError);
    199     actor_->ShowUIError(
    200         EnrollmentScreenActor::UI_ERROR_DOMAIN_MISMATCH);
    201     return;
    202   }
    203 
    204   policy::DeviceCloudPolicyManagerChromeOS::AllowedDeviceModes modes;
    205   modes[policy::DEVICE_MODE_ENTERPRISE] = true;
    206   modes[policy::DEVICE_MODE_RETAIL_KIOSK] = !is_auto_enrollment_;
    207   connector->ScheduleServiceInitialization(0);
    208   connector->GetDeviceCloudPolicyManager()->StartEnrollment(
    209       token, is_auto_enrollment_, modes,
    210       base::Bind(&EnrollmentScreen::ReportEnrollmentStatus,
    211                  weak_ptr_factory_.GetWeakPtr()));
    212 }
    213 
    214 void EnrollmentScreen::ReportEnrollmentStatus(
    215     policy::EnrollmentStatus status) {
    216   bool success = status.status() == policy::EnrollmentStatus::STATUS_SUCCESS;
    217   enrollment_failed_once_ |= !success;
    218   actor_->ShowEnrollmentStatus(status);
    219 
    220   switch (status.status()) {
    221     case policy::EnrollmentStatus::STATUS_SUCCESS:
    222       StartupUtils::MarkDeviceRegistered();
    223       UMA(is_auto_enrollment_ ? policy::kMetricEnrollmentAutoOK
    224                               : policy::kMetricEnrollmentOK);
    225       return;
    226     case policy::EnrollmentStatus::STATUS_REGISTRATION_FAILED:
    227     case policy::EnrollmentStatus::STATUS_POLICY_FETCH_FAILED:
    228       switch (status.client_status()) {
    229         case policy::DM_STATUS_SUCCESS:
    230         case policy::DM_STATUS_REQUEST_INVALID:
    231         case policy::DM_STATUS_SERVICE_DEVICE_NOT_FOUND:
    232         case policy::DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID:
    233         case policy::DM_STATUS_SERVICE_ACTIVATION_PENDING:
    234         case policy::DM_STATUS_SERVICE_DEVICE_ID_CONFLICT:
    235         case policy::DM_STATUS_SERVICE_POLICY_NOT_FOUND:
    236           UMAFailure(policy::kMetricEnrollmentOtherFailed);
    237           return;
    238         case policy::DM_STATUS_REQUEST_FAILED:
    239         case policy::DM_STATUS_TEMPORARY_UNAVAILABLE:
    240         case policy::DM_STATUS_HTTP_STATUS_ERROR:
    241         case policy::DM_STATUS_RESPONSE_DECODING_ERROR:
    242           UMAFailure(policy::kMetricEnrollmentNetworkFailed);
    243           return;
    244         case policy::DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED:
    245           UMAFailure(policy::kMetricEnrollmentNotSupported);
    246           return;
    247         case policy::DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER:
    248           UMAFailure(policy::kMetricEnrollmentInvalidSerialNumber);
    249           return;
    250         case policy::DM_STATUS_SERVICE_MISSING_LICENSES:
    251           UMAFailure(policy::kMetricMissingLicensesError);
    252           return;
    253       }
    254       break;
    255     case policy::EnrollmentStatus::STATUS_REGISTRATION_BAD_MODE:
    256       UMAFailure(policy::kMetricEnrollmentInvalidEnrollmentMode);
    257       return;
    258     case policy::EnrollmentStatus::STATUS_LOCK_TIMEOUT:
    259       UMAFailure(policy::kMetricLockboxTimeoutError);
    260       return;
    261     case policy::EnrollmentStatus::STATUS_LOCK_WRONG_USER:
    262       UMAFailure(policy::kMetricEnrollmentWrongUserError);
    263       return;
    264     case policy::EnrollmentStatus::STATUS_VALIDATION_FAILED:
    265     case policy::EnrollmentStatus::STATUS_STORE_ERROR:
    266     case policy::EnrollmentStatus::STATUS_LOCK_ERROR:
    267       UMAFailure(policy::kMetricEnrollmentOtherFailed);
    268       return;
    269   }
    270 
    271   NOTREACHED();
    272   UMAFailure(policy::kMetricEnrollmentOtherFailed);
    273 }
    274 
    275 void EnrollmentScreen::UMAFailure(int sample) {
    276   if (is_auto_enrollment_)
    277     sample = policy::kMetricEnrollmentAutoFailed;
    278   UMA(sample);
    279 }
    280 
    281 void EnrollmentScreen::ShowSigninScreen() {
    282   actor_->Show();
    283   actor_->ShowSigninScreen();
    284 }
    285 
    286 }  // namespace chromeos
    287