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