• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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