enrollment_screen.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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_method_call_status.h"
23#include "chromeos/dbus/dbus_thread_manager.h"
24#include "chromeos/dbus/session_manager_client.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    NOTREACHED() << "Cancellation should not be permitted";
151    return;
152  }
153
154  if (is_auto_enrollment_)
155    policy::AutoEnrollmentClient::CancelAutoEnrollment();
156  UMA(is_auto_enrollment_ ? policy::kMetricEnrollmentAutoCancelled
157                          : policy::kMetricEnrollmentCancelled);
158  actor_->ResetAuth(
159      base::Bind(&ScreenObserver::OnExit,
160                 base::Unretained(get_screen_observer()),
161                 ScreenObserver::ENTERPRISE_ENROLLMENT_COMPLETED));
162}
163
164void EnrollmentScreen::OnConfirmationClosed() {
165  // If the machine has been put in KIOSK mode we have to restart the session
166  // here to go in the proper KIOSK mode login screen.
167  if (g_browser_process->browser_policy_connector()->GetDeviceMode() ==
168          policy::DEVICE_MODE_RETAIL_KIOSK) {
169    DBusThreadManager::Get()->GetSessionManagerClient()->StopSession();
170    return;
171  }
172
173  if (is_auto_enrollment_ &&
174      !enrollment_failed_once_ &&
175      !user_.empty() &&
176      LoginUtils::IsWhitelisted(user_)) {
177    actor_->ShowLoginSpinnerScreen();
178    get_screen_observer()->OnExit(
179        ScreenObserver::ENTERPRISE_AUTO_MAGIC_ENROLLMENT_COMPLETED);
180  } else {
181    actor_->ResetAuth(
182        base::Bind(&ScreenObserver::OnExit,
183                   base::Unretained(get_screen_observer()),
184                   ScreenObserver::ENTERPRISE_ENROLLMENT_COMPLETED));
185  }
186}
187
188void EnrollmentScreen::RegisterForDevicePolicy(
189    const std::string& token) {
190  policy::BrowserPolicyConnector* connector =
191      g_browser_process->browser_policy_connector();
192  if (connector->IsEnterpriseManaged() &&
193      connector->GetEnterpriseDomain() != gaia::ExtractDomainName(user_)) {
194    LOG(ERROR) << "Trying to re-enroll to a different domain than "
195               << connector->GetEnterpriseDomain();
196    UMAFailure(policy::kMetricEnrollmentWrongUserError);
197    actor_->ShowUIError(
198        EnrollmentScreenActor::UI_ERROR_DOMAIN_MISMATCH);
199    return;
200  }
201
202  policy::DeviceCloudPolicyManagerChromeOS::AllowedDeviceModes modes;
203  modes[policy::DEVICE_MODE_ENTERPRISE] = true;
204  modes[policy::DEVICE_MODE_RETAIL_KIOSK] = !is_auto_enrollment_;
205  connector->ScheduleServiceInitialization(0);
206  connector->GetDeviceCloudPolicyManager()->StartEnrollment(
207      token, is_auto_enrollment_, modes,
208      base::Bind(&EnrollmentScreen::ReportEnrollmentStatus,
209                 weak_ptr_factory_.GetWeakPtr()));
210}
211
212void EnrollmentScreen::ReportEnrollmentStatus(
213    policy::EnrollmentStatus status) {
214  bool success = status.status() == policy::EnrollmentStatus::STATUS_SUCCESS;
215  enrollment_failed_once_ |= !success;
216  actor_->ShowEnrollmentStatus(status);
217
218  switch (status.status()) {
219    case policy::EnrollmentStatus::STATUS_SUCCESS:
220      StartupUtils::MarkDeviceRegistered();
221      UMA(is_auto_enrollment_ ? policy::kMetricEnrollmentAutoOK
222                              : policy::kMetricEnrollmentOK);
223      return;
224    case policy::EnrollmentStatus::STATUS_REGISTRATION_FAILED:
225    case policy::EnrollmentStatus::STATUS_POLICY_FETCH_FAILED:
226      switch (status.client_status()) {
227        case policy::DM_STATUS_SUCCESS:
228        case policy::DM_STATUS_REQUEST_INVALID:
229        case policy::DM_STATUS_SERVICE_DEVICE_NOT_FOUND:
230        case policy::DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID:
231        case policy::DM_STATUS_SERVICE_ACTIVATION_PENDING:
232        case policy::DM_STATUS_SERVICE_DEVICE_ID_CONFLICT:
233        case policy::DM_STATUS_SERVICE_POLICY_NOT_FOUND:
234          UMAFailure(policy::kMetricEnrollmentOtherFailed);
235          return;
236        case policy::DM_STATUS_REQUEST_FAILED:
237        case policy::DM_STATUS_TEMPORARY_UNAVAILABLE:
238        case policy::DM_STATUS_HTTP_STATUS_ERROR:
239        case policy::DM_STATUS_RESPONSE_DECODING_ERROR:
240          UMAFailure(policy::kMetricEnrollmentNetworkFailed);
241          return;
242        case policy::DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED:
243          UMAFailure(policy::kMetricEnrollmentNotSupported);
244          return;
245        case policy::DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER:
246          UMAFailure(policy::kMetricEnrollmentInvalidSerialNumber);
247          return;
248        case policy::DM_STATUS_SERVICE_MISSING_LICENSES:
249          UMAFailure(policy::kMetricMissingLicensesError);
250          return;
251      }
252      break;
253    case policy::EnrollmentStatus::STATUS_REGISTRATION_BAD_MODE:
254      UMAFailure(policy::kMetricEnrollmentInvalidEnrollmentMode);
255      return;
256    case policy::EnrollmentStatus::STATUS_LOCK_TIMEOUT:
257      UMAFailure(policy::kMetricLockboxTimeoutError);
258      return;
259    case policy::EnrollmentStatus::STATUS_LOCK_WRONG_USER:
260      UMAFailure(policy::kMetricEnrollmentWrongUserError);
261      return;
262    case policy::EnrollmentStatus::STATUS_VALIDATION_FAILED:
263    case policy::EnrollmentStatus::STATUS_STORE_ERROR:
264    case policy::EnrollmentStatus::STATUS_LOCK_ERROR:
265      UMAFailure(policy::kMetricEnrollmentOtherFailed);
266      return;
267  }
268
269  NOTREACHED();
270  UMAFailure(policy::kMetricEnrollmentOtherFailed);
271}
272
273void EnrollmentScreen::UMAFailure(int sample) {
274  if (is_auto_enrollment_)
275    sample = policy::kMetricEnrollmentAutoFailed;
276  UMA(sample);
277}
278
279void EnrollmentScreen::ShowSigninScreen() {
280  actor_->Show();
281  actor_->ShowSigninScreen();
282}
283
284}  // namespace chromeos
285