enrollment_handler_chromeos.cc revision effb81e5f8246d0db0270817048dc992db66e9fb
10d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin// Copyright (c) 2012 The Chromium Authors. All rights reserved.
20d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin// Use of this source code is governed by a BSD-style license that can be
30d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin// found in the LICENSE file.
40d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
50d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin#include "chrome/browser/chromeos/policy/enrollment_handler_chromeos.h"
60d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
70d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin#include "base/bind.h"
80d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin#include "base/command_line.h"
90d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin#include "base/logging.h"
100d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin#include "base/message_loop/message_loop.h"
110d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin#include "chrome/browser/browser_process.h"
120d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin#include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
130d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin#include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
140d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin#include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
150d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin#include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
160d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin#include "chromeos/chromeos_switches.h"
170d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin#include "components/policy/core/common/cloud/cloud_policy_constants.h"
180d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin#include "google_apis/gaia/gaia_urls.h"
190d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin#include "net/http/http_status_code.h"
200d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin#include "policy/proto/device_management_backend.pb.h"
210d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
220d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkinnamespace em = enterprise_management;
230d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
240d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkinnamespace policy {
250d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
260d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkinnamespace {
270d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
280d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin// Retry for InstallAttrs initialization every 500ms.
290d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkinconst int kLockRetryIntervalMs = 500;
300d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin// Maximum time to retry InstallAttrs initialization before we give up.
310d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkinconst int kLockRetryTimeoutMs = 10 * 60 * 1000;  // 10 minutes.
320d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
330d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin// Testing token used when the enrollment-skip-robot-auth is set to skip talking
340d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin// to GAIA for an actual token. This is needed to be able to run against the
350d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin// testing DMServer implementations.
360d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkinconst char kTestingRobotToken[] = "test-token";
370d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
380d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin}  // namespace
390d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
400d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander GutkinEnrollmentHandlerChromeOS::EnrollmentHandlerChromeOS(
410d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    DeviceCloudPolicyStoreChromeOS* store,
420d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    EnterpriseInstallAttributes* install_attributes,
430d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    scoped_ptr<CloudPolicyClient> client,
440d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    scoped_refptr<base::SequencedTaskRunner> background_task_runner,
450d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    const std::string& auth_token,
460d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    const std::string& client_id,
470d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    bool is_auto_enrollment,
480d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    const std::string& requisition,
490d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    const std::string& current_state_key,
500d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    const AllowedDeviceModes& allowed_device_modes,
510d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    const EnrollmentCallback& completion_callback)
520d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    : store_(store),
530d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      install_attributes_(install_attributes),
540d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      client_(client.Pass()),
550d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      background_task_runner_(background_task_runner),
560d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      auth_token_(auth_token),
570d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      client_id_(client_id),
580d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      is_auto_enrollment_(is_auto_enrollment),
590d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      requisition_(requisition),
600d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      current_state_key_(current_state_key),
610d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      allowed_device_modes_(allowed_device_modes),
620d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      completion_callback_(completion_callback),
630d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      device_mode_(DEVICE_MODE_NOT_SET),
640d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      enrollment_step_(STEP_PENDING),
650d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      lockbox_init_duration_(0),
660d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      weak_ptr_factory_(this) {
670d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  CHECK(!client_->is_registered());
680d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  CHECK_EQ(DM_STATUS_SUCCESS, client_->status());
690d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  store_->AddObserver(this);
700d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  client_->AddObserver(this);
710d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  client_->AddNamespaceToFetch(PolicyNamespaceKey(
720d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      dm_protocol::kChromeDevicePolicyType, std::string()));
730d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin}
740d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
750d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander GutkinEnrollmentHandlerChromeOS::~EnrollmentHandlerChromeOS() {
760d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  Stop();
770d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  store_->RemoveObserver(this);
780d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin}
790d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
800d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkinvoid EnrollmentHandlerChromeOS::StartEnrollment() {
810d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  CHECK_EQ(STEP_PENDING, enrollment_step_);
820d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  enrollment_step_ = STEP_LOADING_STORE;
830d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  AttemptRegistration();
840d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin}
850d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
860d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkinscoped_ptr<CloudPolicyClient> EnrollmentHandlerChromeOS::ReleaseClient() {
870d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  Stop();
880d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  return client_.Pass();
890d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin}
900d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
910d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkinvoid EnrollmentHandlerChromeOS::OnPolicyFetched(CloudPolicyClient* client) {
920d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  DCHECK_EQ(client_.get(), client);
930d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  CHECK_EQ(STEP_POLICY_FETCH, enrollment_step_);
940d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
950d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  enrollment_step_ = STEP_VALIDATION;
960d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
970d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  // Validate the policy.
980d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  const em::PolicyFetchResponse* policy = client_->GetPolicyFor(
990d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      PolicyNamespaceKey(dm_protocol::kChromeDevicePolicyType, std::string()));
1000d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  if (!policy) {
1010d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    ReportResult(EnrollmentStatus::ForFetchError(
1020d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin        DM_STATUS_RESPONSE_DECODING_ERROR));
1030d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    return;
1040d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  }
1050d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
1060d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  scoped_ptr<DeviceCloudPolicyValidator> validator(
1070d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      DeviceCloudPolicyValidator::Create(
1080d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin          scoped_ptr<em::PolicyFetchResponse>(
1090d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin              new em::PolicyFetchResponse(*policy)),
1100d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin          background_task_runner_));
1110d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
1120d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  validator->ValidateTimestamp(base::Time(), base::Time::NowFromSystemTime(),
1130d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin                               CloudPolicyValidatorBase::TIMESTAMP_REQUIRED);
1140d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
1150d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  // If this is re-enrollment, make sure that the new policy matches the
1160d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  // previously-enrolled domain.
1170d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  std::string domain;
1180d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  if (install_attributes_->IsEnterpriseDevice()) {
1190d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    domain = install_attributes_->GetDomain();
1200d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    validator->ValidateDomain(domain);
1210d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  }
1220d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  validator->ValidateDMToken(client->dm_token(),
1230d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin                             CloudPolicyValidatorBase::DM_TOKEN_REQUIRED);
1240d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  validator->ValidatePolicyType(dm_protocol::kChromeDevicePolicyType);
1250d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  validator->ValidatePayload();
1260d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  // If |domain| is empty here, the policy validation code will just use the
1270d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  // domain from the username field in the policy itself to do key validation.
1280d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  // TODO(mnissler): Plumb the enrolling user's username into this object so
1290d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  // we can validate the username on the resulting policy, and use the domain
1300d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  // from that username to validate the key below (http://crbug.com/343074).
1310d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  validator->ValidateInitialKey(GetPolicyVerificationKey(), domain);
1320d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  validator.release()->StartValidation(
1330d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      base::Bind(&EnrollmentHandlerChromeOS::PolicyValidated,
1340d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin                 weak_ptr_factory_.GetWeakPtr()));
1350d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin}
1360d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
1370d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkinvoid EnrollmentHandlerChromeOS::OnRegistrationStateChanged(
1380d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    CloudPolicyClient* client) {
1390d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  DCHECK_EQ(client_.get(), client);
1400d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
1410d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  if (enrollment_step_ == STEP_REGISTRATION && client_->is_registered()) {
1420d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    enrollment_step_ = STEP_POLICY_FETCH,
1430d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    device_mode_ = client_->device_mode();
1440d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    if (device_mode_ == DEVICE_MODE_NOT_SET)
1450d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      device_mode_ = DEVICE_MODE_ENTERPRISE;
1460d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    if (!allowed_device_modes_.test(device_mode_)) {
1470d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      LOG(ERROR) << "Bad device mode " << device_mode_;
1480d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      ReportResult(EnrollmentStatus::ForStatus(
1490d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin          EnrollmentStatus::STATUS_REGISTRATION_BAD_MODE));
1500d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      return;
1510d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    }
1520d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    client_->FetchPolicy();
1530d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  } else {
1540d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    LOG(FATAL) << "Registration state changed to " << client_->is_registered()
1550d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin               << " in step " << enrollment_step_;
1560d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  }
1570d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin}
1580d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
1590d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkinvoid EnrollmentHandlerChromeOS::OnClientError(CloudPolicyClient* client) {
1600d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  DCHECK_EQ(client_.get(), client);
1610d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
1620d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  if (enrollment_step_ == STEP_ROBOT_AUTH_FETCH) {
1630d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    LOG(ERROR) << "API authentication code fetch failed: "
1640d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin               << client_->status();
1650d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    ReportResult(EnrollmentStatus::ForRobotAuthFetchError(client_->status()));
1660d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  } else if (enrollment_step_ < STEP_POLICY_FETCH) {
1670d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    ReportResult(EnrollmentStatus::ForRegistrationError(client_->status()));
1680d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  } else {
1690d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    ReportResult(EnrollmentStatus::ForFetchError(client_->status()));
1700d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  }
1710d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin}
1720d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
1730d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkinvoid EnrollmentHandlerChromeOS::OnStoreLoaded(CloudPolicyStore* store) {
1740d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  DCHECK_EQ(store_, store);
1750d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
1760d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  if (enrollment_step_ == STEP_LOADING_STORE) {
1770d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    // If the |store_| wasn't initialized when StartEnrollment() was
1780d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    // called, then AttemptRegistration() bails silently.  This gets
1790d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    // registration rolling again after the store finishes loading.
1800d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    AttemptRegistration();
1810d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  } else if (enrollment_step_ == STEP_STORE_POLICY) {
1820d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    ReportResult(EnrollmentStatus::ForStatus(EnrollmentStatus::STATUS_SUCCESS));
1830d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  }
1840d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin}
1850d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
1860d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkinvoid EnrollmentHandlerChromeOS::OnStoreError(CloudPolicyStore* store) {
1870d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  DCHECK_EQ(store_, store);
1880d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  ReportResult(EnrollmentStatus::ForStoreError(store_->status(),
1890d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin                                               store_->validation_status()));
1900d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin}
1910d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
1920d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkinvoid EnrollmentHandlerChromeOS::AttemptRegistration() {
1930d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  CHECK_EQ(STEP_LOADING_STORE, enrollment_step_);
1940d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  if (store_->is_initialized()) {
1950d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    enrollment_step_ = STEP_REGISTRATION;
1960d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    client_->Register(em::DeviceRegisterRequest::DEVICE,
1970d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin                      auth_token_, client_id_, is_auto_enrollment_,
1980d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin                      requisition_, current_state_key_);
1990d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  }
2000d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin}
2010d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
2020d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkinvoid EnrollmentHandlerChromeOS::PolicyValidated(
2030d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    DeviceCloudPolicyValidator* validator) {
2040d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  CHECK_EQ(STEP_VALIDATION, enrollment_step_);
2050d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  if (validator->success()) {
2060d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    policy_ = validator->policy().Pass();
2070d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    username_ = validator->policy_data()->username();
2080d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    device_id_ = validator->policy_data()->device_id();
2090d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
2100d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    if (CommandLine::ForCurrentProcess()->HasSwitch(
2110d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin            chromeos::switches::kEnterpriseEnrollmentSkipRobotAuth)) {
2120d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      // For test purposes we allow enrollment to succeed without proper robot
2130d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      // account and use the provided value as a token.
2140d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      refresh_token_ = kTestingRobotToken;
2150d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      enrollment_step_ = STEP_LOCK_DEVICE,
2160d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      StartLockDevice(username_, device_mode_, device_id_);
2170d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      return;
2180d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    }
2190d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
2200d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    enrollment_step_ = STEP_ROBOT_AUTH_FETCH;
2210d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    client_->FetchRobotAuthCodes(auth_token_);
2220d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  } else {
2230d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    ReportResult(EnrollmentStatus::ForValidationError(validator->status()));
2240d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  }
2250d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin}
2260d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
2270d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkinvoid EnrollmentHandlerChromeOS::OnRobotAuthCodesFetched(
2280d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin    CloudPolicyClient* client) {
2290d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  DCHECK_EQ(client_.get(), client);
2300d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  CHECK_EQ(STEP_ROBOT_AUTH_FETCH, enrollment_step_);
2310d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
2320d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  enrollment_step_ = STEP_ROBOT_AUTH_REFRESH;
2330d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
2340d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  gaia::OAuthClientInfo client_info;
2350d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  client_info.client_id = GaiaUrls::GetInstance()->oauth2_chrome_client_id();
2360d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  client_info.client_secret =
2370d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin      GaiaUrls::GetInstance()->oauth2_chrome_client_secret();
2380d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  client_info.redirect_uri = "oob";
2390d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin
2400d4c52358a1af421705c54bd8a9fdd8a30558a2eAlexander Gutkin  // Use the system request context to avoid sending user cookies.
241  gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(
242      g_browser_process->system_request_context()));
243  gaia_oauth_client_->GetTokensFromAuthCode(client_info,
244                                            client->robot_api_auth_code(),
245                                            0 /* max_retries */,
246                                            this);
247}
248
249// GaiaOAuthClient::Delegate callback for OAuth2 refresh token fetched.
250void EnrollmentHandlerChromeOS::OnGetTokensResponse(
251    const std::string& refresh_token,
252    const std::string& access_token,
253    int expires_in_seconds) {
254  CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_);
255
256  refresh_token_ = refresh_token;
257
258  enrollment_step_ = STEP_LOCK_DEVICE,
259  StartLockDevice(username_, device_mode_, device_id_);
260}
261
262// GaiaOAuthClient::Delegate
263void EnrollmentHandlerChromeOS::OnRefreshTokenResponse(
264    const std::string& access_token,
265    int expires_in_seconds) {
266  // We never use the code that should trigger this callback.
267  LOG(FATAL) << "Unexpected callback invoked";
268}
269
270// GaiaOAuthClient::Delegate OAuth2 error when fetching refresh token request.
271void EnrollmentHandlerChromeOS::OnOAuthError() {
272  CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_);
273  // OnOAuthError is only called if the request is bad (malformed) or the
274  // response is bad (empty access token returned).
275  LOG(ERROR) << "OAuth protocol error while fetching API refresh token.";
276  ReportResult(
277      EnrollmentStatus::ForRobotRefreshFetchError(net::HTTP_BAD_REQUEST));
278}
279
280// GaiaOAuthClient::Delegate network error when fetching refresh token.
281void EnrollmentHandlerChromeOS::OnNetworkError(int response_code) {
282  CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_);
283  LOG(ERROR) << "Network error while fetching API refresh token: "
284             << response_code;
285  ReportResult(
286      EnrollmentStatus::ForRobotRefreshFetchError(response_code));
287}
288
289void EnrollmentHandlerChromeOS::StartLockDevice(
290    const std::string& user,
291    DeviceMode device_mode,
292    const std::string& device_id) {
293  CHECK_EQ(STEP_LOCK_DEVICE, enrollment_step_);
294  // Since this method is also called directly.
295  weak_ptr_factory_.InvalidateWeakPtrs();
296
297  install_attributes_->LockDevice(
298      user, device_mode, device_id,
299      base::Bind(&EnrollmentHandlerChromeOS::HandleLockDeviceResult,
300                 weak_ptr_factory_.GetWeakPtr(),
301                 user,
302                 device_mode,
303                 device_id));
304}
305
306void EnrollmentHandlerChromeOS::HandleLockDeviceResult(
307    const std::string& user,
308    DeviceMode device_mode,
309    const std::string& device_id,
310    EnterpriseInstallAttributes::LockResult lock_result) {
311  CHECK_EQ(STEP_LOCK_DEVICE, enrollment_step_);
312  switch (lock_result) {
313    case EnterpriseInstallAttributes::LOCK_SUCCESS:
314      // Get the token service so we can store our robot refresh token.
315      enrollment_step_ = STEP_STORE_ROBOT_AUTH;
316      chromeos::DeviceOAuth2TokenServiceFactory::Get()->SetAndSaveRefreshToken(
317          refresh_token_,
318          base::Bind(&EnrollmentHandlerChromeOS::HandleRobotAuthTokenStored,
319                     weak_ptr_factory_.GetWeakPtr()));
320      return;
321    case EnterpriseInstallAttributes::LOCK_NOT_READY:
322      // We wait up to |kLockRetryTimeoutMs| milliseconds and if it hasn't
323      // succeeded by then show an error to the user and stop the enrollment.
324      if (lockbox_init_duration_ < kLockRetryTimeoutMs) {
325        // InstallAttributes not ready yet, retry later.
326        LOG(WARNING) << "Install Attributes not ready yet will retry in "
327                     << kLockRetryIntervalMs << "ms.";
328        base::MessageLoop::current()->PostDelayedTask(
329            FROM_HERE,
330            base::Bind(&EnrollmentHandlerChromeOS::StartLockDevice,
331                       weak_ptr_factory_.GetWeakPtr(),
332                       user, device_mode, device_id),
333            base::TimeDelta::FromMilliseconds(kLockRetryIntervalMs));
334        lockbox_init_duration_ += kLockRetryIntervalMs;
335      } else {
336        ReportResult(EnrollmentStatus::ForStatus(
337            EnrollmentStatus::STATUS_LOCK_TIMEOUT));
338      }
339      return;
340    case EnterpriseInstallAttributes::LOCK_BACKEND_ERROR:
341      ReportResult(EnrollmentStatus::ForStatus(
342          EnrollmentStatus::STATUS_LOCK_ERROR));
343      return;
344    case EnterpriseInstallAttributes::LOCK_WRONG_USER:
345      LOG(ERROR) << "Enrollment cannot proceed because the InstallAttrs "
346                 << "has been locked already!";
347      ReportResult(EnrollmentStatus::ForStatus(
348          EnrollmentStatus::STATUS_LOCK_WRONG_USER));
349      return;
350  }
351
352  NOTREACHED() << "Invalid lock result " << lock_result;
353  ReportResult(EnrollmentStatus::ForStatus(
354      EnrollmentStatus::STATUS_LOCK_ERROR));
355}
356
357void EnrollmentHandlerChromeOS::HandleRobotAuthTokenStored(bool result) {
358  CHECK_EQ(STEP_STORE_ROBOT_AUTH, enrollment_step_);
359
360  if (!result) {
361    LOG(ERROR) << "Failed to store API refresh token.";
362    ReportResult(EnrollmentStatus::ForStatus(
363        EnrollmentStatus::STATUS_ROBOT_REFRESH_STORE_FAILED));
364    return;
365  }
366
367  enrollment_step_ = STEP_STORE_POLICY;
368  store_->InstallInitialPolicy(*policy_);
369}
370
371void EnrollmentHandlerChromeOS::Stop() {
372  if (client_.get())
373    client_->RemoveObserver(this);
374  enrollment_step_ = STEP_FINISHED;
375  weak_ptr_factory_.InvalidateWeakPtrs();
376  completion_callback_.Reset();
377}
378
379void EnrollmentHandlerChromeOS::ReportResult(EnrollmentStatus status) {
380  EnrollmentCallback callback = completion_callback_;
381  Stop();
382
383  if (status.status() != EnrollmentStatus::STATUS_SUCCESS) {
384    LOG(WARNING) << "Enrollment failed: " << status.status()
385                 << " " << status.client_status()
386                 << " " << status.validation_status()
387                 << " " << status.store_status();
388  }
389
390  if (!callback.is_null())
391    callback.Run(status);
392}
393
394}  // namespace policy
395