enrollment_handler_chromeos.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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/policy/enrollment_handler_chromeos.h"
6
7#include "base/bind.h"
8#include "base/logging.h"
9#include "base/message_loop.h"
10#include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
11#include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
12#include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
13#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
14#include "chrome/browser/policy/cloud/proto/device_management_backend.pb.h"
15
16namespace em = enterprise_management;
17
18namespace policy {
19
20namespace {
21
22// Retry for InstallAttrs initialization every 500ms.
23const int kLockRetryIntervalMs = 500;
24// Maximum time to retry InstallAttrs initialization before we give up.
25const int kLockRetryTimeoutMs = 10 * 60 * 1000;  // 10 minutes.
26
27}  // namespace
28
29EnrollmentHandlerChromeOS::EnrollmentHandlerChromeOS(
30    DeviceCloudPolicyStoreChromeOS* store,
31    EnterpriseInstallAttributes* install_attributes,
32    scoped_ptr<CloudPolicyClient> client,
33    const std::string& auth_token,
34    const std::string& client_id,
35    bool is_auto_enrollment,
36    const AllowedDeviceModes& allowed_device_modes,
37    const EnrollmentCallback& completion_callback)
38    : store_(store),
39      install_attributes_(install_attributes),
40      client_(client.Pass()),
41      auth_token_(auth_token),
42      client_id_(client_id),
43      is_auto_enrollment_(is_auto_enrollment),
44      allowed_device_modes_(allowed_device_modes),
45      completion_callback_(completion_callback),
46      device_mode_(DEVICE_MODE_NOT_SET),
47      enrollment_step_(STEP_PENDING),
48      lockbox_init_duration_(0),
49      ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
50  CHECK(!client_->is_registered());
51  CHECK_EQ(DM_STATUS_SUCCESS, client_->status());
52  store_->AddObserver(this);
53  client_->AddObserver(this);
54  client_->AddNamespaceToFetch(PolicyNamespaceKey(
55      dm_protocol::kChromeDevicePolicyType, std::string()));
56}
57
58EnrollmentHandlerChromeOS::~EnrollmentHandlerChromeOS() {
59  Stop();
60  store_->RemoveObserver(this);
61}
62
63void EnrollmentHandlerChromeOS::StartEnrollment() {
64  CHECK_EQ(STEP_PENDING, enrollment_step_);
65  enrollment_step_ = STEP_LOADING_STORE;
66  AttemptRegistration();
67}
68
69scoped_ptr<CloudPolicyClient> EnrollmentHandlerChromeOS::ReleaseClient() {
70  Stop();
71  return client_.Pass();
72}
73
74void EnrollmentHandlerChromeOS::OnPolicyFetched(CloudPolicyClient* client) {
75  DCHECK_EQ(client_.get(), client);
76  CHECK_EQ(STEP_POLICY_FETCH, enrollment_step_);
77
78  enrollment_step_ = STEP_VALIDATION;
79
80  // Validate the policy.
81  const em::PolicyFetchResponse* policy = client_->GetPolicyFor(
82      PolicyNamespaceKey(dm_protocol::kChromeDevicePolicyType, std::string()));
83  if (!policy) {
84    ReportResult(EnrollmentStatus::ForFetchError(
85        DM_STATUS_RESPONSE_DECODING_ERROR));
86    return;
87  }
88
89  scoped_ptr<DeviceCloudPolicyValidator> validator(
90      DeviceCloudPolicyValidator::Create(
91          scoped_ptr<em::PolicyFetchResponse>(
92              new em::PolicyFetchResponse(*policy))));
93
94  validator->ValidateTimestamp(base::Time(), base::Time::NowFromSystemTime(),
95                               CloudPolicyValidatorBase::TIMESTAMP_REQUIRED);
96  if (install_attributes_->IsEnterpriseDevice())
97    validator->ValidateDomain(install_attributes_->GetDomain());
98  validator->ValidateDMToken(client->dm_token(),
99                             CloudPolicyValidatorBase::DM_TOKEN_REQUIRED);
100  validator->ValidatePolicyType(dm_protocol::kChromeDevicePolicyType);
101  validator->ValidatePayload();
102  validator->ValidateInitialKey();
103  validator.release()->StartValidation(
104      base::Bind(&EnrollmentHandlerChromeOS::PolicyValidated,
105                 weak_factory_.GetWeakPtr()));
106}
107
108void EnrollmentHandlerChromeOS::OnRegistrationStateChanged(
109    CloudPolicyClient* client) {
110  DCHECK_EQ(client_.get(), client);
111
112  if (enrollment_step_ == STEP_REGISTRATION && client_->is_registered()) {
113    enrollment_step_ = STEP_POLICY_FETCH,
114    device_mode_ = client_->device_mode();
115    if (device_mode_ == DEVICE_MODE_NOT_SET)
116      device_mode_ = DEVICE_MODE_ENTERPRISE;
117    if (!allowed_device_modes_.test(device_mode_)) {
118      LOG(ERROR) << "Bad device mode " << device_mode_;
119      ReportResult(EnrollmentStatus::ForStatus(
120          EnrollmentStatus::STATUS_REGISTRATION_BAD_MODE));
121      return;
122    }
123    client_->FetchPolicy();
124  } else {
125    LOG(FATAL) << "Registration state changed to " << client_->is_registered()
126               << " in step " << enrollment_step_;
127  }
128}
129
130void EnrollmentHandlerChromeOS::OnClientError(CloudPolicyClient* client) {
131  DCHECK_EQ(client_.get(), client);
132
133  if (enrollment_step_ < STEP_POLICY_FETCH)
134    ReportResult(EnrollmentStatus::ForRegistrationError(client_->status()));
135  else
136    ReportResult(EnrollmentStatus::ForFetchError(client_->status()));
137}
138
139void EnrollmentHandlerChromeOS::OnStoreLoaded(CloudPolicyStore* store) {
140  DCHECK_EQ(store_, store);
141
142  if (enrollment_step_ == STEP_LOADING_STORE) {
143    AttemptRegistration();
144  } else if (enrollment_step_ == STEP_STORE_POLICY) {
145    ReportResult(EnrollmentStatus::ForStatus(EnrollmentStatus::STATUS_SUCCESS));
146  }
147}
148
149void EnrollmentHandlerChromeOS::OnStoreError(CloudPolicyStore* store) {
150  DCHECK_EQ(store_, store);
151  ReportResult(EnrollmentStatus::ForStoreError(store_->status(),
152                                               store_->validation_status()));
153}
154
155void EnrollmentHandlerChromeOS::AttemptRegistration() {
156  CHECK_EQ(STEP_LOADING_STORE, enrollment_step_);
157  if (store_->is_initialized()) {
158    enrollment_step_ = STEP_REGISTRATION;
159    client_->Register(em::DeviceRegisterRequest::DEVICE,
160                      auth_token_, client_id_, is_auto_enrollment_);
161  }
162}
163
164void EnrollmentHandlerChromeOS::PolicyValidated(
165    DeviceCloudPolicyValidator* validator) {
166  CHECK_EQ(STEP_VALIDATION, enrollment_step_);
167  if (validator->success()) {
168    policy_ = validator->policy().Pass();
169    enrollment_step_ = STEP_LOCK_DEVICE;
170    WriteInstallAttributes(validator->policy_data()->username(), device_mode_,
171                           validator->policy_data()->device_id());
172  } else {
173    ReportResult(EnrollmentStatus::ForValidationError(validator->status()));
174  }
175}
176
177void EnrollmentHandlerChromeOS::WriteInstallAttributes(
178    const std::string& user,
179    DeviceMode device_mode,
180    const std::string& device_id) {
181  CHECK_EQ(STEP_LOCK_DEVICE, enrollment_step_);
182  // Since this method is also called directly.
183  weak_factory_.InvalidateWeakPtrs();
184
185  EnterpriseInstallAttributes::LockResult lock_result =
186      install_attributes_->LockDevice(user, device_mode, device_id);
187  switch (lock_result) {
188    case EnterpriseInstallAttributes::LOCK_SUCCESS:
189      enrollment_step_ = STEP_STORE_POLICY;
190      store_->InstallInitialPolicy(*policy_);
191      return;
192    case EnterpriseInstallAttributes::LOCK_NOT_READY:
193      // We wait up to |kLockRetryTimeoutMs| milliseconds and if it hasn't
194      // succeeded by then show an error to the user and stop the enrollment.
195      if (lockbox_init_duration_ < kLockRetryTimeoutMs) {
196        // InstallAttributes not ready yet, retry later.
197        LOG(WARNING) << "Install Attributes not ready yet will retry in "
198                     << kLockRetryIntervalMs << "ms.";
199        MessageLoop::current()->PostDelayedTask(
200            FROM_HERE,
201            base::Bind(&EnrollmentHandlerChromeOS::WriteInstallAttributes,
202                       weak_factory_.GetWeakPtr(),
203                       user, device_mode, device_id),
204            base::TimeDelta::FromMilliseconds(kLockRetryIntervalMs));
205        lockbox_init_duration_ += kLockRetryIntervalMs;
206      } else {
207        ReportResult(EnrollmentStatus::ForStatus(
208            EnrollmentStatus::STATUS_LOCK_TIMEOUT));
209      }
210      return;
211    case EnterpriseInstallAttributes::LOCK_BACKEND_ERROR:
212      ReportResult(EnrollmentStatus::ForStatus(
213          EnrollmentStatus::STATUS_LOCK_ERROR));
214      return;
215    case EnterpriseInstallAttributes::LOCK_WRONG_USER:
216      LOG(ERROR) << "Enrollment cannot proceed because the InstallAttrs "
217                 << "has been locked already!";
218      ReportResult(EnrollmentStatus::ForStatus(
219          EnrollmentStatus::STATUS_LOCK_WRONG_USER));
220      return;
221  }
222
223  NOTREACHED() << "Invalid lock result " << lock_result;
224  ReportResult(EnrollmentStatus::ForStatus(
225      EnrollmentStatus::STATUS_LOCK_ERROR));
226}
227
228void EnrollmentHandlerChromeOS::Stop() {
229  if (client_.get())
230    client_->RemoveObserver(this);
231  enrollment_step_ = STEP_FINISHED;
232  weak_factory_.InvalidateWeakPtrs();
233  completion_callback_.Reset();
234}
235
236void EnrollmentHandlerChromeOS::ReportResult(EnrollmentStatus status) {
237  EnrollmentCallback callback = completion_callback_;
238  Stop();
239
240  if (status.status() != EnrollmentStatus::STATUS_SUCCESS) {
241    LOG(WARNING) << "Enrollment failed: " << status.status()
242                 << " " << status.client_status()
243                 << " " << status.validation_status()
244                 << " " << status.store_status();
245  }
246
247  if (!callback.is_null())
248    callback.Run(status);
249}
250
251}  // namespace policy
252