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
Get(ScreenManager * manager)50 EnrollmentScreen* EnrollmentScreen::Get(ScreenManager* manager) {
51 return static_cast<EnrollmentScreen*>(
52 manager->GetScreen(WizardController::kEnrollmentScreenName));
53 }
54
EnrollmentScreen(ScreenObserver * observer,EnrollmentScreenActor * actor)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
~EnrollmentScreen()73 EnrollmentScreen::~EnrollmentScreen() {
74 if (remora_controller_)
75 remora_controller_->RemoveObserver(this);
76 }
77
SetParameters(EnrollmentScreenActor::EnrollmentMode enrollment_mode,const std::string & management_domain,const std::string & user,const std::string & auth_token,pairing_chromeos::ControllerPairingController * shark_controller,pairing_chromeos::HostPairingController * remora_controller)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
PrepareToShow()97 void EnrollmentScreen::PrepareToShow() {
98 actor_->PrepareToShow();
99 }
100
Show()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
Hide()118 void EnrollmentScreen::Hide() {
119 actor_->Hide();
120 weak_ptr_factory_.InvalidateWeakPtrs();
121 }
122
GetName() const123 std::string EnrollmentScreen::GetName() const {
124 return WizardController::kEnrollmentScreenName;
125 }
126
PairingStageChanged(Stage new_stage)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
ConfigureHost(bool accepted_eula,const std::string & lang,const std::string & timezone,bool send_reports,const std::string & keyboard_layout)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
EnrollHost(const std::string & auth_token)145 void EnrollmentScreen::EnrollHost(const std::string& auth_token) {
146 }
147
OnLoginDone(const std::string & user)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
OnAuthError(const GoogleServiceAuthError & error)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
OnOAuthTokenAvailable(const std::string & token)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
OnRetry()218 void EnrollmentScreen::OnRetry() {
219 actor_->ResetAuth(base::Bind(&EnrollmentScreen::ShowSigninScreen,
220 weak_ptr_factory_.GetWeakPtr()));
221 }
222
OnCancel()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
OnConfirmationClosed()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
RegisterForDevicePolicy(const std::string & token)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
SendEnrollmentAuthToken(const std::string & token)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
ShowEnrollmentStatusOnSuccess(const policy::EnrollmentStatus & status)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
ReportEnrollmentStatus(policy::EnrollmentStatus status)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
UMA(policy::MetricEnrollment sample)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
UMAFailure(policy::MetricEnrollment sample)443 void EnrollmentScreen::UMAFailure(policy::MetricEnrollment sample) {
444 if (is_auto_enrollment())
445 sample = policy::kMetricEnrollmentAutoFailed;
446 UMA(sample);
447 }
448
ShowSigninScreen()449 void EnrollmentScreen::ShowSigninScreen() {
450 actor_->Show();
451 actor_->ShowSigninScreen();
452 }
453
454 } // namespace chromeos
455