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/policy/cloud_policy_cache_base.h"
6
7 #include <string>
8
9 #include "base/logging.h"
10 #include "base/values.h"
11 #include "chrome/browser/policy/configuration_policy_pref_store.h"
12 #include "chrome/browser/policy/policy_notifier.h"
13
14 namespace policy {
15
16 // A thin ConfigurationPolicyProvider implementation sitting on top of
17 // CloudPolicyCacheBase for hooking up with ConfigurationPolicyPrefStore.
18 class CloudPolicyCacheBase::CloudPolicyProvider
19 : public ConfigurationPolicyProvider {
20 public:
CloudPolicyProvider(const PolicyDefinitionList * policy_list,CloudPolicyCacheBase * cache,CloudPolicyCacheBase::PolicyLevel level)21 CloudPolicyProvider(const PolicyDefinitionList* policy_list,
22 CloudPolicyCacheBase* cache,
23 CloudPolicyCacheBase::PolicyLevel level)
24 : ConfigurationPolicyProvider(policy_list),
25 cache_(cache),
26 level_(level) {}
~CloudPolicyProvider()27 virtual ~CloudPolicyProvider() {}
28
Provide(ConfigurationPolicyStoreInterface * store)29 virtual bool Provide(ConfigurationPolicyStoreInterface* store) {
30 if (level_ == POLICY_LEVEL_MANDATORY)
31 ApplyPolicyMap(&cache_->mandatory_policy_, store);
32 else if (level_ == POLICY_LEVEL_RECOMMENDED)
33 ApplyPolicyMap(&cache_->recommended_policy_, store);
34 return true;
35 }
36
IsInitializationComplete() const37 virtual bool IsInitializationComplete() const {
38 return cache_->initialization_complete_;
39 }
40
AddObserver(ConfigurationPolicyProvider::Observer * observer)41 virtual void AddObserver(ConfigurationPolicyProvider::Observer* observer) {
42 cache_->observer_list_.AddObserver(observer);
43 }
RemoveObserver(ConfigurationPolicyProvider::Observer * observer)44 virtual void RemoveObserver(ConfigurationPolicyProvider::Observer* observer) {
45 cache_->observer_list_.RemoveObserver(observer);
46 }
47
48 private:
49 // The underlying policy cache.
50 CloudPolicyCacheBase* cache_;
51 // Policy level this provider will handle.
52 CloudPolicyCacheBase::PolicyLevel level_;
53
54 DISALLOW_COPY_AND_ASSIGN(CloudPolicyProvider);
55 };
56
CloudPolicyCacheBase()57 CloudPolicyCacheBase::CloudPolicyCacheBase()
58 : notifier_(NULL),
59 initialization_complete_(false),
60 is_unmanaged_(false) {
61 public_key_version_.valid = false;
62 managed_policy_provider_.reset(
63 new CloudPolicyProvider(
64 ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(),
65 this,
66 POLICY_LEVEL_MANDATORY));
67 recommended_policy_provider_.reset(
68 new CloudPolicyProvider(
69 ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(),
70 this,
71 POLICY_LEVEL_RECOMMENDED));
72 }
73
~CloudPolicyCacheBase()74 CloudPolicyCacheBase::~CloudPolicyCacheBase() {
75 FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
76 observer_list_, OnProviderGoingAway());
77 }
78
GetPublicKeyVersion(int * version)79 bool CloudPolicyCacheBase::GetPublicKeyVersion(int* version) {
80 if (public_key_version_.valid)
81 *version = public_key_version_.version;
82
83 return public_key_version_.valid;
84 }
85
SetPolicyInternal(const em::PolicyFetchResponse & policy,base::Time * timestamp,bool check_for_timestamp_validity)86 bool CloudPolicyCacheBase::SetPolicyInternal(
87 const em::PolicyFetchResponse& policy,
88 base::Time* timestamp,
89 bool check_for_timestamp_validity) {
90 DCHECK(CalledOnValidThread());
91 bool initialization_was_not_complete = !initialization_complete_;
92 is_unmanaged_ = false;
93 PolicyMap mandatory_policy;
94 PolicyMap recommended_policy;
95 base::Time temp_timestamp;
96 PublicKeyVersion temp_public_key_version;
97 bool ok = DecodePolicyResponse(policy, &mandatory_policy, &recommended_policy,
98 &temp_timestamp, &temp_public_key_version);
99 if (!ok) {
100 LOG(WARNING) << "Decoding policy data failed.";
101 return false;
102 }
103 if (timestamp) {
104 *timestamp = temp_timestamp;
105 }
106 if (check_for_timestamp_validity &&
107 temp_timestamp > base::Time::NowFromSystemTime()) {
108 LOG(WARNING) << "Rejected policy data, file is from the future.";
109 return false;
110 }
111 public_key_version_.version = temp_public_key_version.version;
112 public_key_version_.valid = temp_public_key_version.valid;
113
114 const bool new_policy_differs =
115 !mandatory_policy_.Equals(mandatory_policy) ||
116 !recommended_policy_.Equals(recommended_policy);
117 mandatory_policy_.Swap(&mandatory_policy);
118 recommended_policy_.Swap(&recommended_policy);
119 initialization_complete_ = true;
120
121 if (new_policy_differs || initialization_was_not_complete) {
122 FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
123 observer_list_, OnUpdatePolicy());
124 }
125 InformNotifier(CloudPolicySubsystem::SUCCESS,
126 CloudPolicySubsystem::NO_DETAILS);
127 return true;
128 }
129
SetUnmanagedInternal(const base::Time & timestamp)130 void CloudPolicyCacheBase::SetUnmanagedInternal(const base::Time& timestamp) {
131 is_unmanaged_ = true;
132 initialization_complete_ = true;
133 public_key_version_.valid = false;
134 mandatory_policy_.Clear();
135 recommended_policy_.Clear();
136 last_policy_refresh_time_ = timestamp;
137
138 FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
139 observer_list_, OnUpdatePolicy());
140 }
141
GetManagedPolicyProvider()142 ConfigurationPolicyProvider* CloudPolicyCacheBase::GetManagedPolicyProvider() {
143 DCHECK(CalledOnValidThread());
144 return managed_policy_provider_.get();
145 }
146
147 ConfigurationPolicyProvider*
GetRecommendedPolicyProvider()148 CloudPolicyCacheBase::GetRecommendedPolicyProvider() {
149 DCHECK(CalledOnValidThread());
150 return recommended_policy_provider_.get();
151 }
152
DecodePolicyResponse(const em::PolicyFetchResponse & policy_response,PolicyMap * mandatory,PolicyMap * recommended,base::Time * timestamp,PublicKeyVersion * public_key_version)153 bool CloudPolicyCacheBase::DecodePolicyResponse(
154 const em::PolicyFetchResponse& policy_response,
155 PolicyMap* mandatory,
156 PolicyMap* recommended,
157 base::Time* timestamp,
158 PublicKeyVersion* public_key_version) {
159 std::string data = policy_response.policy_data();
160 em::PolicyData policy_data;
161 if (!policy_data.ParseFromString(data)) {
162 LOG(WARNING) << "Failed to parse PolicyData protobuf.";
163 return false;
164 }
165 if (timestamp) {
166 *timestamp = base::Time::UnixEpoch() +
167 base::TimeDelta::FromMilliseconds(policy_data.timestamp());
168 }
169 if (public_key_version) {
170 public_key_version->valid = policy_data.has_public_key_version();
171 if (public_key_version->valid)
172 public_key_version->version = policy_data.public_key_version();
173 }
174
175 return DecodePolicyData(policy_data, mandatory, recommended);
176 }
177
InformNotifier(CloudPolicySubsystem::PolicySubsystemState state,CloudPolicySubsystem::ErrorDetails error_details)178 void CloudPolicyCacheBase::InformNotifier(
179 CloudPolicySubsystem::PolicySubsystemState state,
180 CloudPolicySubsystem::ErrorDetails error_details) {
181 // TODO(jkummerow): To obsolete this NULL-check, make all uses of
182 // UserPolicyCache explicitly set a notifier using |set_policy_notifier()|.
183 if (notifier_)
184 notifier_->Inform(state, error_details, PolicyNotifier::POLICY_CACHE);
185 }
186
187 } // namespace policy
188