device_settings_service.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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/settings/device_settings_service.h"
6
7#include "base/bind.h"
8#include "base/logging.h"
9#include "base/message_loop/message_loop.h"
10#include "base/stl_util.h"
11#include "base/time/time.h"
12#include "chrome/browser/chrome_notification_types.h"
13#include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
14#include "chrome/browser/chromeos/settings/owner_key_util.h"
15#include "chrome/browser/chromeos/settings/session_manager_operation.h"
16#include "components/policy/core/common/cloud/cloud_policy_constants.h"
17#include "content/public/browser/browser_thread.h"
18#include "content/public/browser/notification_service.h"
19#include "content/public/browser/notification_source.h"
20#include "crypto/rsa_private_key.h"
21
22namespace em = enterprise_management;
23
24namespace {
25
26// Delay between load retries when there was a validation error.
27// NOTE: This code is here to mitigate clock loss on some devices where policy
28// loads will fail with a validation error caused by RTC clock being reset when
29// the battery is drained.
30int kLoadRetryDelayMs = 1000 * 5;
31// Maximal number of retries before we give up. Calculated to allow for 10 min
32// of retry time.
33int kMaxLoadRetries = (1000 * 60 * 10) / kLoadRetryDelayMs;
34
35}  // namespace
36
37namespace chromeos {
38
39DeviceSettingsService::Observer::~Observer() {}
40
41static DeviceSettingsService* g_device_settings_service = NULL;
42
43// static
44void DeviceSettingsService::Initialize() {
45  CHECK(!g_device_settings_service);
46  g_device_settings_service = new DeviceSettingsService();
47}
48
49// static
50bool DeviceSettingsService::IsInitialized() {
51  return g_device_settings_service;
52}
53
54// static
55void DeviceSettingsService::Shutdown() {
56  DCHECK(g_device_settings_service);
57  delete g_device_settings_service;
58  g_device_settings_service = NULL;
59}
60
61// static
62DeviceSettingsService* DeviceSettingsService::Get() {
63  CHECK(g_device_settings_service);
64  return g_device_settings_service;
65}
66
67DeviceSettingsService::DeviceSettingsService()
68    : session_manager_client_(NULL),
69      store_status_(STORE_SUCCESS),
70      load_retries_left_(kMaxLoadRetries),
71      weak_factory_(this) {
72}
73
74DeviceSettingsService::~DeviceSettingsService() {
75  DCHECK(pending_operations_.empty());
76}
77
78void DeviceSettingsService::SetSessionManager(
79    SessionManagerClient* session_manager_client,
80    scoped_refptr<OwnerKeyUtil> owner_key_util) {
81  DCHECK(session_manager_client);
82  DCHECK(owner_key_util.get());
83  DCHECK(!session_manager_client_);
84  DCHECK(!owner_key_util_.get());
85
86  session_manager_client_ = session_manager_client;
87  owner_key_util_ = owner_key_util;
88
89  session_manager_client_->AddObserver(this);
90
91  StartNextOperation();
92}
93
94void DeviceSettingsService::UnsetSessionManager() {
95  STLDeleteContainerPointers(pending_operations_.begin(),
96                             pending_operations_.end());
97  pending_operations_.clear();
98
99  if (session_manager_client_)
100    session_manager_client_->RemoveObserver(this);
101  session_manager_client_ = NULL;
102  owner_key_util_ = NULL;
103}
104
105scoped_refptr<PublicKey> DeviceSettingsService::GetPublicKey() {
106  return public_key_;
107}
108
109void DeviceSettingsService::Load() {
110  EnqueueLoad(false);
111}
112
113void DeviceSettingsService::SignAndStore(
114    scoped_ptr<em::ChromeDeviceSettingsProto> new_settings,
115    const base::Closure& callback) {
116  if (!delegate_)
117    HandleError(STORE_KEY_UNAVAILABLE, callback);
118  else
119    delegate_->SignAndStoreAsync(new_settings.Pass(), callback);
120}
121
122void DeviceSettingsService::SetManagementSettings(
123    em::PolicyData::ManagementMode management_mode,
124    const std::string& request_token,
125    const std::string& device_id,
126    const base::Closure& callback) {
127  if (!delegate_) {
128    HandleError(STORE_KEY_UNAVAILABLE, callback);
129  } else {
130    delegate_->SetManagementSettingsAsync(
131        management_mode, request_token, device_id, callback);
132  }
133}
134
135void DeviceSettingsService::Store(scoped_ptr<em::PolicyFetchResponse> policy,
136                                  const base::Closure& callback) {
137  Enqueue(
138      new StoreSettingsOperation(
139          base::Bind(&DeviceSettingsService::HandleCompletedOperation,
140                     weak_factory_.GetWeakPtr(),
141                     callback),
142          policy.Pass()));
143}
144
145DeviceSettingsService::OwnershipStatus
146    DeviceSettingsService::GetOwnershipStatus() {
147  if (public_key_)
148    return public_key_->is_loaded() ? OWNERSHIP_TAKEN : OWNERSHIP_NONE;
149  return OWNERSHIP_UNKNOWN;
150}
151
152void DeviceSettingsService::GetOwnershipStatusAsync(
153    const OwnershipStatusCallback& callback) {
154  if (public_key_) {
155    // If there is a key, report status immediately.
156    base::MessageLoop::current()->PostTask(
157        FROM_HERE, base::Bind(callback, GetOwnershipStatus()));
158  } else {
159    // If the key hasn't been loaded yet, enqueue the callback to be fired when
160    // the next SessionManagerOperation completes. If no operation is pending,
161    // start a load operation to fetch the key and report the result.
162    pending_ownership_status_callbacks_.push_back(callback);
163    if (pending_operations_.empty())
164      EnqueueLoad(false);
165  }
166}
167
168bool DeviceSettingsService::HasPrivateOwnerKey() {
169  return delegate_ && delegate_->IsOwner();
170}
171
172void DeviceSettingsService::InitOwner(
173    const std::string& username,
174    const base::WeakPtr<PrivateKeyDelegate>& delegate) {
175  // When InitOwner() is called twice with the same |username| it's
176  // worth to reload settings since owner key may become available.
177  if (!username_.empty() && username_ != username)
178    return;
179  username_ = username;
180  delegate_ = delegate;
181
182  EnsureReload(true);
183}
184
185const std::string& DeviceSettingsService::GetUsername() const {
186  return username_;
187}
188
189void DeviceSettingsService::AddObserver(Observer* observer) {
190  observers_.AddObserver(observer);
191}
192
193void DeviceSettingsService::RemoveObserver(Observer* observer) {
194  observers_.RemoveObserver(observer);
195}
196
197void DeviceSettingsService::OwnerKeySet(bool success) {
198  if (!success) {
199    LOG(ERROR) << "Owner key change failed.";
200    return;
201  }
202
203  public_key_ = NULL;
204  EnsureReload(true);
205}
206
207void DeviceSettingsService::PropertyChangeComplete(bool success) {
208  if (!success) {
209    LOG(ERROR) << "Policy update failed.";
210    return;
211  }
212
213  EnsureReload(false);
214}
215
216void DeviceSettingsService::Enqueue(SessionManagerOperation* operation) {
217  pending_operations_.push_back(operation);
218  if (pending_operations_.front() == operation)
219    StartNextOperation();
220}
221
222void DeviceSettingsService::EnqueueLoad(bool force_key_load) {
223  SessionManagerOperation* operation =
224      new LoadSettingsOperation(
225          base::Bind(&DeviceSettingsService::HandleCompletedOperation,
226                     weak_factory_.GetWeakPtr(),
227                     base::Closure()));
228  operation->set_force_key_load(force_key_load);
229  operation->set_username(username_);
230  operation->set_delegate(delegate_);
231  Enqueue(operation);
232}
233
234void DeviceSettingsService::EnsureReload(bool force_key_load) {
235  if (!pending_operations_.empty()) {
236    pending_operations_.front()->set_username(username_);
237    pending_operations_.front()->set_delegate(delegate_);
238    pending_operations_.front()->RestartLoad(force_key_load);
239  } else {
240    EnqueueLoad(force_key_load);
241  }
242}
243
244void DeviceSettingsService::StartNextOperation() {
245  if (!pending_operations_.empty() &&
246      session_manager_client_ &&
247      owner_key_util_.get()) {
248    pending_operations_.front()->Start(
249        session_manager_client_, owner_key_util_, public_key_);
250  }
251}
252
253void DeviceSettingsService::HandleCompletedOperation(
254    const base::Closure& callback,
255    SessionManagerOperation* operation,
256    Status status) {
257  DCHECK_EQ(operation, pending_operations_.front());
258  store_status_ = status;
259
260  OwnershipStatus ownership_status = OWNERSHIP_UNKNOWN;
261  scoped_refptr<PublicKey> new_key(operation->public_key());
262  if (new_key.get()) {
263    ownership_status = new_key->is_loaded() ? OWNERSHIP_TAKEN : OWNERSHIP_NONE;
264  } else {
265    NOTREACHED() << "Failed to determine key status.";
266  }
267
268  bool new_owner_key = false;
269  if (public_key_.get() != new_key.get()) {
270    public_key_ = new_key;
271    new_owner_key = true;
272  }
273
274  if (status == STORE_SUCCESS) {
275    policy_data_ = operation->policy_data().Pass();
276    device_settings_ = operation->device_settings().Pass();
277    load_retries_left_ = kMaxLoadRetries;
278  } else if (status != STORE_KEY_UNAVAILABLE) {
279    LOG(ERROR) << "Session manager operation failed: " << status;
280    // Validation errors can be temporary if the rtc has gone on holiday for a
281    // short while. So we will retry such loads for up to 10 minutes.
282    if (status == STORE_TEMP_VALIDATION_ERROR) {
283      if (load_retries_left_ > 0) {
284        load_retries_left_--;
285        LOG(ERROR) << "A re-load has been scheduled due to a validation error.";
286        content::BrowserThread::PostDelayedTask(
287            content::BrowserThread::UI,
288            FROM_HERE,
289            base::Bind(&DeviceSettingsService::Load, base::Unretained(this)),
290            base::TimeDelta::FromMilliseconds(kLoadRetryDelayMs));
291      } else {
292        // Once we've given up retrying, the validation error is not temporary
293        // anymore.
294        store_status_ = STORE_VALIDATION_ERROR;
295      }
296    }
297  }
298
299  if (new_owner_key) {
300    FOR_EACH_OBSERVER(Observer, observers_, OwnershipStatusChanged());
301    content::NotificationService::current()->Notify(
302        chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
303        content::Source<DeviceSettingsService>(this),
304        content::NotificationService::NoDetails());
305  }
306
307  FOR_EACH_OBSERVER(Observer, observers_, DeviceSettingsUpdated());
308
309  std::vector<OwnershipStatusCallback> callbacks;
310  callbacks.swap(pending_ownership_status_callbacks_);
311  for (std::vector<OwnershipStatusCallback>::iterator iter(callbacks.begin());
312       iter != callbacks.end(); ++iter) {
313    iter->Run(ownership_status);
314  }
315
316  // The completion callback happens after the notification so clients can
317  // filter self-triggered updates.
318  if (!callback.is_null())
319    callback.Run();
320
321  // Only remove the pending operation here, so new operations triggered by any
322  // of the callbacks above are queued up properly.
323  pending_operations_.pop_front();
324  delete operation;
325
326  StartNextOperation();
327}
328
329void DeviceSettingsService::HandleError(Status status,
330                                        const base::Closure& callback) {
331  store_status_ = status;
332
333  LOG(ERROR) << "Session manager operation failed: " << status;
334
335  FOR_EACH_OBSERVER(Observer, observers_, DeviceSettingsUpdated());
336
337  // The completion callback happens after the notification so clients can
338  // filter self-triggered updates.
339  if (!callback.is_null())
340    callback.Run();
341}
342
343void DeviceSettingsService::OnSignAndStoreOperationCompleted(Status status) {
344  store_status_ = status;
345  FOR_EACH_OBSERVER(Observer, observers_, DeviceSettingsUpdated());
346}
347
348ScopedTestDeviceSettingsService::ScopedTestDeviceSettingsService() {
349  DeviceSettingsService::Initialize();
350}
351
352ScopedTestDeviceSettingsService::~ScopedTestDeviceSettingsService() {
353  // Clean pending operations.
354  DeviceSettingsService::Get()->UnsetSessionManager();
355  DeviceSettingsService::Shutdown();
356}
357
358}  // namespace chromeos
359