| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/policy/cloud_policy_cache_base.h" |
| |
| #include <string> |
| |
| #include "base/logging.h" |
| #include "base/values.h" |
| #include "chrome/browser/policy/configuration_policy_pref_store.h" |
| #include "chrome/browser/policy/policy_notifier.h" |
| |
| namespace policy { |
| |
| // A thin ConfigurationPolicyProvider implementation sitting on top of |
| // CloudPolicyCacheBase for hooking up with ConfigurationPolicyPrefStore. |
| class CloudPolicyCacheBase::CloudPolicyProvider |
| : public ConfigurationPolicyProvider { |
| public: |
| CloudPolicyProvider(const PolicyDefinitionList* policy_list, |
| CloudPolicyCacheBase* cache, |
| CloudPolicyCacheBase::PolicyLevel level) |
| : ConfigurationPolicyProvider(policy_list), |
| cache_(cache), |
| level_(level) {} |
| virtual ~CloudPolicyProvider() {} |
| |
| virtual bool Provide(ConfigurationPolicyStoreInterface* store) { |
| if (level_ == POLICY_LEVEL_MANDATORY) |
| ApplyPolicyMap(&cache_->mandatory_policy_, store); |
| else if (level_ == POLICY_LEVEL_RECOMMENDED) |
| ApplyPolicyMap(&cache_->recommended_policy_, store); |
| return true; |
| } |
| |
| virtual bool IsInitializationComplete() const { |
| return cache_->initialization_complete_; |
| } |
| |
| virtual void AddObserver(ConfigurationPolicyProvider::Observer* observer) { |
| cache_->observer_list_.AddObserver(observer); |
| } |
| virtual void RemoveObserver(ConfigurationPolicyProvider::Observer* observer) { |
| cache_->observer_list_.RemoveObserver(observer); |
| } |
| |
| private: |
| // The underlying policy cache. |
| CloudPolicyCacheBase* cache_; |
| // Policy level this provider will handle. |
| CloudPolicyCacheBase::PolicyLevel level_; |
| |
| DISALLOW_COPY_AND_ASSIGN(CloudPolicyProvider); |
| }; |
| |
| CloudPolicyCacheBase::CloudPolicyCacheBase() |
| : notifier_(NULL), |
| initialization_complete_(false), |
| is_unmanaged_(false) { |
| public_key_version_.valid = false; |
| managed_policy_provider_.reset( |
| new CloudPolicyProvider( |
| ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(), |
| this, |
| POLICY_LEVEL_MANDATORY)); |
| recommended_policy_provider_.reset( |
| new CloudPolicyProvider( |
| ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(), |
| this, |
| POLICY_LEVEL_RECOMMENDED)); |
| } |
| |
| CloudPolicyCacheBase::~CloudPolicyCacheBase() { |
| FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer, |
| observer_list_, OnProviderGoingAway()); |
| } |
| |
| bool CloudPolicyCacheBase::GetPublicKeyVersion(int* version) { |
| if (public_key_version_.valid) |
| *version = public_key_version_.version; |
| |
| return public_key_version_.valid; |
| } |
| |
| bool CloudPolicyCacheBase::SetPolicyInternal( |
| const em::PolicyFetchResponse& policy, |
| base::Time* timestamp, |
| bool check_for_timestamp_validity) { |
| DCHECK(CalledOnValidThread()); |
| bool initialization_was_not_complete = !initialization_complete_; |
| is_unmanaged_ = false; |
| PolicyMap mandatory_policy; |
| PolicyMap recommended_policy; |
| base::Time temp_timestamp; |
| PublicKeyVersion temp_public_key_version; |
| bool ok = DecodePolicyResponse(policy, &mandatory_policy, &recommended_policy, |
| &temp_timestamp, &temp_public_key_version); |
| if (!ok) { |
| LOG(WARNING) << "Decoding policy data failed."; |
| return false; |
| } |
| if (timestamp) { |
| *timestamp = temp_timestamp; |
| } |
| if (check_for_timestamp_validity && |
| temp_timestamp > base::Time::NowFromSystemTime()) { |
| LOG(WARNING) << "Rejected policy data, file is from the future."; |
| return false; |
| } |
| public_key_version_.version = temp_public_key_version.version; |
| public_key_version_.valid = temp_public_key_version.valid; |
| |
| const bool new_policy_differs = |
| !mandatory_policy_.Equals(mandatory_policy) || |
| !recommended_policy_.Equals(recommended_policy); |
| mandatory_policy_.Swap(&mandatory_policy); |
| recommended_policy_.Swap(&recommended_policy); |
| initialization_complete_ = true; |
| |
| if (new_policy_differs || initialization_was_not_complete) { |
| FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer, |
| observer_list_, OnUpdatePolicy()); |
| } |
| InformNotifier(CloudPolicySubsystem::SUCCESS, |
| CloudPolicySubsystem::NO_DETAILS); |
| return true; |
| } |
| |
| void CloudPolicyCacheBase::SetUnmanagedInternal(const base::Time& timestamp) { |
| is_unmanaged_ = true; |
| initialization_complete_ = true; |
| public_key_version_.valid = false; |
| mandatory_policy_.Clear(); |
| recommended_policy_.Clear(); |
| last_policy_refresh_time_ = timestamp; |
| |
| FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer, |
| observer_list_, OnUpdatePolicy()); |
| } |
| |
| ConfigurationPolicyProvider* CloudPolicyCacheBase::GetManagedPolicyProvider() { |
| DCHECK(CalledOnValidThread()); |
| return managed_policy_provider_.get(); |
| } |
| |
| ConfigurationPolicyProvider* |
| CloudPolicyCacheBase::GetRecommendedPolicyProvider() { |
| DCHECK(CalledOnValidThread()); |
| return recommended_policy_provider_.get(); |
| } |
| |
| bool CloudPolicyCacheBase::DecodePolicyResponse( |
| const em::PolicyFetchResponse& policy_response, |
| PolicyMap* mandatory, |
| PolicyMap* recommended, |
| base::Time* timestamp, |
| PublicKeyVersion* public_key_version) { |
| std::string data = policy_response.policy_data(); |
| em::PolicyData policy_data; |
| if (!policy_data.ParseFromString(data)) { |
| LOG(WARNING) << "Failed to parse PolicyData protobuf."; |
| return false; |
| } |
| if (timestamp) { |
| *timestamp = base::Time::UnixEpoch() + |
| base::TimeDelta::FromMilliseconds(policy_data.timestamp()); |
| } |
| if (public_key_version) { |
| public_key_version->valid = policy_data.has_public_key_version(); |
| if (public_key_version->valid) |
| public_key_version->version = policy_data.public_key_version(); |
| } |
| |
| return DecodePolicyData(policy_data, mandatory, recommended); |
| } |
| |
| void CloudPolicyCacheBase::InformNotifier( |
| CloudPolicySubsystem::PolicySubsystemState state, |
| CloudPolicySubsystem::ErrorDetails error_details) { |
| // TODO(jkummerow): To obsolete this NULL-check, make all uses of |
| // UserPolicyCache explicitly set a notifier using |set_policy_notifier()|. |
| if (notifier_) |
| notifier_->Inform(state, error_details, PolicyNotifier::POLICY_CACHE); |
| } |
| |
| } // namespace policy |