1 // Copyright (c) 2011 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/signed_settings_helper.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "base/memory/ref_counted.h"
13 #include "chrome/browser/chromeos/login/signed_settings.h"
14 #include "chrome/browser/policy/proto/device_management_backend.pb.h"
15 #include "content/browser/browser_thread.h"
16
17 namespace chromeos {
18
19 namespace {
20
21 class OpContext {
22 public:
23 class Delegate {
24 public:
25 virtual void OnOpCreated(OpContext* context) = 0;
26 virtual void OnOpStarted(OpContext* context) = 0;
27 virtual void OnOpCompleted(OpContext* context) = 0;
28 };
29
~OpContext()30 virtual ~OpContext() {}
31
32 // Creates and execute op.
Execute()33 void Execute() {
34 CreateOp();
35 CHECK(op_.get());
36 if (delegate_)
37 delegate_->OnOpCreated(this);
38
39 // Note that the context could be released when op_->Execute() returns.
40 // So keep a local copy of delegate and executing flag to use after
41 // the call.
42 Delegate* delegate = delegate_;
43 executing_ = true;
44 op_->Execute();
45 if (delegate)
46 delegate->OnOpStarted(this);
47 }
48
49 // Cancels the callback.
CancelCallback()50 void CancelCallback() {
51 callback_ = NULL;
52 }
53
54 // Cancels the callback and cancels the op if it is not executing.
Cancel()55 void Cancel() {
56 CancelCallback();
57
58 if (!executing_)
59 OnOpCompleted();
60 }
61
62 // Accessors.
op() const63 SignedSettings* op() const {
64 return op_.get();
65 }
66
callback() const67 SignedSettingsHelper::Callback* callback() const {
68 return callback_;
69 }
70
set_delegate(Delegate * delegate)71 void set_delegate(Delegate* delegate) {
72 delegate_ = delegate;
73 }
74
75 protected:
OpContext(SignedSettingsHelper::Callback * callback,Delegate * delegate)76 OpContext(SignedSettingsHelper::Callback* callback,
77 Delegate* delegate)
78 : executing_(false),
79 delegate_(delegate),
80 callback_(callback) {
81 }
82
83 // Creates the op to execute.
84 virtual void CreateOp() = 0;
85
86 // Callback on op completion.
OnOpCompleted()87 virtual void OnOpCompleted() {
88 if (delegate_)
89 delegate_->OnOpCompleted(this);
90
91 delete this;
92 }
93
94 bool executing_;
95 Delegate* delegate_;
96
97 scoped_refptr<SignedSettings> op_;
98 SignedSettingsHelper::Callback* callback_;
99 };
100
101 class WhitelistOpContext : public SignedSettings::Delegate<bool>,
102 public OpContext {
103 public:
104 enum Type {
105 CHECK,
106 ADD,
107 REMOVE,
108 };
109
WhitelistOpContext(Type type,const std::string & email,SignedSettingsHelper::Callback * callback,OpContext::Delegate * delegate)110 WhitelistOpContext(Type type,
111 const std::string& email,
112 SignedSettingsHelper::Callback* callback,
113 OpContext::Delegate* delegate)
114 : OpContext(callback, delegate),
115 type_(type),
116 email_(email) {
117 }
118
119 // chromeos::SignedSettings::Delegate implementation
OnSettingsOpCompleted(SignedSettings::ReturnCode code,bool value)120 virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code,
121 bool value) OVERRIDE {
122 if (callback_) {
123 switch (type_) {
124 case CHECK:
125 callback_->OnCheckWhitelistCompleted(code, email_);
126 break;
127 case ADD:
128 callback_->OnWhitelistCompleted(code, email_);
129 break;
130 case REMOVE:
131 callback_->OnUnwhitelistCompleted(code, email_);
132 break;
133 default:
134 LOG(ERROR) << "Unknown WhitelistOpContext type " << type_;
135 break;
136 }
137 }
138 OnOpCompleted();
139 }
140
141 protected:
142 // OpContext implemenetation
CreateOp()143 virtual void CreateOp() OVERRIDE {
144 switch (type_) {
145 case CHECK:
146 op_ = SignedSettings::CreateCheckWhitelistOp(email_, this);
147 break;
148 case ADD:
149 op_ = SignedSettings::CreateWhitelistOp(email_, true, this);
150 break;
151 case REMOVE:
152 op_ = SignedSettings::CreateWhitelistOp(email_, false, this);
153 break;
154 default:
155 LOG(ERROR) << "Unknown WhitelistOpContext type " << type_;
156 break;
157 }
158 }
159
160 private:
161 Type type_;
162 std::string email_;
163
164 DISALLOW_COPY_AND_ASSIGN(WhitelistOpContext);
165 };
166
167 class StorePropertyOpContext : public SignedSettings::Delegate<bool>,
168 public OpContext {
169 public:
StorePropertyOpContext(const std::string & name,const std::string & value,SignedSettingsHelper::Callback * callback,OpContext::Delegate * delegate)170 StorePropertyOpContext(const std::string& name,
171 const std::string& value,
172 SignedSettingsHelper::Callback* callback,
173 OpContext::Delegate* delegate)
174 : OpContext(callback, delegate),
175 name_(name),
176 value_(value) {
177 }
178
179 // chromeos::SignedSettings::Delegate implementation
OnSettingsOpCompleted(SignedSettings::ReturnCode code,bool unused)180 virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code,
181 bool unused) OVERRIDE {
182 VLOG(2) << "OnSettingsOpCompleted, code = " << code;
183 if (callback_)
184 callback_->OnStorePropertyCompleted(code, name_, value_);
185 OnOpCompleted();
186 }
187
188 protected:
189 // OpContext implemenetation
CreateOp()190 virtual void CreateOp() OVERRIDE {
191 op_ = SignedSettings::CreateStorePropertyOp(name_, value_, this);
192 }
193
194 private:
195 std::string name_;
196 std::string value_;
197
198 DISALLOW_COPY_AND_ASSIGN(StorePropertyOpContext);
199 };
200
201 class RetrievePropertyOpContext
202 : public SignedSettings::Delegate<std::string>,
203 public OpContext {
204 public:
RetrievePropertyOpContext(const std::string & name,SignedSettingsHelper::Callback * callback,OpContext::Delegate * delegate)205 RetrievePropertyOpContext(const std::string& name,
206 SignedSettingsHelper::Callback* callback,
207 OpContext::Delegate* delegate)
208 : OpContext(callback, delegate),
209 name_(name) {
210 }
211
212 // chromeos::SignedSettings::Delegate implementation
OnSettingsOpCompleted(SignedSettings::ReturnCode code,std::string value)213 virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code,
214 std::string value) OVERRIDE {
215 if (callback_)
216 callback_->OnRetrievePropertyCompleted(code, name_, value);
217
218 OnOpCompleted();
219 }
220
221 protected:
222 // OpContext implemenetation
CreateOp()223 virtual void CreateOp() OVERRIDE {
224 op_ = SignedSettings::CreateRetrievePropertyOp(name_, this);
225 }
226
227 private:
228 std::string name_;
229
230 DISALLOW_COPY_AND_ASSIGN(RetrievePropertyOpContext);
231 };
232
233 class StorePolicyOpContext : public SignedSettings::Delegate<bool>,
234 public OpContext {
235 public:
StorePolicyOpContext(const em::PolicyFetchResponse & policy,SignedSettingsHelper::Callback * callback,OpContext::Delegate * delegate)236 StorePolicyOpContext(const em::PolicyFetchResponse& policy,
237 SignedSettingsHelper::Callback* callback,
238 OpContext::Delegate* delegate)
239 : OpContext(callback, delegate),
240 policy_(policy) {
241 }
242
243 // chromeos::SignedSettings::Delegate implementation
OnSettingsOpCompleted(SignedSettings::ReturnCode code,bool unused)244 virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code,
245 bool unused) OVERRIDE {
246 VLOG(2) << "OnSettingsOpCompleted, code = " << code;
247 if (callback_)
248 callback_->OnStorePolicyCompleted(code);
249 OnOpCompleted();
250 }
251
252 protected:
253 // OpContext implementation
CreateOp()254 virtual void CreateOp() OVERRIDE {
255 op_ = SignedSettings::CreateStorePolicyOp(&policy_, this);
256 }
257
258 private:
259 em::PolicyFetchResponse policy_;
260 DISALLOW_COPY_AND_ASSIGN(StorePolicyOpContext);
261 };
262
263 class RetrievePolicyOpContext
264 : public SignedSettings::Delegate<const em::PolicyFetchResponse&>,
265 public OpContext {
266 public:
RetrievePolicyOpContext(SignedSettingsHelper::Callback * callback,OpContext::Delegate * delegate)267 RetrievePolicyOpContext(SignedSettingsHelper::Callback* callback,
268 OpContext::Delegate* delegate)
269 : OpContext(callback, delegate) {
270 }
271
272 // chromeos::SignedSettings::Delegate implementation
OnSettingsOpCompleted(SignedSettings::ReturnCode code,const em::PolicyFetchResponse & policy)273 virtual void OnSettingsOpCompleted(
274 SignedSettings::ReturnCode code,
275 const em::PolicyFetchResponse& policy) OVERRIDE {
276 if (callback_)
277 callback_->OnRetrievePolicyCompleted(code, policy);
278 OnOpCompleted();
279 }
280
281 protected:
282 // OpContext implementation
CreateOp()283 virtual void CreateOp() OVERRIDE {
284 op_ = SignedSettings::CreateRetrievePolicyOp(this);
285 }
286
287 private:
288 DISALLOW_COPY_AND_ASSIGN(RetrievePolicyOpContext);
289 };
290
291 } // namespace
292
293
294 class SignedSettingsHelperImpl : public SignedSettingsHelper,
295 public OpContext::Delegate {
296 public:
297 // SignedSettingsHelper implementation
298 virtual void StartCheckWhitelistOp(const std::string& email,
299 Callback* callback) OVERRIDE;
300 virtual void StartWhitelistOp(const std::string& email,
301 bool add_to_whitelist,
302 Callback* callback) OVERRIDE;
303 virtual void StartStorePropertyOp(const std::string& name,
304 const std::string& value,
305 Callback* callback) OVERRIDE;
306 virtual void StartRetrieveProperty(const std::string& name,
307 Callback* callback) OVERRIDE;
308 virtual void StartStorePolicyOp(const em::PolicyFetchResponse& policy,
309 Callback* callback) OVERRIDE;
310 virtual void StartRetrievePolicyOp(Callback* callback) OVERRIDE;
311 virtual void CancelCallback(Callback* callback) OVERRIDE;
312
313 // OpContext::Delegate implementation
314 virtual void OnOpCreated(OpContext* context);
315 virtual void OnOpStarted(OpContext* context);
316 virtual void OnOpCompleted(OpContext* context);
317
318 private:
319 SignedSettingsHelperImpl();
320 ~SignedSettingsHelperImpl();
321
322 void AddOpContext(OpContext* context);
323 void ClearAll();
324
325 std::vector<OpContext*> pending_contexts_;
326
327 friend struct base::DefaultLazyInstanceTraits<SignedSettingsHelperImpl>;
328 DISALLOW_COPY_AND_ASSIGN(SignedSettingsHelperImpl);
329 };
330
331 static base::LazyInstance<SignedSettingsHelperImpl>
332 g_signed_settings_helper_impl(base::LINKER_INITIALIZED);
333
SignedSettingsHelperImpl()334 SignedSettingsHelperImpl::SignedSettingsHelperImpl() {
335 }
336
~SignedSettingsHelperImpl()337 SignedSettingsHelperImpl::~SignedSettingsHelperImpl() {
338 if (!pending_contexts_.empty()) {
339 LOG(WARNING) << "SignedSettingsHelperImpl shutdown with pending ops, "
340 << "changes will be lost.";
341 ClearAll();
342 }
343 }
344
StartCheckWhitelistOp(const std::string & email,SignedSettingsHelper::Callback * callback)345 void SignedSettingsHelperImpl::StartCheckWhitelistOp(
346 const std::string&email,
347 SignedSettingsHelper::Callback* callback) {
348 AddOpContext(new WhitelistOpContext(
349 WhitelistOpContext::CHECK,
350 email,
351 callback,
352 this));
353 }
354
StartWhitelistOp(const std::string & email,bool add_to_whitelist,SignedSettingsHelper::Callback * callback)355 void SignedSettingsHelperImpl::StartWhitelistOp(
356 const std::string&email,
357 bool add_to_whitelist,
358 SignedSettingsHelper::Callback* callback) {
359 AddOpContext(new WhitelistOpContext(
360 add_to_whitelist ? WhitelistOpContext::ADD : WhitelistOpContext::REMOVE,
361 email,
362 callback,
363 this));
364 }
365
StartStorePropertyOp(const std::string & name,const std::string & value,SignedSettingsHelper::Callback * callback)366 void SignedSettingsHelperImpl::StartStorePropertyOp(
367 const std::string& name,
368 const std::string& value,
369 SignedSettingsHelper::Callback* callback) {
370 AddOpContext(new StorePropertyOpContext(
371 name,
372 value,
373 callback,
374 this));
375 }
376
StartRetrieveProperty(const std::string & name,SignedSettingsHelper::Callback * callback)377 void SignedSettingsHelperImpl::StartRetrieveProperty(
378 const std::string& name,
379 SignedSettingsHelper::Callback* callback) {
380 AddOpContext(new RetrievePropertyOpContext(
381 name,
382 callback,
383 this));
384 }
385
StartStorePolicyOp(const em::PolicyFetchResponse & policy,SignedSettingsHelper::Callback * callback)386 void SignedSettingsHelperImpl::StartStorePolicyOp(
387 const em::PolicyFetchResponse& policy,
388 SignedSettingsHelper::Callback* callback) {
389 AddOpContext(new StorePolicyOpContext(policy, callback, this));
390 }
391
StartRetrievePolicyOp(SignedSettingsHelper::Callback * callback)392 void SignedSettingsHelperImpl::StartRetrievePolicyOp(
393 SignedSettingsHelper::Callback* callback) {
394 AddOpContext(new RetrievePolicyOpContext(callback, this));
395 }
396
CancelCallback(SignedSettingsHelper::Callback * callback)397 void SignedSettingsHelperImpl::CancelCallback(
398 SignedSettingsHelper::Callback* callback) {
399 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
400
401 for (size_t i = 0; i < pending_contexts_.size(); ++i) {
402 if (pending_contexts_[i]->callback() == callback) {
403 pending_contexts_[i]->CancelCallback();
404 }
405 }
406 }
407
AddOpContext(OpContext * context)408 void SignedSettingsHelperImpl::AddOpContext(OpContext* context) {
409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
410 CHECK(context);
411
412 pending_contexts_.push_back(context);
413 if (pending_contexts_.size() == 1)
414 context->Execute();
415 }
416
ClearAll()417 void SignedSettingsHelperImpl::ClearAll() {
418 for (size_t i = 0; i < pending_contexts_.size(); ++i) {
419 pending_contexts_[i]->set_delegate(NULL);
420 pending_contexts_[i]->Cancel();
421 }
422 pending_contexts_.clear();
423 }
424
OnOpCreated(OpContext * context)425 void SignedSettingsHelperImpl::OnOpCreated(OpContext* context) {
426 if (test_delegate_)
427 test_delegate_->OnOpCreated(context->op());
428 }
429
OnOpStarted(OpContext * context)430 void SignedSettingsHelperImpl::OnOpStarted(OpContext* context) {
431 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
432
433 if (test_delegate_)
434 test_delegate_->OnOpStarted(context->op());
435 }
436
OnOpCompleted(OpContext * context)437 void SignedSettingsHelperImpl::OnOpCompleted(OpContext* context) {
438 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
439 DCHECK(pending_contexts_.front() == context);
440
441 pending_contexts_.erase(pending_contexts_.begin());
442 if (!pending_contexts_.empty())
443 pending_contexts_.front()->Execute();
444
445 if (test_delegate_)
446 test_delegate_->OnOpCompleted(context->op());
447 }
448
Get()449 SignedSettingsHelper* SignedSettingsHelper::Get() {
450 return g_signed_settings_helper_impl.Pointer();
451 }
452
453 } // namespace chromeos
454