Home | History | Annotate | Download | only in policy
      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/policy/managed_mode_policy_provider.h"
      6 
      7 #include "base/callback.h"
      8 #include "base/json/json_reader.h"
      9 #include "base/json/json_writer.h"
     10 #include "base/prefs/json_pref_store.h"
     11 #include "base/strings/string_util.h"
     12 #include "base/threading/sequenced_worker_pool.h"
     13 #include "chrome/browser/managed_mode/managed_mode_url_filter.h"
     14 #include "chrome/browser/policy/external_data_fetcher.h"
     15 #include "chrome/browser/policy/policy_bundle.h"
     16 #include "chrome/browser/prefs/incognito_mode_prefs.h"
     17 #include "chrome/browser/profiles/profile.h"
     18 #include "chrome/common/chrome_constants.h"
     19 #include "content/public/browser/browser_thread.h"
     20 #include "content/public/browser/user_metrics.h"
     21 #include "policy/policy_constants.h"
     22 #include "sync/api/sync_change.h"
     23 #include "sync/protocol/sync.pb.h"
     24 
     25 using base::DictionaryValue;
     26 using base::JSONReader;
     27 using base::Value;
     28 using content::BrowserThread;
     29 using content::UserMetricsAction;
     30 using syncer::MANAGED_USER_SETTINGS;
     31 using syncer::ModelType;
     32 using syncer::SyncChange;
     33 using syncer::SyncChangeList;
     34 using syncer::SyncChangeProcessor;
     35 using syncer::SyncData;
     36 using syncer::SyncDataList;
     37 using syncer::SyncError;
     38 using syncer::SyncErrorFactory;
     39 using syncer::SyncMergeResult;
     40 
     41 namespace {
     42 
     43 const char kAtomicSettings[] = "atomic_settings";
     44 const char kManagedUserInternalPolicyPrefix[] = "X-";
     45 const char kQueuedItems[] = "queued_items";
     46 const char kSplitSettingKeySeparator = ':';
     47 const char kSplitSettings[] = "split_settings";
     48 
     49 bool SettingShouldApplyToPolicy(const std::string& key) {
     50   return !StartsWithASCII(key, kManagedUserInternalPolicyPrefix, false);
     51 }
     52 
     53 }  // namespace
     54 
     55 namespace policy {
     56 
     57 
     58 // static
     59 scoped_ptr<ManagedModePolicyProvider> ManagedModePolicyProvider::Create(
     60     Profile* profile,
     61     base::SequencedTaskRunner* sequenced_task_runner,
     62     bool force_load) {
     63   base::FilePath path =
     64       profile->GetPath().Append(chrome::kManagedModePolicyFilename);
     65   JsonPrefStore* pref_store = new JsonPrefStore(path, sequenced_task_runner);
     66   // Load the data synchronously if needed (when creating profiles on startup).
     67   if (force_load)
     68     pref_store->ReadPrefs();
     69   else
     70     pref_store->ReadPrefsAsync(NULL);
     71 
     72   return make_scoped_ptr(new ManagedModePolicyProvider(pref_store));
     73 }
     74 
     75 ManagedModePolicyProvider::ManagedModePolicyProvider(
     76     PersistentPrefStore* pref_store)
     77     : store_(pref_store),
     78       local_policies_(new DictionaryValue) {
     79   store_->AddObserver(this);
     80   if (store_->IsInitializationComplete())
     81     UpdatePolicyFromCache();
     82 }
     83 
     84 ManagedModePolicyProvider::~ManagedModePolicyProvider() {}
     85 
     86 void ManagedModePolicyProvider::Clear() {
     87   store_->RemoveValue(kAtomicSettings);
     88   store_->RemoveValue(kSplitSettings);
     89 }
     90 
     91 // static
     92 std::string ManagedModePolicyProvider::MakeSplitSettingKey(
     93     const std::string& prefix,
     94     const std::string& key) {
     95   return prefix + kSplitSettingKeySeparator + key;
     96 }
     97 
     98 void ManagedModePolicyProvider::UploadItem(const std::string& key,
     99                                            scoped_ptr<Value> value) {
    100   DCHECK(!SettingShouldApplyToPolicy(key));
    101 
    102   std::string key_suffix = key;
    103   DictionaryValue* dict = NULL;
    104   if (sync_processor_) {
    105     content::RecordAction(
    106         UserMetricsAction("ManagedUsers_UploadItem_Syncing"));
    107     dict = GetDictionaryAndSplitKey(&key_suffix);
    108     DCHECK(GetQueuedItems()->empty());
    109     SyncChangeList change_list;
    110     SyncData data = CreateSyncDataForPolicy(key, value.get());
    111     SyncChange::SyncChangeType change_type =
    112         dict->HasKey(key_suffix) ? SyncChange::ACTION_UPDATE
    113                                  : SyncChange::ACTION_ADD;
    114     change_list.push_back(SyncChange(FROM_HERE, change_type, data));
    115     SyncError error =
    116         sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
    117     DCHECK(!error.IsSet()) << error.ToString();
    118   } else {
    119     content::RecordAction(
    120         UserMetricsAction("ManagedUsers_UploadItem_Queued"));
    121     dict = GetQueuedItems();
    122   }
    123   dict->SetWithoutPathExpansion(key_suffix, value.release());
    124 }
    125 
    126 void ManagedModePolicyProvider::SetLocalPolicyForTesting(
    127     const std::string& key,
    128     scoped_ptr<Value> value) {
    129   if (value)
    130     local_policies_->SetWithoutPathExpansion(key, value.release());
    131   else
    132     local_policies_->RemoveWithoutPathExpansion(key, NULL);
    133 
    134   UpdatePolicyFromCache();
    135 }
    136 
    137 // static
    138 SyncData ManagedModePolicyProvider::CreateSyncDataForPolicy(
    139     const std::string& name,
    140     const Value* value) {
    141   std::string json_value;
    142   base::JSONWriter::Write(value, &json_value);
    143   ::sync_pb::EntitySpecifics specifics;
    144   specifics.mutable_managed_user_setting()->set_name(name);
    145   specifics.mutable_managed_user_setting()->set_value(json_value);
    146   return SyncData::CreateLocalData(name, name, specifics);
    147 }
    148 
    149 void ManagedModePolicyProvider::Shutdown() {
    150   store_->RemoveObserver(this);
    151   ConfigurationPolicyProvider::Shutdown();
    152 }
    153 
    154 void ManagedModePolicyProvider::RefreshPolicies() {
    155   UpdatePolicyFromCache();
    156 }
    157 
    158 bool ManagedModePolicyProvider::IsInitializationComplete(
    159     PolicyDomain domain) const {
    160   if (domain == POLICY_DOMAIN_CHROME)
    161     return store_->IsInitializationComplete();
    162   return true;
    163 }
    164 
    165 void ManagedModePolicyProvider::OnPrefValueChanged(const std::string& key) {}
    166 
    167 void ManagedModePolicyProvider::OnInitializationCompleted(bool success) {
    168   DCHECK(success);
    169   UpdatePolicyFromCache();
    170 }
    171 
    172 SyncMergeResult ManagedModePolicyProvider::MergeDataAndStartSyncing(
    173     ModelType type,
    174     const SyncDataList& initial_sync_data,
    175     scoped_ptr<SyncChangeProcessor> sync_processor,
    176     scoped_ptr<SyncErrorFactory> error_handler) {
    177   DCHECK_EQ(MANAGED_USER_SETTINGS, type);
    178   sync_processor_ = sync_processor.Pass();
    179   error_handler_ = error_handler.Pass();
    180 
    181   // Clear all atomic and split settings, then recreate them from Sync data.
    182   Clear();
    183   for (SyncDataList::const_iterator it = initial_sync_data.begin();
    184        it != initial_sync_data.end(); ++it) {
    185     DCHECK_EQ(MANAGED_USER_SETTINGS, it->GetDataType());
    186     const ::sync_pb::ManagedUserSettingSpecifics& managed_user_setting =
    187         it->GetSpecifics().managed_user_setting();
    188     scoped_ptr<Value> value(JSONReader::Read(managed_user_setting.value()));
    189     std::string name_suffix = managed_user_setting.name();
    190     DictionaryValue* dict = GetDictionaryAndSplitKey(&name_suffix);
    191     dict->SetWithoutPathExpansion(name_suffix, value.release());
    192   }
    193   store_->ReportValueChanged(kAtomicSettings);
    194   store_->ReportValueChanged(kSplitSettings);
    195   UpdatePolicyFromCache();
    196 
    197   // Upload all the queued up items (either with an ADD or an UPDATE action,
    198   // depending on whether they already exist) and move them to split settings.
    199   SyncChangeList change_list;
    200   DictionaryValue* queued_items = GetQueuedItems();
    201   for (DictionaryValue::Iterator it(*queued_items); !it.IsAtEnd();
    202        it.Advance()) {
    203     std::string key_suffix = it.key();
    204     DictionaryValue* dict = GetDictionaryAndSplitKey(&key_suffix);
    205     SyncData data = CreateSyncDataForPolicy(it.key(), &it.value());
    206     SyncChange::SyncChangeType change_type =
    207         dict->HasKey(key_suffix) ? SyncChange::ACTION_UPDATE
    208                                  : SyncChange::ACTION_ADD;
    209     change_list.push_back(SyncChange(FROM_HERE, change_type, data));
    210     dict->SetWithoutPathExpansion(key_suffix, it.value().DeepCopy());
    211   }
    212   queued_items->Clear();
    213 
    214   SyncMergeResult result(MANAGED_USER_SETTINGS);
    215   // Process all the accumulated changes from the queued items.
    216   if (change_list.size() > 0) {
    217     store_->ReportValueChanged(kQueuedItems);
    218     result.set_error(
    219         sync_processor_->ProcessSyncChanges(FROM_HERE, change_list));
    220   }
    221 
    222   // TODO(bauerb): Statistics?
    223   return result;
    224 }
    225 
    226 void ManagedModePolicyProvider::StopSyncing(ModelType type) {
    227   DCHECK_EQ(syncer::MANAGED_USER_SETTINGS, type);
    228   sync_processor_.reset();
    229   error_handler_.reset();
    230 }
    231 
    232 SyncDataList ManagedModePolicyProvider::GetAllSyncData(ModelType type) const {
    233   DCHECK_EQ(syncer::MANAGED_USER_SETTINGS, type);
    234   SyncDataList data;
    235   for (DictionaryValue::Iterator it(*GetAtomicSettings()); !it.IsAtEnd();
    236        it.Advance()) {
    237     data.push_back(CreateSyncDataForPolicy(it.key(), &it.value()));
    238   }
    239   for (DictionaryValue::Iterator it(*GetSplitSettings()); !it.IsAtEnd();
    240        it.Advance()) {
    241     const DictionaryValue* dict = NULL;
    242     it.value().GetAsDictionary(&dict);
    243     for (DictionaryValue::Iterator jt(*dict); !jt.IsAtEnd(); jt.Advance()) {
    244       data.push_back(CreateSyncDataForPolicy(
    245           MakeSplitSettingKey(it.key(), jt.key()), &jt.value()));
    246     }
    247   }
    248   DCHECK_EQ(0u, GetQueuedItems()->size());
    249   return data;
    250 }
    251 
    252 SyncError ManagedModePolicyProvider::ProcessSyncChanges(
    253     const tracked_objects::Location& from_here,
    254     const SyncChangeList& change_list) {
    255   for (SyncChangeList::const_iterator it = change_list.begin();
    256        it != change_list.end(); ++it) {
    257     SyncData data = it->sync_data();
    258     DCHECK_EQ(MANAGED_USER_SETTINGS, data.GetDataType());
    259     const ::sync_pb::ManagedUserSettingSpecifics& managed_user_setting =
    260         data.GetSpecifics().managed_user_setting();
    261     std::string key = managed_user_setting.name();
    262     DictionaryValue* dict = GetDictionaryAndSplitKey(&key);
    263     switch (it->change_type()) {
    264       case SyncChange::ACTION_ADD:
    265       case SyncChange::ACTION_UPDATE: {
    266         scoped_ptr<Value> value(JSONReader::Read(managed_user_setting.value()));
    267         if (dict->HasKey(key)) {
    268           DLOG_IF(WARNING, it->change_type() == SyncChange::ACTION_ADD)
    269               << "Value for key " << key << " already exists";
    270         } else {
    271           DLOG_IF(WARNING, it->change_type() == SyncChange::ACTION_UPDATE)
    272               << "Value for key " << key << " doesn't exist yet";
    273         }
    274         dict->SetWithoutPathExpansion(key, value.release());
    275         break;
    276       }
    277       case SyncChange::ACTION_DELETE: {
    278         DLOG_IF(WARNING, !dict->HasKey(key)) << "Trying to delete nonexistent "
    279                                              << "key " << key;
    280         dict->RemoveWithoutPathExpansion(key, NULL);
    281         break;
    282       }
    283       case SyncChange::ACTION_INVALID: {
    284         NOTREACHED();
    285         break;
    286       }
    287     }
    288   }
    289   store_->ReportValueChanged(kAtomicSettings);
    290   store_->ReportValueChanged(kSplitSettings);
    291   UpdatePolicyFromCache();
    292 
    293   SyncError error;
    294   return error;
    295 }
    296 
    297 void ManagedModePolicyProvider::InitLocalPolicies() {
    298   local_policies_->Clear();
    299   local_policies_->SetBoolean(policy::key::kAllowDeletingBrowserHistory, false);
    300   local_policies_->SetInteger(policy::key::kContentPackDefaultFilteringBehavior,
    301                               ManagedModeURLFilter::ALLOW);
    302   local_policies_->SetBoolean(policy::key::kForceSafeSearch, true);
    303   local_policies_->SetBoolean(policy::key::kHideWebStoreIcon, true);
    304   local_policies_->SetInteger(policy::key::kIncognitoModeAvailability,
    305                               IncognitoModePrefs::DISABLED);
    306   local_policies_->SetBoolean(policy::key::kSigninAllowed, false);
    307   UpdatePolicyFromCache();
    308 }
    309 
    310 DictionaryValue* ManagedModePolicyProvider::GetOrCreateDictionary(
    311     const std::string& key) const {
    312   Value* value = NULL;
    313   DictionaryValue* dict = NULL;
    314   if (store_->GetMutableValue(key, &value)) {
    315     bool success = value->GetAsDictionary(&dict);
    316     DCHECK(success);
    317   } else {
    318     dict = new base::DictionaryValue;
    319     store_->SetValue(key, dict);
    320   }
    321 
    322   return dict;
    323 }
    324 
    325 DictionaryValue* ManagedModePolicyProvider::GetAtomicSettings() const {
    326   return GetOrCreateDictionary(kAtomicSettings);
    327 }
    328 
    329 DictionaryValue* ManagedModePolicyProvider::GetSplitSettings() const {
    330   return GetOrCreateDictionary(kSplitSettings);
    331 }
    332 
    333 DictionaryValue* ManagedModePolicyProvider::GetQueuedItems() const {
    334   return GetOrCreateDictionary(kQueuedItems);
    335 }
    336 
    337 DictionaryValue* ManagedModePolicyProvider::GetDictionaryAndSplitKey(
    338     std::string* key) const {
    339   size_t pos = key->find_first_of(kSplitSettingKeySeparator);
    340   if (pos == std::string::npos)
    341     return GetAtomicSettings();
    342 
    343   DictionaryValue* split_settings = GetSplitSettings();
    344   std::string prefix = key->substr(0, pos);
    345   DictionaryValue* dict = NULL;
    346   if (!split_settings->GetDictionary(prefix, &dict)) {
    347     dict = new DictionaryValue;
    348     DCHECK(!split_settings->HasKey(prefix));
    349     split_settings->Set(prefix, dict);
    350   }
    351   key->erase(0, pos + 1);
    352   return dict;
    353 }
    354 
    355 void ManagedModePolicyProvider::UpdatePolicyFromCache() {
    356   scoped_ptr<PolicyBundle> policy_bundle(new PolicyBundle);
    357   PolicyMap* policy_map = &policy_bundle->Get(
    358       PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
    359   policy_map->LoadFrom(
    360       local_policies_.get(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
    361 
    362   DictionaryValue* atomic_settings = GetAtomicSettings();
    363   for (DictionaryValue::Iterator it(*atomic_settings); !it.IsAtEnd();
    364        it.Advance()) {
    365     if (!SettingShouldApplyToPolicy(it.key()))
    366       continue;
    367 
    368     policy_map->Set(it.key(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
    369                     it.value().DeepCopy(), NULL);
    370   }
    371 
    372   DictionaryValue* split_settings = GetSplitSettings();
    373   for (DictionaryValue::Iterator it(*split_settings); !it.IsAtEnd();
    374        it.Advance()) {
    375     if (!SettingShouldApplyToPolicy(it.key()))
    376       continue;
    377 
    378     policy_map->Set(it.key(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
    379                     it.value().DeepCopy(), NULL);
    380   }
    381   UpdatePolicy(policy_bundle.Pass());
    382 }
    383 
    384 }  // namespace policy
    385