enrollment_handler_chromeos.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/policy/enrollment_handler_chromeos.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
99ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/browser_process.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "google_apis/gaia/gaia_urls.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace em = enterprise_management;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace policy {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Retry for InstallAttrs initialization every 500ms.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kLockRetryIntervalMs = 500;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum time to retry InstallAttrs initialization before we give up.
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kLockRetryTimeoutMs = 10 * 60 * 1000;  // 10 minutes.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EnrollmentHandlerChromeOS::EnrollmentHandlerChromeOS(
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DeviceCloudPolicyStoreChromeOS* store,
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EnterpriseInstallAttributes* install_attributes,
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<CloudPolicyClient> client,
368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> background_task_runner,
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& auth_token,
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& client_id,
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool is_auto_enrollment,
4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& requisition,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AllowedDeviceModes& allowed_device_modes,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const EnrollmentCallback& completion_callback)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : store_(store),
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      install_attributes_(install_attributes),
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      client_(client.Pass()),
468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      background_task_runner_(background_task_runner),
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      auth_token_(auth_token),
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      client_id_(client_id),
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      is_auto_enrollment_(is_auto_enrollment),
5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      requisition_(requisition),
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      allowed_device_modes_(allowed_device_modes),
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      completion_callback_(completion_callback),
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      device_mode_(DEVICE_MODE_NOT_SET),
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      enrollment_step_(STEP_PENDING),
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      lockbox_init_duration_(0),
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_factory_(this) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!client_->is_registered());
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(DM_STATUS_SUCCESS, client_->status());
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  store_->AddObserver(this);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  client_->AddObserver(this);
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  client_->AddNamespaceToFetch(PolicyNamespaceKey(
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      dm_protocol::kChromeDevicePolicyType, std::string()));
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EnrollmentHandlerChromeOS::~EnrollmentHandlerChromeOS() {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Stop();
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  store_->RemoveObserver(this);
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EnrollmentHandlerChromeOS::StartEnrollment() {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(STEP_PENDING, enrollment_step_);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enrollment_step_ = STEP_LOADING_STORE;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AttemptRegistration();
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<CloudPolicyClient> EnrollmentHandlerChromeOS::ReleaseClient() {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Stop();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return client_.Pass();
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EnrollmentHandlerChromeOS::OnPolicyFetched(CloudPolicyClient* client) {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(client_.get(), client);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(STEP_POLICY_FETCH, enrollment_step_);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enrollment_step_ = STEP_VALIDATION;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Validate the policy.
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const em::PolicyFetchResponse* policy = client_->GetPolicyFor(
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      PolicyNamespaceKey(dm_protocol::kChromeDevicePolicyType, std::string()));
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!policy) {
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ReportResult(EnrollmentStatus::ForFetchError(
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        DM_STATUS_RESPONSE_DECODING_ERROR));
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<DeviceCloudPolicyValidator> validator(
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DeviceCloudPolicyValidator::Create(
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          scoped_ptr<em::PolicyFetchResponse>(
998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)              new em::PolicyFetchResponse(*policy)),
1008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          background_task_runner_));
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  validator->ValidateTimestamp(base::Time(), base::Time::NowFromSystemTime(),
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               CloudPolicyValidatorBase::TIMESTAMP_REQUIRED);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (install_attributes_->IsEnterpriseDevice())
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    validator->ValidateDomain(install_attributes_->GetDomain());
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  validator->ValidateDMToken(client->dm_token(),
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             CloudPolicyValidatorBase::DM_TOKEN_REQUIRED);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  validator->ValidatePolicyType(dm_protocol::kChromeDevicePolicyType);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  validator->ValidatePayload();
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  validator->ValidateInitialKey();
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  validator.release()->StartValidation(
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&EnrollmentHandlerChromeOS::PolicyValidated,
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 weak_factory_.GetWeakPtr()));
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EnrollmentHandlerChromeOS::OnRegistrationStateChanged(
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloudPolicyClient* client) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(client_.get(), client);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (enrollment_step_ == STEP_REGISTRATION && client_->is_registered()) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    enrollment_step_ = STEP_POLICY_FETCH,
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    device_mode_ = client_->device_mode();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (device_mode_ == DEVICE_MODE_NOT_SET)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      device_mode_ = DEVICE_MODE_ENTERPRISE;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!allowed_device_modes_.test(device_mode_)) {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Bad device mode " << device_mode_;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportResult(EnrollmentStatus::ForStatus(
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          EnrollmentStatus::STATUS_REGISTRATION_BAD_MODE));
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    client_->FetchPolicy();
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(FATAL) << "Registration state changed to " << client_->is_registered()
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " in step " << enrollment_step_;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EnrollmentHandlerChromeOS::OnClientError(CloudPolicyClient* client) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(client_.get(), client);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (enrollment_step_ == STEP_ROBOT_AUTH_FETCH) {
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG(WARNING) << "API authentication code fetch failed: "
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 << client_->status();
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Robot auth tokens are currently optional.  Skip fetching the refresh
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // token and jump directly to the lock device step.
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    robot_refresh_token_.clear();
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DoLockDeviceStep();
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else if (enrollment_step_ < STEP_POLICY_FETCH) {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReportResult(EnrollmentStatus::ForRegistrationError(client_->status()));
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReportResult(EnrollmentStatus::ForFetchError(client_->status()));
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EnrollmentHandlerChromeOS::OnStoreLoaded(CloudPolicyStore* store) {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(store_, store);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (enrollment_step_ == STEP_LOADING_STORE) {
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If the |store_| wasn't initialized when StartEnrollment() was
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // called, then AttemptRegistration() bails silently.  This gets
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // registration rolling again after the store finishes loading.
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AttemptRegistration();
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (enrollment_step_ == STEP_STORE_POLICY) {
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Store the robot API auth refresh token.
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Currently optional, so always return success.
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    chromeos::DeviceOAuth2TokenService* token_service =
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        chromeos::DeviceOAuth2TokenServiceFactory::Get();
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (token_service && !robot_refresh_token_.empty()) {
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      token_service->SetAndSaveRefreshToken(robot_refresh_token_);
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReportResult(EnrollmentStatus::ForStatus(EnrollmentStatus::STATUS_SUCCESS));
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EnrollmentHandlerChromeOS::OnStoreError(CloudPolicyStore* store) {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(store_, store);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReportResult(EnrollmentStatus::ForStoreError(store_->status(),
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               store_->validation_status()));
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EnrollmentHandlerChromeOS::AttemptRegistration() {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(STEP_LOADING_STORE, enrollment_step_);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (store_->is_initialized()) {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    enrollment_step_ = STEP_REGISTRATION;
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    client_->Register(em::DeviceRegisterRequest::DEVICE,
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      auth_token_, client_id_, is_auto_enrollment_,
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      requisition_);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EnrollmentHandlerChromeOS::PolicyValidated(
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DeviceCloudPolicyValidator* validator) {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(STEP_VALIDATION, enrollment_step_);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (validator->success()) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    policy_ = validator->policy().Pass();
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    username_ = validator->policy_data()->username();
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    device_id_ = validator->policy_data()->device_id();
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    enrollment_step_ = STEP_ROBOT_AUTH_FETCH;
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    client_->FetchRobotAuthCodes(auth_token_);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReportResult(EnrollmentStatus::ForValidationError(validator->status()));
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void EnrollmentHandlerChromeOS::OnRobotAuthCodesFetched(
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    CloudPolicyClient* client) {
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(client_.get(), client);
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CHECK_EQ(STEP_ROBOT_AUTH_FETCH, enrollment_step_);
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  enrollment_step_ = STEP_ROBOT_AUTH_REFRESH;
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gaia::OAuthClientInfo client_info;
215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  client_info.client_id = GaiaUrls::GetInstance()->oauth2_chrome_client_id();
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  client_info.client_secret =
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      GaiaUrls::GetInstance()->oauth2_chrome_client_secret();
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  client_info.redirect_uri = "oob";
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Use the system request context to avoid sending user cookies.
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      g_browser_process->system_request_context()));
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gaia_oauth_client_->GetTokensFromAuthCode(client_info,
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                            client->robot_api_auth_code(),
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                            0 /* max_retries */,
226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                            this);
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// GaiaOAuthClient::Delegate callback for OAuth2 refresh token fetched.
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void EnrollmentHandlerChromeOS::OnGetTokensResponse(
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& refresh_token,
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& access_token,
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int expires_in_seconds) {
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_);
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  robot_refresh_token_ = refresh_token;
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DoLockDeviceStep();
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void EnrollmentHandlerChromeOS::DoLockDeviceStep() {
242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  enrollment_step_ = STEP_LOCK_DEVICE,
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  StartLockDevice(username_, device_mode_, device_id_);
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// GaiaOAuthClient::Delegate
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void EnrollmentHandlerChromeOS::OnRefreshTokenResponse(
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& access_token,
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int expires_in_seconds) {
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We never use the code that should trigger this callback.
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  LOG(FATAL) << "Unexpected callback invoked";
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// GaiaOAuthClient::Delegate OAuth2 error when fetching refresh token request.
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void EnrollmentHandlerChromeOS::OnOAuthError() {
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_);
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DoLockDeviceStep();
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// GaiaOAuthClient::Delegate network error when fetching refresh token.
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void EnrollmentHandlerChromeOS::OnNetworkError(int response_code) {
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  LOG(ERROR) << "Network error while fetching API refresh token: "
263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)             << response_code;
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_);
265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DoLockDeviceStep();
266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void EnrollmentHandlerChromeOS::StartLockDevice(
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& user,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DeviceMode device_mode,
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& device_id) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(STEP_LOCK_DEVICE, enrollment_step_);
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since this method is also called directly.
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_factory_.InvalidateWeakPtrs();
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  install_attributes_->LockDevice(
277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      user, device_mode, device_id,
278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&EnrollmentHandlerChromeOS::HandleLockDeviceResult,
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 weak_factory_.GetWeakPtr(),
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 user,
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 device_mode,
282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 device_id));
283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void EnrollmentHandlerChromeOS::HandleLockDeviceResult(
286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& user,
287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DeviceMode device_mode,
288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& device_id,
289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    EnterpriseInstallAttributes::LockResult lock_result) {
290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CHECK_EQ(STEP_LOCK_DEVICE, enrollment_step_);
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (lock_result) {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case EnterpriseInstallAttributes::LOCK_SUCCESS:
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      enrollment_step_ = STEP_STORE_POLICY;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      store_->InstallInitialPolicy(*policy_);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case EnterpriseInstallAttributes::LOCK_NOT_READY:
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We wait up to |kLockRetryTimeoutMs| milliseconds and if it hasn't
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // succeeded by then show an error to the user and stop the enrollment.
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (lockbox_init_duration_ < kLockRetryTimeoutMs) {
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // InstallAttributes not ready yet, retry later.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(WARNING) << "Install Attributes not ready yet will retry in "
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     << kLockRetryIntervalMs << "ms.";
30390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::MessageLoop::current()->PostDelayedTask(
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            FROM_HERE,
305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            base::Bind(&EnrollmentHandlerChromeOS::StartLockDevice,
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       weak_factory_.GetWeakPtr(),
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       user, device_mode, device_id),
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            base::TimeDelta::FromMilliseconds(kLockRetryIntervalMs));
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        lockbox_init_duration_ += kLockRetryIntervalMs;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ReportResult(EnrollmentStatus::ForStatus(
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            EnrollmentStatus::STATUS_LOCK_TIMEOUT));
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case EnterpriseInstallAttributes::LOCK_BACKEND_ERROR:
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportResult(EnrollmentStatus::ForStatus(
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          EnrollmentStatus::STATUS_LOCK_ERROR));
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case EnterpriseInstallAttributes::LOCK_WRONG_USER:
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Enrollment cannot proceed because the InstallAttrs "
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << "has been locked already!";
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportResult(EnrollmentStatus::ForStatus(
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          EnrollmentStatus::STATUS_LOCK_WRONG_USER));
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED() << "Invalid lock result " << lock_result;
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReportResult(EnrollmentStatus::ForStatus(
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EnrollmentStatus::STATUS_LOCK_ERROR));
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EnrollmentHandlerChromeOS::Stop() {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (client_.get())
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    client_->RemoveObserver(this);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enrollment_step_ = STEP_FINISHED;
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_factory_.InvalidateWeakPtrs();
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  completion_callback_.Reset();
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EnrollmentHandlerChromeOS::ReportResult(EnrollmentStatus status) {
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EnrollmentCallback callback = completion_callback_;
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Stop();
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.status() != EnrollmentStatus::STATUS_SUCCESS) {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Enrollment failed: " << status.status()
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << " " << status.client_status()
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << " " << status.validation_status()
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << " " << status.store_status();
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!callback.is_null())
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback.Run(status);
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace policy
356