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