Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(25)

Side by Side Diff: chrome/browser/policy/cloud_policy_cache.cc

Issue 6705031: Send policy blobs to session_manager (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix nits Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.h"
6
7 #include <limits>
8
9 #include "base/file_util.h"
10 #include "base/logging.h"
11 #include "base/task.h"
12 #include "base/values.h"
13 #include "chrome/browser/policy/configuration_policy_pref_store.h"
14 #include "chrome/browser/policy/proto/cloud_policy.pb.h"
15 #include "chrome/browser/policy/proto/device_management_constants.h"
16 #include "chrome/browser/policy/proto/device_management_local.pb.h"
17 #include "content/browser/browser_thread.h"
18
19 using google::protobuf::RepeatedField;
20 using google::protobuf::RepeatedPtrField;
21
22 // This CloudPolicyCache currently supports two protocols for the interaction
23 // with DMServer: the old "DevicePolicy" format, which is being used in the
24 // CrOS Pilot Program and will be deprecated afterwards, and the new
25 // "CloudPolicy" format, which will be used exclusively after the public launch
26 // of ChromeOS.
27
28 namespace policy {
29
30 // Decodes a CloudPolicySettings object into two maps with mandatory and
31 // recommended settings, respectively. The implementation is generated code
32 // in policy/cloud_policy_generated.cc.
33 void DecodePolicy(const em::CloudPolicySettings& policy,
34 PolicyMap* mandatory, PolicyMap* recommended);
35
36 // A thin ConfigurationPolicyProvider implementation sitting on top of
37 // CloudPolicyCache for hooking up with ConfigurationPolicyPrefStore.
38 class CloudPolicyCache::CloudPolicyProvider
39 : public ConfigurationPolicyProvider {
40 public:
41 CloudPolicyProvider(const PolicyDefinitionList* policy_list,
42 CloudPolicyCache* cache,
43 CloudPolicyCache::PolicyLevel level)
44 : ConfigurationPolicyProvider(policy_list),
45 cache_(cache),
46 level_(level) {}
47 virtual ~CloudPolicyProvider() {}
48
49 virtual bool Provide(ConfigurationPolicyStoreInterface* store) {
50 if (!cache_->has_device_policy()) {
51 if (level_ == POLICY_LEVEL_MANDATORY)
52 ApplyPolicyMap(&cache_->mandatory_policy_, store);
53 else if (level_ == POLICY_LEVEL_RECOMMENDED)
54 ApplyPolicyMap(&cache_->recommended_policy_, store);
55 } else {
56 ApplyPolicyValueTree(cache_->device_policy_.get(), store);
57 }
58 return true;
59 }
60
61 virtual bool IsInitializationComplete() const {
62 return cache_->initialization_complete_;
63 }
64
65 virtual void AddObserver(ConfigurationPolicyProvider::Observer* observer) {
66 cache_->observer_list_.AddObserver(observer);
67 }
68 virtual void RemoveObserver(ConfigurationPolicyProvider::Observer* observer) {
69 cache_->observer_list_.RemoveObserver(observer);
70 }
71
72 private:
73 // The underlying policy cache.
74 CloudPolicyCache* cache_;
75 // Policy level this provider will handle.
76 CloudPolicyCache::PolicyLevel level_;
77
78 DISALLOW_COPY_AND_ASSIGN(CloudPolicyProvider);
79 };
80
81 // Saves policy information to a file.
82 class PersistPolicyTask : public Task {
83 public:
84 PersistPolicyTask(const FilePath& path,
85 const em::PolicyFetchResponse* cloud_policy_response,
86 const em::DevicePolicyResponse* device_policy_response,
87 const bool is_unmanaged)
88 : path_(path),
89 cloud_policy_response_(cloud_policy_response),
90 device_policy_response_(device_policy_response),
91 is_unmanaged_(is_unmanaged) {}
92
93 private:
94 // Task override.
95 virtual void Run();
96
97 const FilePath path_;
98 scoped_ptr<const em::PolicyFetchResponse> cloud_policy_response_;
99 scoped_ptr<const em::DevicePolicyResponse> device_policy_response_;
100 const bool is_unmanaged_;
101 };
102
103 void PersistPolicyTask::Run() {
104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
105 std::string data;
106 em::CachedCloudPolicyResponse cached_policy;
107 if (cloud_policy_response_.get()) {
108 cached_policy.mutable_cloud_policy()->CopyFrom(*cloud_policy_response_);
109 } else if (device_policy_response_.get()) {
110 cached_policy.mutable_device_policy()->CopyFrom(*device_policy_response_);
111 cached_policy.set_timestamp(base::Time::NowFromSystemTime().ToTimeT());
112 }
113 if (is_unmanaged_) {
114 cached_policy.set_unmanaged(true);
115 cached_policy.set_timestamp(base::Time::NowFromSystemTime().ToTimeT());
116 }
117 if (!cached_policy.SerializeToString(&data)) {
118 LOG(WARNING) << "Failed to serialize policy data";
119 return;
120 }
121
122 int size = data.size();
123 if (file_util::WriteFile(path_, data.c_str(), size) != size) {
124 LOG(WARNING) << "Failed to write " << path_.value();
125 return;
126 }
127 }
128
129 CloudPolicyCache::CloudPolicyCache(
130 const FilePath& backing_file_path)
131 : backing_file_path_(backing_file_path),
132 device_policy_(new DictionaryValue),
133 initialization_complete_(false),
134 is_unmanaged_(false),
135 has_device_policy_(false) {
136 managed_policy_provider_.reset(
137 new CloudPolicyProvider(
138 ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(),
139 this,
140 POLICY_LEVEL_MANDATORY));
141 recommended_policy_provider_.reset(
142 new CloudPolicyProvider(
143 ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(),
144 this,
145 POLICY_LEVEL_RECOMMENDED));
146 }
147
148 CloudPolicyCache::~CloudPolicyCache() {
149 FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
150 observer_list_, OnProviderGoingAway());
151 }
152
153 void CloudPolicyCache::LoadFromFile() {
154 // TODO(jkummerow): This method is doing file IO during browser startup. In
155 // the long run it would be better to delay this until the FILE thread exists.
156 if (!file_util::PathExists(backing_file_path_) || initialization_complete_) {
157 return;
158 }
159
160 // Read the protobuf from the file.
161 std::string data;
162 if (!file_util::ReadFileToString(backing_file_path_, &data)) {
163 LOG(WARNING) << "Failed to read policy data from "
164 << backing_file_path_.value();
165 return;
166 }
167
168 em::CachedCloudPolicyResponse cached_response;
169 if (!cached_response.ParseFromArray(data.c_str(), data.size())) {
170 LOG(WARNING) << "Failed to parse policy data read from "
171 << backing_file_path_.value();
172 return;
173 }
174 base::Time timestamp;
175 PolicyMap mandatory_policy;
176 PolicyMap recommended_policy;
177 is_unmanaged_ = cached_response.unmanaged();
178 if (is_unmanaged_ || cached_response.has_device_policy())
179 timestamp = base::Time::FromTimeT(cached_response.timestamp());
180 if (cached_response.has_cloud_policy()) {
181 DCHECK(!is_unmanaged_);
182 bool ok = DecodePolicyResponse(cached_response.cloud_policy(),
183 &mandatory_policy,
184 &recommended_policy,
185 &timestamp);
186 if (!ok) {
187 LOG(WARNING) << "Decoding policy data failed.";
188 return;
189 }
190 }
191 if (timestamp > base::Time::NowFromSystemTime()) {
192 LOG(WARNING) << "Rejected policy data from " << backing_file_path_.value()
193 << ", file is from the future.";
194 return;
195 }
196 // Swap in the new policy information.
197 if (cached_response.has_cloud_policy()) {
198 mandatory_policy_.Swap(&mandatory_policy);
199 recommended_policy_.Swap(&recommended_policy);
200 has_device_policy_ = false;
201 } else if (cached_response.has_device_policy()) {
202 scoped_ptr<DictionaryValue> value(
203 DecodeDevicePolicy(cached_response.device_policy()));
204 device_policy_.reset(value.release());
205 has_device_policy_ = true;
206 }
207 last_policy_refresh_time_ = timestamp;
208 initialization_complete_ = true;
209
210 FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
211 observer_list_, OnUpdatePolicy());
212 }
213
214 void CloudPolicyCache::SetPolicy(const em::PolicyFetchResponse& policy) {
215 DCHECK(CalledOnValidThread());
216 bool initialization_was_not_complete = !initialization_complete_;
217 is_unmanaged_ = false;
218 last_policy_refresh_time_ = base::Time::NowFromSystemTime();
219 base::Time timestamp;
220 PolicyMap mandatory_policy;
221 PolicyMap recommended_policy;
222 bool ok = DecodePolicyResponse(policy, &mandatory_policy, &recommended_policy,
223 &timestamp);
224 if (!ok)
225 return;
226
227 const bool new_policy_differs =
228 !mandatory_policy_.Equals(mandatory_policy) ||
229 !recommended_policy_.Equals(recommended_policy);
230 mandatory_policy_.Swap(&mandatory_policy);
231 recommended_policy_.Swap(&recommended_policy);
232 initialization_complete_ = true;
233 has_device_policy_ = false;
234
235 if (new_policy_differs || initialization_was_not_complete) {
236 FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
237 observer_list_, OnUpdatePolicy());
238 }
239
240 if (timestamp > base::Time::NowFromSystemTime() +
241 base::TimeDelta::FromMinutes(1)) {
242 LOG(WARNING) << "Server returned policy with timestamp from the future, "
243 "not persisting to disk.";
244 } else {
245 em::PolicyFetchResponse* policy_copy = new em::PolicyFetchResponse;
246 policy_copy->CopyFrom(policy);
247 BrowserThread::PostTask(
248 BrowserThread::FILE,
249 FROM_HERE,
250 new PersistPolicyTask(backing_file_path_, policy_copy, NULL, false));
251 }
252 }
253
254 void CloudPolicyCache::SetDevicePolicy(const em::DevicePolicyResponse& policy) {
255 DCHECK(CalledOnValidThread());
256 bool initialization_was_not_complete = !initialization_complete_;
257 is_unmanaged_ = false;
258 DictionaryValue* value = DecodeDevicePolicy(policy);
259 const bool new_policy_differs = !(value->Equals(device_policy_.get()));
260 base::Time now(base::Time::NowFromSystemTime());
261 device_policy_.reset(value);
262 initialization_complete_ = true;
263 last_policy_refresh_time_ = now;
264 has_device_policy_ = true;
265
266 if (new_policy_differs || initialization_was_not_complete) {
267 FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
268 observer_list_, OnUpdatePolicy());
269 }
270
271 em::DevicePolicyResponse* policy_copy = new em::DevicePolicyResponse;
272 policy_copy->CopyFrom(policy);
273 BrowserThread::PostTask(
274 BrowserThread::FILE,
275 FROM_HERE,
276 new PersistPolicyTask(backing_file_path_, NULL, policy_copy, false));
277 }
278
279 ConfigurationPolicyProvider* CloudPolicyCache::GetManagedPolicyProvider() {
280 DCHECK(CalledOnValidThread());
281 return managed_policy_provider_.get();
282 }
283
284 ConfigurationPolicyProvider* CloudPolicyCache::GetRecommendedPolicyProvider() {
285 DCHECK(CalledOnValidThread());
286 return recommended_policy_provider_.get();
287 }
288
289 void CloudPolicyCache::SetUnmanaged() {
290 DCHECK(CalledOnValidThread());
291 is_unmanaged_ = true;
292 mandatory_policy_.Clear();
293 recommended_policy_.Clear();
294 device_policy_.reset(new DictionaryValue);
295 last_policy_refresh_time_ = base::Time::NowFromSystemTime();
296
297 FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
298 observer_list_, OnUpdatePolicy());
299
300 BrowserThread::PostTask(
301 BrowserThread::FILE,
302 FROM_HERE,
303 new PersistPolicyTask(backing_file_path_, NULL, NULL, true));
304 }
305
306 // static
307 bool CloudPolicyCache::DecodePolicyResponse(
308 const em::PolicyFetchResponse& policy_response,
309 PolicyMap* mandatory,
310 PolicyMap* recommended,
311 base::Time* timestamp) {
312 std::string data = policy_response.policy_data();
313
314 em::PolicyData policy_data;
315 if (!policy_data.ParseFromString(data)) {
316 LOG(WARNING) << "Failed to parse PolicyData protobuf.";
317 return false;
318 }
319
320 // TODO(jkummerow): Verify policy_data.device_token(). Needs final
321 // specification which token we're actually sending / expecting to get back.
322
323 // TODO(jkummerow): Store policy_data.device_name(), if we decide to transfer
324 // it from the server to the client.
325
326 *timestamp = base::Time::UnixEpoch() +
327 base::TimeDelta::FromMilliseconds(policy_data.timestamp());
328 em::CloudPolicySettings policy;
329 if (!policy.ParseFromString(policy_data.policy_value())) {
330 LOG(WARNING) << "Failed to parse CloudPolicySettings protobuf.";
331 return false;
332 }
333 DecodePolicy(policy, mandatory, recommended);
334 return true;
335 }
336
337 // static
338 bool CloudPolicyCache::VerifySignature(
339 const std::string& signature,
340 const std::string& data,
341 const RepeatedPtrField<std::string>& certificate_chain) {
342 // TODO(jkummerow): Implement this. Non-trivial because we want to do it
343 // for all platforms -> it's enough work to deserve its own CL.
344 // Don't forget to also verify the hostname of the server against the cert.
345 return true;
346 }
347
348 // static
349 Value* CloudPolicyCache::DecodeIntegerValue(google::protobuf::int64 value) {
350 if (value < std::numeric_limits<int>::min() ||
351 value > std::numeric_limits<int>::max()) {
352 LOG(WARNING) << "Integer value " << value
353 << " out of numeric limits, ignoring.";
354 return NULL;
355 }
356
357 return Value::CreateIntegerValue(static_cast<int>(value));
358 }
359
360 // static
361 Value* CloudPolicyCache::DecodeValue(const em::GenericValue& value) {
362 if (!value.has_value_type())
363 return NULL;
364
365 switch (value.value_type()) {
366 case em::GenericValue::VALUE_TYPE_BOOL:
367 if (value.has_bool_value())
368 return Value::CreateBooleanValue(value.bool_value());
369 return NULL;
370 case em::GenericValue::VALUE_TYPE_INT64:
371 if (value.has_int64_value())
372 return DecodeIntegerValue(value.int64_value());
373 return NULL;
374 case em::GenericValue::VALUE_TYPE_STRING:
375 if (value.has_string_value())
376 return Value::CreateStringValue(value.string_value());
377 return NULL;
378 case em::GenericValue::VALUE_TYPE_DOUBLE:
379 if (value.has_double_value())
380 return Value::CreateDoubleValue(value.double_value());
381 return NULL;
382 case em::GenericValue::VALUE_TYPE_BYTES:
383 if (value.has_bytes_value()) {
384 std::string bytes = value.bytes_value();
385 return BinaryValue::CreateWithCopiedBuffer(bytes.c_str(), bytes.size());
386 }
387 return NULL;
388 case em::GenericValue::VALUE_TYPE_BOOL_ARRAY: {
389 ListValue* list = new ListValue;
390 RepeatedField<bool>::const_iterator i;
391 for (i = value.bool_array().begin(); i != value.bool_array().end(); ++i)
392 list->Append(Value::CreateBooleanValue(*i));
393 return list;
394 }
395 case em::GenericValue::VALUE_TYPE_INT64_ARRAY: {
396 ListValue* list = new ListValue;
397 RepeatedField<google::protobuf::int64>::const_iterator i;
398 for (i = value.int64_array().begin();
399 i != value.int64_array().end(); ++i) {
400 Value* int_value = DecodeIntegerValue(*i);
401 if (int_value)
402 list->Append(int_value);
403 }
404 return list;
405 }
406 case em::GenericValue::VALUE_TYPE_STRING_ARRAY: {
407 ListValue* list = new ListValue;
408 RepeatedPtrField<std::string>::const_iterator i;
409 for (i = value.string_array().begin();
410 i != value.string_array().end(); ++i)
411 list->Append(Value::CreateStringValue(*i));
412 return list;
413 }
414 case em::GenericValue::VALUE_TYPE_DOUBLE_ARRAY: {
415 ListValue* list = new ListValue;
416 RepeatedField<double>::const_iterator i;
417 for (i = value.double_array().begin();
418 i != value.double_array().end(); ++i)
419 list->Append(Value::CreateDoubleValue(*i));
420 return list;
421 }
422 default:
423 NOTREACHED() << "Unhandled value type";
424 }
425
426 return NULL;
427 }
428
429 // static
430 DictionaryValue* CloudPolicyCache::DecodeDevicePolicy(
431 const em::DevicePolicyResponse& policy) {
432 DictionaryValue* result = new DictionaryValue;
433 RepeatedPtrField<em::DevicePolicySetting>::const_iterator setting;
434 for (setting = policy.setting().begin();
435 setting != policy.setting().end();
436 ++setting) {
437 // Wrong policy key? Skip.
438 if (setting->policy_key().compare(kChromeDevicePolicySettingKey) != 0)
439 continue;
440
441 // No policy value? Skip.
442 if (!setting->has_policy_value())
443 continue;
444
445 // Iterate through all the name-value pairs wrapped in |setting|.
446 const em::GenericSetting& policy_value(setting->policy_value());
447 RepeatedPtrField<em::GenericNamedValue>::const_iterator named_value;
448 for (named_value = policy_value.named_value().begin();
449 named_value != policy_value.named_value().end();
450 ++named_value) {
451 if (named_value->has_value()) {
452 Value* decoded_value =
453 CloudPolicyCache::DecodeValue(named_value->value());
454 if (decoded_value)
455 result->Set(named_value->name(), decoded_value);
456 }
457 }
458 }
459 return result;
460 }
461
462 } // namespace policy
OLDNEW
« no previous file with comments | « chrome/browser/policy/cloud_policy_cache.h ('k') | chrome/browser/policy/cloud_policy_cache_base.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698