Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(710)

Side by Side Diff: chrome/browser/chromeos/login/device_settings_service.cc

Issue 10828032: Add DeviceSettingsService. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Oops. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/login/device_settings_service.h"
6
7 #include "base/bind.h"
8 #include "base/file_util.h"
9 #include "base/lazy_instance.h"
10 #include "base/logging.h"
11 #include "base/message_loop.h"
12 #include "base/stl_util.h"
13 #include "chrome/browser/chromeos/login/owner_key_util.h"
14 #include "chrome/browser/chromeos/login/session_manager_operation.h"
15 #include "chrome/browser/policy/proto/chrome_device_policy.pb.h"
16 #include "chrome/browser/policy/proto/device_management_backend.pb.h"
17 #include "chrome/common/chrome_notification_types.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/notification_service.h"
20 #include "content/public/browser/notification_source.h"
21 #include "crypto/rsa_private_key.h"
22
23 namespace em = enterprise_management;
24
25 namespace chromeos {
26
27 static base::LazyInstance<DeviceSettingsService> g_device_settings_service =
28 LAZY_INSTANCE_INITIALIZER;
29
30 OwnerKey::OwnerKey(scoped_ptr<std::vector<uint8> > public_key,
31 scoped_ptr<crypto::RSAPrivateKey> private_key)
32 : public_key_(public_key.Pass()),
33 private_key_(private_key.Pass()) {}
34
35 OwnerKey::~OwnerKey() {}
36
37 DeviceSettingsService::Observer::~Observer() {}
38
39 DeviceSettingsService::DeviceSettingsService()
40 : session_manager_client_(NULL),
41 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
42 store_status_(STORE_SUCCESS),
43 ownership_status_(OWNERSHIP_UNKNOWN) {}
44
45 DeviceSettingsService::~DeviceSettingsService() {
46 STLDeleteContainerPointers(pending_operations_.begin(),
47 pending_operations_.end());
48 pending_operations_.clear();
49 }
50
51 // static
52 DeviceSettingsService* DeviceSettingsService::Get() {
53 return g_device_settings_service.Pointer();
54 }
55
56 void DeviceSettingsService::Initialize(
57 SessionManagerClient* session_manager_client,
58 scoped_refptr<OwnerKeyUtil> owner_key_util) {
59 DCHECK(session_manager_client);
60 DCHECK(owner_key_util.get());
61 DCHECK(!session_manager_client_);
62 DCHECK(!owner_key_util_.get());
63
64 session_manager_client_ = session_manager_client;
65 owner_key_util_ = owner_key_util;
66
67 session_manager_client_->AddObserver(this);
68
69 StartNextOperation();
70 }
71
72 void DeviceSettingsService::Shutdown() {
73 session_manager_client_->RemoveObserver(this);
74 session_manager_client_ = NULL;
75 owner_key_util_ = NULL;
76 }
77
78 scoped_refptr<OwnerKey> DeviceSettingsService::GetOwnerKey() {
79 return owner_key_;
80 }
81
82 void DeviceSettingsService::Load() {
83 EnqueueLoad(false);
84 }
85
86 void DeviceSettingsService::SignAndStore(
87 scoped_ptr<em::ChromeDeviceSettingsProto> settings,
88 const base::Closure& callback) {
89 Enqueue(
90 new SignAndStoreSettingsOperation(
91 base::Bind(&DeviceSettingsService::HandleCompletedOperation,
92 weak_factory_.GetWeakPtr(),
93 callback),
94 settings.Pass(),
95 username_));
96 }
97
98 void DeviceSettingsService::Store(const std::string& policy_blob,
99 const base::Closure& callback) {
100 Enqueue(
101 new StoreSettingsOperation(
102 base::Bind(&DeviceSettingsService::HandleCompletedOperation,
103 weak_factory_.GetWeakPtr(),
104 callback),
105 policy_blob));
106 }
107
108 DeviceSettingsService::OwnershipStatus
109 DeviceSettingsService::GetOwnershipStatus(bool blocking) {
110 OwnershipStatus status = OWNERSHIP_UNKNOWN;
111 bool is_owned = false;
112 if (content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
113 ownership_status_lock_.Acquire();
114 status = ownership_status_;
115 ownership_status_lock_.Release();
116 if (status != OWNERSHIP_UNKNOWN || !blocking)
117 return status;
118 // Under common usage there is very short lapse of time when ownership
119 // status is still unknown after constructing DeviceSettingsService.
120 LOG(ERROR) << "Blocking on UI thread in DeviceSettingsService::GetStatus";
121 base::ThreadRestrictions::ScopedAllowIO allow_io;
122 is_owned = owner_key_util_->IsPublicKeyPresent();
123 } else {
124 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
125 is_owned = owner_key_util_->IsPublicKeyPresent();
126 }
127 status = is_owned ? OWNERSHIP_TAKEN : OWNERSHIP_NONE;
128 SetOwnershipStatus(status);
129 return status;
130 }
131
132 void DeviceSettingsService::GetOwnershipStatusAsync(
133 const OwnershipStatusCallback& callback) {
134 if (owner_key_.get()) {
135 // If there is a key, report status immediately.
136 MessageLoop::current()->PostTask(
137 FROM_HERE,
138 base::Bind(callback,
139 owner_key_->public_key() ? OWNERSHIP_TAKEN : OWNERSHIP_NONE,
140 owner_key_->private_key()));
141 } else {
142 // If the key hasn't been loaded yet, trigger a policy load operation or
143 // wait for an existing operation to finish.
144 pending_ownership_status_callbacks_.push_back(callback);
145 if (pending_operations_.empty())
146 EnqueueLoad(false);
147 }
148 }
149
150 bool DeviceSettingsService::HasPrivateOwnerKey() {
151 return owner_key_.get() && owner_key_->private_key();
152 }
153
154 void DeviceSettingsService::SetUsername(const std::string& username) {
155 username_ = username;
156
157 // The private key may have become available, so force a key reload.
158 OwnerKeySet(true);
159 }
160
161 const std::string& DeviceSettingsService::GetUsername() const {
162 return username_;
163 }
164
165 void DeviceSettingsService::AddObserver(Observer* observer) {
166 observers_.AddObserver(observer);
167 }
168
169 void DeviceSettingsService::RemoveObserver(Observer* observer) {
170 observers_.RemoveObserver(observer);
171 }
172
173 void DeviceSettingsService::OwnerKeySet(bool success) {
174 if (!success) {
175 LOG(ERROR) << "Owner key change failed.";
176 return;
177 }
178
179 owner_key_ = NULL;
180 EnsureReload(true);
181 }
182
183 void DeviceSettingsService::PropertyChangeComplete(bool success) {
184 if (!success) {
185 LOG(ERROR) << "Policy update failed.";
186 return;
187 }
188
189 EnsureReload(false);
190 }
191
192 void DeviceSettingsService::Enqueue(SessionManagerOperation* operation) {
193 pending_operations_.push_back(operation);
194 if (pending_operations_.front() == operation)
195 StartNextOperation();
196 }
197
198 void DeviceSettingsService::EnqueueLoad(bool force_key_load) {
199 SessionManagerOperation* operation =
200 new LoadSettingsOperation(
201 base::Bind(&DeviceSettingsService::HandleCompletedOperation,
202 weak_factory_.GetWeakPtr(),
203 base::Closure()));
204 operation->set_force_key_load(force_key_load);
205 Enqueue(operation);
206 }
207
208 void DeviceSettingsService::EnsureReload(bool force_key_load) {
209 if (!pending_operations_.empty())
210 pending_operations_.front()->RestartLoad(force_key_load);
pastarmovj 2012/07/30 12:19:19 What if the operation is a store op?
Mattias Nissler (ping if slow) 2012/07/31 13:02:15 If the Store op is still storing data, it'll not b
211 else
212 EnqueueLoad(force_key_load);
213 }
214
215 void DeviceSettingsService::StartNextOperation() {
216 if (!pending_operations_.empty() &&
217 session_manager_client_ &&
218 owner_key_util_.get()) {
219 pending_operations_.front()->Start(session_manager_client_,
220 owner_key_util_, owner_key_);
221 }
222 }
223
224 void DeviceSettingsService::HandleCompletedOperation(
225 const base::Closure& callback,
226 SessionManagerOperation* operation,
227 Status status) {
228 DCHECK_EQ(operation, pending_operations_.front());
229 store_status_ = status;
230
231 OwnershipStatus ownership_status = OWNERSHIP_UNKNOWN;
232 bool is_owner = false;
233 scoped_refptr<OwnerKey> new_key(operation->owner_key());
234 if (new_key.get()) {
235 ownership_status =
236 new_key->public_key() ? OWNERSHIP_TAKEN : OWNERSHIP_NONE;
237 is_owner = new_key->private_key();
pastarmovj 2012/07/30 12:19:19 I think this will be clearer if you wrote down the
Mattias Nissler (ping if slow) 2012/07/31 13:02:15 Done.
238 } else {
239 NOTREACHED() << "Failed to determine key status.";
240 }
241 SetOwnershipStatus(ownership_status);
242
243 if (owner_key_.get() != new_key.get()) {
pastarmovj 2012/07/30 12:19:19 If I understand this right this code will now trig
Mattias Nissler (ping if slow) 2012/07/31 13:02:15 Yes, I verified key rotation thoroughly, and it st
244 owner_key_ = new_key;
245 FOR_EACH_OBSERVER(Observer, observers_, OwnershipStatusChanged());
246 content::NotificationService::current()->Notify(
247 chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
248 content::Source<DeviceSettingsService>(this),
249 content::NotificationService::NoDetails());
250 }
251
252 if (status == STORE_SUCCESS) {
253 policy_data_ = operation->policy_data().Pass();
254 device_settings_ = operation->device_settings().Pass();
255 } else if (status != STORE_KEY_UNAVAILABLE) {
256 LOG(ERROR) << "Session manager operation failed: " << status;
257 }
258
259 FOR_EACH_OBSERVER(Observer, observers_, DeviceSettingsUpdated());
260
261 std::vector<OwnershipStatusCallback> callbacks;
262 callbacks.swap(pending_ownership_status_callbacks_);
263 for (std::vector<OwnershipStatusCallback>::iterator iter(callbacks.begin());
264 iter != callbacks.end(); ++iter) {
265 iter->Run(ownership_status, is_owner);
266 }
267
268 // The completion callback happens after the notification so clients can
269 // filter self-triggered updates.
270 if (!callback.is_null())
271 callback.Run();
272
273 // Only remove the pending operation here, so new operations triggered by any
274 // of the callbacks above are queued up properly.
275 pending_operations_.pop_front();
276 delete operation;
277
278 StartNextOperation();
279 }
280
281 void DeviceSettingsService::SetOwnershipStatus(OwnershipStatus new_status) {
282 DCHECK(new_status == OWNERSHIP_TAKEN || new_status == OWNERSHIP_NONE);
283 base::AutoLock lk(ownership_status_lock_);
284 ownership_status_ = new_status;
285 }
286
287 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698