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

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

Issue 6409040: New policy protobuf protocol. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Ready for review! Created 9 years, 10 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/browser_thread.h"
14 #include "chrome/browser/policy/proto/cloud_policy.pb.h"
15 #include "chrome/browser/policy/proto/device_management_backend.pb.h"
16 #include "chrome/browser/policy/proto/device_management_constants.h"
17 #include "chrome/browser/policy/proto/device_management_local.pb.h"
18 // configuration_policy_type.h is generated. See policy_templates.json for
19 // policy definitions.
20 #include "policy/configuration_policy_type.h"
21
22 using google::protobuf::RepeatedPtrField;
23
24 namespace policy {
25
26 // Saves policy information to a file.
27 class PersistCloudPolicyTask : public Task {
28 public:
29 PersistCloudPolicyTask(const FilePath& path,
30 const em::CloudPolicyResponse* policy_response,
31 const bool is_unmanaged)
32 : path_(path),
33 policy_response_(policy_response),
34 is_unmanaged_(is_unmanaged) {}
35
36 private:
37 // Task override.
38 virtual void Run();
39
40 const FilePath path_;
41 scoped_ptr<const em::CloudPolicyResponse> policy_response_;
42 const bool is_unmanaged_;
43 };
44
45 void PersistCloudPolicyTask::Run() {
46 std::string data;
47 em::CachedCloudPolicyResponse cached_policy;
48 if (policy_response_.get())
49 cached_policy.mutable_policy_response()->CopyFrom(*policy_response_);
50 if (is_unmanaged_) {
51 cached_policy.set_unmanaged(true);
52 cached_policy.set_timestamp(
53 base::Time::NowFromSystemTime().ToTimeT());
54 }
55 if (!cached_policy.SerializeToString(&data)) {
56 LOG(WARNING) << "Failed to serialize policy data";
57 return;
58 }
59
60 int size = data.size();
61 if (file_util::WriteFile(path_, data.c_str(), size) != size) {
62 LOG(WARNING) << "Failed to write " << path_.value();
63 return;
64 }
65 }
66
67 CloudPolicyCache::CloudPolicyCache(
68 const FilePath& backing_file_path)
69 : backing_file_path_(backing_file_path),
70 mandatory_policy_(new PolicyMapType),
71 recommended_policy_(new PolicyMapType),
72 fresh_policy_(false),
73 is_unmanaged_(false) {
74 }
75
76 CloudPolicyCache::~CloudPolicyCache() {}
77
78 void CloudPolicyCache::LoadPolicyFromFile() {
79 if (!file_util::PathExists(backing_file_path_) || fresh_policy_) {
80 return;
81 }
82
83 // Read the protobuf from the file.
84 std::string data;
85 if (!file_util::ReadFileToString(backing_file_path_, &data)) {
86 LOG(WARNING) << "Failed to read policy data from "
87 << backing_file_path_.value();
88 return;
89 }
90
91 em::CachedCloudPolicyResponse cached_response;
92 if (!cached_response.ParseFromArray(data.c_str(), data.size())) {
93 LOG(WARNING) << "Failed to parse policy data read from "
94 << backing_file_path_.value();
95 return;
96 }
97 base::Time timestamp;
98 is_unmanaged_ = cached_response.unmanaged();
99 // Decode and swap in the new policy information.
100 scoped_ptr<PolicyMapType> mandatory_policy_map(new PolicyMapType);
101 scoped_ptr<PolicyMapType> recommended_policy_map(new PolicyMapType);
102 bool ok = DecodePolicyResponse(cached_response.policy_response(),
103 mandatory_policy_map.get(),
104 recommended_policy_map.get(),
105 &timestamp);
106 if (is_unmanaged_) {
107 timestamp = base::Time::FromTimeT(cached_response.timestamp());
108 } else {
109 if (!ok) {
110 LOG(WARNING) << "Decoding policy data failed.";
111 return;
112 }
113 }
114 {
115 base::AutoLock lock(lock_);
116 if (!fresh_policy_)
117 mandatory_policy_.reset(mandatory_policy_map.release());
118 recommended_policy_.reset(recommended_policy_map.release());
119 last_policy_refresh_time_ = timestamp;
120 }
121 }
122
123 bool CloudPolicyCache::SetPolicy(
124 const em::CloudPolicyResponse& policy) {
125 is_unmanaged_ = false;
126 base::Time timestamp;
127 scoped_ptr<PolicyMapType> mandatory_policy_map(new PolicyMapType);
128 scoped_ptr<PolicyMapType> recommended_policy_map(new PolicyMapType);
129 bool ok = DecodePolicyResponse(policy, mandatory_policy_map.get(),
130 recommended_policy_map.get(), &timestamp);
131 if (!ok) {
132 // TODO(jkummerow): Signal error to PolicyProvider.
133 return false;
134 }
135 const bool new_policy_differs =
136 !Equals(mandatory_policy_map.get(), mandatory_policy_.get()) ||
137 !Equals(recommended_policy_map.get(), recommended_policy_.get());
138 {
139 base::AutoLock lock(lock_);
140 mandatory_policy_.reset(mandatory_policy_map.release());
141 recommended_policy_.reset(recommended_policy_map.release());
142 fresh_policy_ = true;
143 last_policy_refresh_time_ = timestamp;
144 }
145
146 em::CloudPolicyResponse* policy_copy = new em::CloudPolicyResponse;
147 policy_copy->CopyFrom(policy);
148 BrowserThread::PostTask(
149 BrowserThread::FILE,
150 FROM_HERE,
151 new PersistCloudPolicyTask(backing_file_path_, policy_copy, false));
152 return new_policy_differs;
153 }
154
155 PolicyMapType* CloudPolicyCache::GetPolicy() {
156 base::AutoLock lock(lock_);
157 PolicyMapType* policy_copy = new PolicyMapType;
158 for (PolicyMapType::iterator it = mandatory_policy_->begin();
159 it != mandatory_policy_->end(); ++it) {
gfeher 2011/02/02 08:42:45 Nit: indent.
Jakob Kummerow 2011/02/03 14:36:52 Done.
160 policy_copy->insert(std::make_pair(it->first, it->second->DeepCopy()));
161 }
162 return policy_copy;
163 }
164
165 void CloudPolicyCache::SetUnmanaged() {
166 is_unmanaged_ = true;
167 {
168 base::AutoLock lock(lock_);
169 mandatory_policy_.reset(new PolicyMapType);
170 recommended_policy_.reset(new PolicyMapType);
171 last_policy_refresh_time_ = base::Time::NowFromSystemTime();
172 }
173 BrowserThread::PostTask(
174 BrowserThread::FILE,
175 FROM_HERE,
176 new PersistCloudPolicyTask(backing_file_path_, NULL, true));
177 }
178
179 // static
180 bool CloudPolicyCache::DecodePolicyResponse(
181 const em::CloudPolicyResponse& policy_response,
182 PolicyMapType* mandatory,
183 PolicyMapType* recommended,
184 base::Time* timestamp) {
185 std::string data = policy_response.signed_response();
186
187 if (!VerifySignature(policy_response.signature(), data,
188 policy_response.certificate_chain())) {
189 LOG(WARNING) << "Failed to verify signature.";
190 return false;
191 }
192
193 em::SignedCloudPolicyResponse response;
194 if (!response.ParseFromArray(data.c_str(), data.size())) {
195 LOG(WARNING) << "Failed to parse SignedCloudPolicyResponse protobuf.";
196 return false;
197 }
198
199 // TODO(jkummerow): Verify response.device_token(). Needs final specification
200 // which token we're actually sending / expecting to get back.
201
202 // TODO(jkummerow): Store response.device_name(), if we decide to transfer
203 // it from the server to the client.
204
205 // Reject policies that claim to be from the future.
206 DCHECK(timestamp);
207 *timestamp = base::Time::FromTimeT(response.timestamp());
208 if (*timestamp > base::Time::NowFromSystemTime()) {
gfeher 2011/02/02 08:42:45 Allow a small difference for safety?
Jakob Kummerow 2011/02/03 14:36:52 Done.
209 LOG(WARNING) << "Rejected policy data, timestamp is from the future.";
210 return false;
211 }
212
213 DecodePolicy(response.settings(), mandatory, recommended);
214 return true;
215 }
216
217 // static
218 bool CloudPolicyCache::VerifySignature(
219 const std::string& signature,
220 const std::string& data,
221 const RepeatedPtrField<std::string>& certificate_chain) {
222 // TODO(jkummerow): Implement this. Non-trivial because we want to do it
223 // for all platforms -> it's enough work to deserve its own CL.
224 // Don't forget to also verify the hostname of the server against the cert.
225 return true;
226 }
227
228 // static
229 bool CloudPolicyCache::Equals(const PolicyMapType* a, const PolicyMapType* b) {
230 for (PolicyMapType::const_iterator it = a->begin(); it != a->end(); ++it) {
231 PolicyMapType::const_iterator is_in_b = b->find(it->first);
232 if (is_in_b == b->end())
233 return false;
234 if (!it->second->Equals(is_in_b->second))
235 return false;
236 }
237 for (PolicyMapType::const_iterator it = b->begin(); it != b->end(); ++it) {
238 if (a->find(it->first) == a->end())
239 return false;
240 }
241 return true;
242 }
243
244 } // namespace policy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698