// 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