Home | History | Annotate | Download | only in login
      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 
     30   virtual ~OpContext() {}
     31 
     32   // Creates and execute op.
     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.
     50   void CancelCallback() {
     51     callback_ = NULL;
     52   }
     53 
     54   // Cancels the callback and cancels the op if it is not executing.
     55   void Cancel() {
     56     CancelCallback();
     57 
     58     if (!executing_)
     59       OnOpCompleted();
     60   }
     61 
     62   // Accessors.
     63   SignedSettings* op() const {
     64     return op_.get();
     65   }
     66 
     67   SignedSettingsHelper::Callback* callback() const {
     68     return callback_;
     69   }
     70 
     71   void set_delegate(Delegate* delegate) {
     72     delegate_ = delegate;
     73   }
     74 
     75  protected:
     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.
     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 
    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
    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
    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:
    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
    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
    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:
    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
    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
    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:
    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
    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
    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:
    267   RetrievePolicyOpContext(SignedSettingsHelper::Callback* callback,
    268                           OpContext::Delegate* delegate)
    269       : OpContext(callback, delegate) {
    270   }
    271 
    272   // chromeos::SignedSettings::Delegate implementation
    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
    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 
    334 SignedSettingsHelperImpl::SignedSettingsHelperImpl() {
    335 }
    336 
    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 
    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 
    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 
    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 
    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 
    386 void SignedSettingsHelperImpl::StartStorePolicyOp(
    387     const em::PolicyFetchResponse& policy,
    388     SignedSettingsHelper::Callback* callback) {
    389   AddOpContext(new StorePolicyOpContext(policy, callback, this));
    390 }
    391 
    392 void SignedSettingsHelperImpl::StartRetrievePolicyOp(
    393     SignedSettingsHelper::Callback* callback) {
    394   AddOpContext(new RetrievePolicyOpContext(callback, this));
    395 }
    396 
    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 
    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 
    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 
    425 void SignedSettingsHelperImpl::OnOpCreated(OpContext* context) {
    426   if (test_delegate_)
    427     test_delegate_->OnOpCreated(context->op());
    428 }
    429 
    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 
    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 
    449 SignedSettingsHelper* SignedSettingsHelper::Get() {
    450   return g_signed_settings_helper_impl.Pointer();
    451 }
    452 
    453 }  // namespace chromeos
    454