1// Copyright 2014 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/device_cloud_policy_initializer.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/logging.h"
10#include "base/prefs/pref_service.h"
11#include "base/sequenced_task_runner.h"
12#include "base/values.h"
13#include "chrome/browser/browser_process.h"
14#include "chrome/browser/chromeos/login/startup_utils.h"
15#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
16#include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
17#include "chrome/browser/chromeos/policy/device_status_collector.h"
18#include "chrome/browser/chromeos/policy/enrollment_handler_chromeos.h"
19#include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
20#include "chrome/browser/chromeos/policy/server_backed_device_state.h"
21#include "chrome/browser/chromeos/settings/device_settings_service.h"
22#include "chrome/common/chrome_content_client.h"
23#include "chrome/common/pref_names.h"
24#include "chromeos/system/statistics_provider.h"
25#include "components/policy/core/common/cloud/cloud_policy_constants.h"
26#include "components/policy/core/common/cloud/cloud_policy_core.h"
27#include "components/policy/core/common/cloud/device_management_service.h"
28#include "components/policy/core/common/cloud/system_policy_request_context.h"
29#include "net/url_request/url_request_context_getter.h"
30
31namespace em = enterprise_management;
32
33namespace policy {
34
35namespace {
36
37// Gets a machine flag from StatisticsProvider, returning the given
38// |default_value| if not present.
39bool GetMachineFlag(const std::string& key, bool default_value) {
40  bool value = default_value;
41  chromeos::system::StatisticsProvider* provider =
42      chromeos::system::StatisticsProvider::GetInstance();
43  if (!provider->GetMachineFlag(key, &value))
44    return default_value;
45
46  return value;
47}
48
49}  // namespace
50
51DeviceCloudPolicyInitializer::DeviceCloudPolicyInitializer(
52    PrefService* local_state,
53    DeviceManagementService* enterprise_service,
54    DeviceManagementService* consumer_service,
55    const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
56    EnterpriseInstallAttributes* install_attributes,
57    ServerBackedStateKeysBroker* state_keys_broker,
58    DeviceCloudPolicyStoreChromeOS* device_store,
59    DeviceCloudPolicyManagerChromeOS* manager,
60    chromeos::DeviceSettingsService* device_settings_service,
61    const base::Closure& on_connected_callback)
62    : local_state_(local_state),
63      enterprise_service_(enterprise_service),
64      consumer_service_(consumer_service),
65      background_task_runner_(background_task_runner),
66      install_attributes_(install_attributes),
67      state_keys_broker_(state_keys_broker),
68      device_store_(device_store),
69      manager_(manager),
70      device_settings_service_(device_settings_service),
71      on_connected_callback_(on_connected_callback),
72      is_initialized_(false) {
73}
74
75DeviceCloudPolicyInitializer::~DeviceCloudPolicyInitializer() {
76  DCHECK(!is_initialized_);
77}
78
79void DeviceCloudPolicyInitializer::Init() {
80  DCHECK(!is_initialized_);
81
82  is_initialized_ = true;
83  device_store_->AddObserver(this);
84  state_keys_update_subscription_ = state_keys_broker_->RegisterUpdateCallback(
85      base::Bind(&DeviceCloudPolicyInitializer::TryToCreateClient,
86                 base::Unretained(this)));
87
88  device_status_provider_.reset(
89      new DeviceStatusCollector(
90          local_state_,
91          chromeos::system::StatisticsProvider::GetInstance(),
92          NULL));
93
94  TryToCreateClient();
95}
96
97void DeviceCloudPolicyInitializer::Shutdown() {
98  DCHECK(is_initialized_);
99
100  device_store_->RemoveObserver(this);
101  device_status_provider_.reset();
102  enrollment_handler_.reset();
103  state_keys_update_subscription_.reset();
104  is_initialized_ = false;
105}
106
107void DeviceCloudPolicyInitializer::StartEnrollment(
108    em::PolicyData::ManagementMode management_mode,
109    DeviceManagementService* device_management_service,
110    const std::string& auth_token,
111    bool is_auto_enrollment,
112    const AllowedDeviceModes& allowed_device_modes,
113    const EnrollmentCallback& enrollment_callback) {
114  DCHECK(is_initialized_);
115  DCHECK(!enrollment_handler_);
116
117  manager_->core()->Disconnect();
118  enrollment_handler_.reset(new EnrollmentHandlerChromeOS(
119      device_store_,
120      install_attributes_,
121      state_keys_broker_,
122      device_settings_service_,
123      CreateClient(device_management_service),
124      background_task_runner_,
125      auth_token,
126      install_attributes_->GetDeviceId(),
127      is_auto_enrollment,
128      manager_->GetDeviceRequisition(),
129      allowed_device_modes,
130      management_mode,
131      base::Bind(&DeviceCloudPolicyInitializer::EnrollmentCompleted,
132                 base::Unretained(this),
133                 enrollment_callback)));
134  enrollment_handler_->StartEnrollment();
135}
136
137bool DeviceCloudPolicyInitializer::ShouldAutoStartEnrollment() const {
138  std::string restore_mode = GetRestoreMode();
139  if (restore_mode == kDeviceStateRestoreModeReEnrollmentRequested ||
140      restore_mode == kDeviceStateRestoreModeReEnrollmentEnforced) {
141    return true;
142  }
143
144  if (local_state_->HasPrefPath(prefs::kDeviceEnrollmentAutoStart))
145    return local_state_->GetBoolean(prefs::kDeviceEnrollmentAutoStart);
146
147  return GetMachineFlag(chromeos::system::kOemIsEnterpriseManagedKey, false);
148}
149
150bool DeviceCloudPolicyInitializer::ShouldRecoverEnrollment() const {
151  if (install_attributes_->IsEnterpriseDevice() &&
152      chromeos::StartupUtils::IsEnrollmentRecoveryRequired()) {
153    LOG(WARNING) << "Enrollment recovery required according to pref.";
154    if (!DeviceCloudPolicyManagerChromeOS::GetMachineID().empty())
155      return true;
156    LOG(WARNING) << "Postponing recovery because machine id is missing.";
157  }
158  return false;
159}
160
161std::string DeviceCloudPolicyInitializer::GetEnrollmentRecoveryDomain() const {
162  return install_attributes_->GetDomain();
163}
164
165bool DeviceCloudPolicyInitializer::CanExitEnrollment() const {
166  if (GetRestoreMode() == kDeviceStateRestoreModeReEnrollmentEnforced)
167    return false;
168
169  if (local_state_->HasPrefPath(prefs::kDeviceEnrollmentCanExit))
170    return local_state_->GetBoolean(prefs::kDeviceEnrollmentCanExit);
171
172  return GetMachineFlag(chromeos::system::kOemCanExitEnterpriseEnrollmentKey,
173                        true);
174}
175
176std::string
177DeviceCloudPolicyInitializer::GetForcedEnrollmentDomain() const {
178  const base::DictionaryValue* device_state_dict =
179      local_state_->GetDictionary(prefs::kServerBackedDeviceState);
180  std::string management_domain;
181  device_state_dict->GetString(kDeviceStateManagementDomain,
182                               &management_domain);
183  return management_domain;
184}
185
186void DeviceCloudPolicyInitializer::OnStoreLoaded(CloudPolicyStore* store) {
187  TryToCreateClient();
188}
189
190void DeviceCloudPolicyInitializer::OnStoreError(CloudPolicyStore* store) {
191  // Do nothing.
192}
193
194void DeviceCloudPolicyInitializer::EnrollmentCompleted(
195    const EnrollmentCallback& enrollment_callback,
196    EnrollmentStatus status) {
197  scoped_ptr<CloudPolicyClient> client = enrollment_handler_->ReleaseClient();
198  enrollment_handler_.reset();
199
200  if (status.status() == EnrollmentStatus::STATUS_SUCCESS) {
201    StartConnection(client.Pass());
202  } else {
203    // Some attempts to create a client may be blocked because the enrollment
204    // was in progress. We give it a try again.
205    TryToCreateClient();
206  }
207
208  if (!enrollment_callback.is_null())
209    enrollment_callback.Run(status);
210}
211
212scoped_ptr<CloudPolicyClient> DeviceCloudPolicyInitializer::CreateClient(
213    DeviceManagementService* device_management_service) {
214  scoped_refptr<net::URLRequestContextGetter> request_context =
215      new SystemPolicyRequestContext(
216          g_browser_process->system_request_context(), GetUserAgent());
217
218  return make_scoped_ptr(
219      new CloudPolicyClient(DeviceCloudPolicyManagerChromeOS::GetMachineID(),
220                            DeviceCloudPolicyManagerChromeOS::GetMachineModel(),
221                            kPolicyVerificationKeyHash,
222                            USER_AFFILIATION_NONE,
223                            device_status_provider_.get(),
224                            device_management_service,
225                            request_context));
226}
227
228void DeviceCloudPolicyInitializer::TryToCreateClient() {
229  if (device_store_->is_initialized() &&
230      device_store_->has_policy() &&
231      !device_store_->policy()->request_token().empty() &&
232      !state_keys_broker_->pending() &&
233      !enrollment_handler_) {
234    DeviceManagementService* service;
235    if (device_store_->policy()->management_mode() ==
236        em::PolicyData::CONSUMER_MANAGED) {
237      service = consumer_service_;
238    } else {
239      service = enterprise_service_;
240    }
241    StartConnection(CreateClient(service));
242  }
243}
244
245void DeviceCloudPolicyInitializer::StartConnection(
246    scoped_ptr<CloudPolicyClient> client) {
247  if (!manager_->core()->service())
248    manager_->StartConnection(client.Pass(), device_status_provider_.Pass());
249
250  if (!on_connected_callback_.is_null()) {
251    on_connected_callback_.Run();
252    on_connected_callback_.Reset();
253  }
254}
255
256std::string DeviceCloudPolicyInitializer::GetRestoreMode() const {
257  const base::DictionaryValue* device_state_dict =
258      local_state_->GetDictionary(prefs::kServerBackedDeviceState);
259  std::string restore_mode;
260  device_state_dict->GetString(kDeviceStateRestoreMode, &restore_mode);
261  return restore_mode;
262}
263
264}  // namespace policy
265