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

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

Issue 7233006: Store/Retrieve CrOS user policy in session_manager. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address feedback. Created 9 years, 6 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/cros_user_policy_cache.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/file_path.h"
13 #include "base/file_util.h"
14 #include "chrome/browser/policy/cros_user_policy_identity_strategy.h"
15 #include "chrome/browser/policy/proto/cloud_policy.pb.h"
16 #include "chrome/common/extensions/extension_constants.h"
17 #include "content/browser/browser_thread.h"
18 #include "crypto/signature_verifier.h"
19
20 using extension_misc::kSignatureAlgorithm;
21
22 static const FilePath::CharType kUserPolicyKeyFile[] =
23 "/home/chronos/user/.enterprise/key";
24
25 namespace policy {
26
27 // Decodes a CloudPolicySettings object into two maps with mandatory and
28 // recommended settings, respectively. The implementation is generated code
29 // in policy/cloud_policy_generated.cc.
30 void DecodePolicy(const em::CloudPolicySettings& policy,
31 PolicyMap* mandatory, PolicyMap* recommended);
32
33 // Manages the policy key and implements signature checking on the key.
gfeher 2011/06/22 22:18:17 on the key -> with the key?
34 class CrosUserPolicyCache::PolicyKey
35 : public base::RefCountedThreadSafe<PolicyKey> {
36 public:
37 typedef base::Callback<void(bool)> StatusCallback;
38
39 explicit PolicyKey(const FilePath& key_file);
40
41 // Loads the key asynchronously on the file thread.
42 void LoadKey();
43
44 // Checks whether |signature| is a valid over |data|. The status will be
gfeher 2011/06/22 22:18:17 is a valid -> is valid
45 // reported through |callback| once the check is complete. If the |reload_key|
46 // flag is set, the key is first reloaded from the file.
47 void CheckSignature(const std::string& data,
48 const std::string& signature,
49 bool reload_key,
50 const StatusCallback& callback);
51
52 private:
53 // Reports the result of a signature check. Must be called on the UI thread.
54 void ReportResult(const StatusCallback& callback, bool result);
55
56 // Read the public key from |key_file_|. Must be called on the file thread.
57 void ReadKeyFromFile();
58
59 // Runs the actual signature checking. Must be called on the file thread.
60 void CheckSignatureOnFileThread(const std::string& data,
61 const std::string& signature,
62 bool reload_key,
63 const StatusCallback& callback);
64
65 // The data members should only be accessed from the file thread.
66 const FilePath key_file_;
67 std::vector<uint8> public_key_;
68
69 DISALLOW_COPY_AND_ASSIGN(PolicyKey);
70 };
71
72 CrosUserPolicyCache::PolicyKey::PolicyKey(const FilePath& key_file)
73 : key_file_(key_file) {}
74
75 void CrosUserPolicyCache::PolicyKey::LoadKey() {
76 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
77 NewRunnableMethod(this, &PolicyKey::ReadKeyFromFile));
78 }
79
80 void CrosUserPolicyCache::PolicyKey::CheckSignature(
81 const std::string& data,
82 const std::string& signature,
83 bool reload_key,
84 const StatusCallback& callback) {
85 BrowserThread::PostTask(
86 BrowserThread::FILE, FROM_HERE,
87 NewRunnableMethod(this, &PolicyKey::CheckSignatureOnFileThread,
88 data, signature, reload_key, callback));
89 }
90
91 void CrosUserPolicyCache::PolicyKey::CheckSignatureOnFileThread(
92 const std::string& data,
93 const std::string& signature,
94 bool reload_key,
95 const StatusCallback& callback) {
96 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
97 bool status = false;
98
99 // Re-read the key if necessary.
100 if (public_key_.empty() || reload_key)
101 ReadKeyFromFile();
102
103 if (!public_key_.empty()) {
104 crypto::SignatureVerifier verifier;
105 if (verifier.VerifyInit(kSignatureAlgorithm, sizeof(kSignatureAlgorithm),
106 reinterpret_cast<const uint8*>(&signature[0]),
107 signature.size(),
108 &public_key_[0], public_key_.size())) {
109 verifier.VerifyUpdate(reinterpret_cast<const uint8*>(data.c_str()),
110 data.length());
111 status = verifier.VerifyFinal();
112 }
113 }
114
115 BrowserThread::PostTask(BrowserThread::UI,
116 FROM_HERE,
117 NewRunnableMethod(this, &PolicyKey::ReportResult,
118 callback, status));
119 }
120
121 void CrosUserPolicyCache::PolicyKey::ReportResult(
122 const StatusCallback& callback,
123 bool result) {
124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
125 callback.Run(result);
126 }
127
128 void CrosUserPolicyCache::PolicyKey::ReadKeyFromFile() {
129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
130
131 public_key_.clear();
132 if (!file_util::PathExists(key_file_))
133 return;
134
135 int64 size = -1;
136 if (!file_util::GetFileSize(key_file_, &size)) {
137 LOG(ERROR) << "Failed to get file size for " << key_file_.value();
138 return;
139 }
140
141 const int64 kMaxSize = 1 * 1024 * 1024; // 1M should be sufficient.
142 if (size < 0 || size > kMaxSize) {
143 LOG(ERROR) << "Bogus policy key file size " << size;
144 return;
145 }
146
147 std::vector<uint8> key_data(size);
148 if (!file_util::ReadFile(key_file_,
149 reinterpret_cast<char*>(&key_data[0]),
150 key_data.size())) {
151 LOG(ERROR) << "Failed to read " << key_file_.value();
152 return;
153 }
154
155 public_key_.swap(key_data);
156 }
157
158 // Takes care of sending a new policy blob to session manager and reports back
159 // the status through a callback.
160 class CrosUserPolicyCache::StorePolicyOperation {
161 public:
162 typedef base::Callback<void(bool)> StatusCallback;
163
164 // Creates and exectues an operation.
165 static StorePolicyOperation* Run(const em::PolicyFetchResponse& policy,
166 chromeos::LoginLibrary* login_library,
167 const StatusCallback& callback);
168
169 // Cancels the operation, making sure that any pending callbacks get killed.
170 void Cancel();
171
172 const em::PolicyFetchResponse& policy() { return policy_; }
173
174 private:
175 StorePolicyOperation(const em::PolicyFetchResponse& policy,
176 const StatusCallback& callback);
177
178 // StorePolicyOperation manages its own lifetime.
179 ~StorePolicyOperation() {}
180
181 // A callback function suitable for passing to login_library.
182 static void StorePolicyCallback(void* delegate, bool result);
183
184 em::PolicyFetchResponse policy_;
185 StatusCallback callback_;
186
187 DISALLOW_COPY_AND_ASSIGN(StorePolicyOperation);
188 };
189
190 // static
191 CrosUserPolicyCache::StorePolicyOperation*
192 CrosUserPolicyCache::StorePolicyOperation::Run(
193 const em::PolicyFetchResponse& policy,
194 chromeos::LoginLibrary* login_library,
195 const StatusCallback& callback) {
196 StorePolicyOperation* op = new StorePolicyOperation(policy, callback);
197 std::string serialized;
198 if (!policy.SerializeToString(&serialized)) {
gfeher 2011/06/22 22:18:17 Possible nit: if you would do this check at the be
199 LOG(ERROR) << "Failed to serialize policy protobuf!";
200 callback.Run(false);
201 delete op;
202 return NULL;
203 }
204 login_library->RequestStoreUserPolicy(serialized, StorePolicyCallback, op);
205 return op;
206 }
207
208 void CrosUserPolicyCache::StorePolicyOperation::Cancel() {
209 callback_.Reset();
210 }
211
212 CrosUserPolicyCache::StorePolicyOperation::StorePolicyOperation(
213 const em::PolicyFetchResponse& policy,
214 const StatusCallback& callback)
215 : policy_(policy),
216 callback_(callback) {}
217
218 // static
219 void CrosUserPolicyCache::StorePolicyOperation::StorePolicyCallback(
220 void* delegate,
221 bool result) {
222 StorePolicyOperation* op(static_cast<StorePolicyOperation*>(delegate));
223 if (!op->callback_.is_null())
224 op->callback_.Run(result);
225 delete op;
226 }
227
228 class CrosUserPolicyCache::RetrievePolicyOperation {
229 public:
230 typedef base::Callback<void(bool, const em::PolicyFetchResponse&)>
231 ResultCallback;
232
233 // Creates and executes an operation.
234 static RetrievePolicyOperation* Run(PolicyKey* key,
235 chromeos::LoginLibrary* login_library,
236 bool reload_key,
237 const ResultCallback& callback);
238
239 // Cancels the operation, disengaging all pending callbacks.
240 void Cancel();
241
242 private:
243 RetrievePolicyOperation(PolicyKey* key,
244 bool reload_key,
245 const ResultCallback& callback);
246
247 // RetrievePolicyOperation manages its own lifetime.
248 ~RetrievePolicyOperation() {}
249
250 // Decodes the policy data and triggers a signature check.
251 void OnPolicyRetrieved(const char* data, unsigned int size);
252
253 // Handles the signature verification callback and reports the result.
254 void OnSignatureChecked(bool result);
255
256 // Finishes the operation, makes the |callback_|, and deletes |this|.
257 void Finish(bool status);
258
259 // A callback function suitable for passing to login_library.
260 static void RetrievePolicyCallback(void* delegate,
261 const char* data,
262 unsigned int size);
263 scoped_refptr<PolicyKey> key_;
264 bool reload_key_;
265 ResultCallback callback_;
266 em::PolicyFetchResponse policy_;
267
268 DISALLOW_COPY_AND_ASSIGN(RetrievePolicyOperation);
269 };
270
271 // static
272 CrosUserPolicyCache::RetrievePolicyOperation*
273 CrosUserPolicyCache::RetrievePolicyOperation::Run(
274 PolicyKey* key,
275 chromeos::LoginLibrary* login_library,
276 bool reload_key,
277 const ResultCallback& callback) {
278 RetrievePolicyOperation* op =
279 new RetrievePolicyOperation(key, reload_key, callback);
280 login_library->RequestRetrieveUserPolicy(RetrievePolicyCallback, op);
281 return op;
282 }
283
284 void CrosUserPolicyCache::RetrievePolicyOperation::Cancel() {
285 callback_.Reset();
286 }
287
288 CrosUserPolicyCache::RetrievePolicyOperation::RetrievePolicyOperation(
289 PolicyKey* key,
290 bool reload_key,
291 const ResultCallback& callback)
292 : key_(key),
293 reload_key_(reload_key),
294 callback_(callback) {}
295
296 void CrosUserPolicyCache::RetrievePolicyOperation::OnPolicyRetrieved(
297 const char* data,
298 unsigned int size) {
299 if (!policy_.ParseFromArray(data, size) ||
300 !policy_.has_policy_data() ||
301 !policy_.has_policy_data_signature()) {
302 LOG(ERROR) << "Failed to decode policy";
303 Finish(false);
304 return;
305 }
306 key_->CheckSignature(policy_.policy_data(),
307 policy_.policy_data_signature(),
308 reload_key_,
309 base::Bind(&RetrievePolicyOperation::OnSignatureChecked,
310 base::Unretained(this)));
311 }
312
313 void CrosUserPolicyCache::RetrievePolicyOperation::OnSignatureChecked(
314 bool result) {
315 if (!result)
316 LOG(ERROR) << "User policy signature check failed.";
gfeher 2011/06/22 22:18:17 We would get this error printed after SetUnmanaged
317 Finish(result);
318 }
319
320 void CrosUserPolicyCache::RetrievePolicyOperation::Finish(bool status) {
321 if (!callback_.is_null())
322 callback_.Run(status, policy_);
323 delete this;
324 }
325
326 // static
327 void CrosUserPolicyCache::RetrievePolicyOperation::RetrievePolicyCallback(
328 void *delegate,
329 const char* data,
330 unsigned int size) {
331 static_cast<RetrievePolicyOperation*>(delegate)->OnPolicyRetrieved(data,
332 size);
333 }
334
335 CrosUserPolicyCache::CrosUserPolicyCache(
336 chromeos::LoginLibrary* login_library,
337 CrosUserPolicyIdentityStrategy* identity_strategy,
338 const FilePath& legacy_cache_file)
339 : key_(new PolicyKey(FilePath(kUserPolicyKeyFile))),
340 login_library_(login_library),
341 identity_strategy_(identity_strategy),
342 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)),
343 legacy_cache_file_(legacy_cache_file),
344 store_operation_(NULL),
345 retrieve_operation_(NULL) {
346 legacy_token_cache_ = new UserPolicyTokenCache(weak_ptr_factory_.GetWeakPtr(),
347 legacy_cache_file);
348 }
349
350 CrosUserPolicyCache::~CrosUserPolicyCache() {
351 CancelStore();
352 CancelRetrieve();
353 }
354
355 void CrosUserPolicyCache::Load() {
356 key_->LoadKey();
357 retrieve_operation_ =
358 RetrievePolicyOperation::Run(
359 key_,
360 login_library_,
361 false,
362 base::Bind(&CrosUserPolicyCache::OnPolicyLoadDone,
363 base::Unretained(this)));
364 }
365
366 void CrosUserPolicyCache::SetPolicy(const em::PolicyFetchResponse& policy) {
367 CancelStore();
368 set_last_policy_refresh_time(base::Time::NowFromSystemTime());
369 store_operation_ =
370 StorePolicyOperation::Run(policy,
371 login_library_,
372 base::Bind(&CrosUserPolicyCache::OnPolicyStored,
373 base::Unretained(this)));
374 }
375
376 void CrosUserPolicyCache::SetUnmanaged() {
377 base::Time now(base::Time::NowFromSystemTime());
378 SetUnmanagedInternal(now);
379
380 // Construct a policy blob with unmanaged state.
381 em::PolicyData policy_data;
382 policy_data.set_policy_type(identity_strategy_->GetPolicyType());
383 policy_data.set_timestamp((now - base::Time::UnixEpoch()).InMilliseconds());
384 policy_data.set_state(em::PolicyData::UNMANAGED);
385
386 em::PolicyFetchResponse policy;
387 if (!policy_data.SerializeToString(policy.mutable_policy_data())) {
388 LOG(ERROR) << "Failed to serialize policy_data";
389 return;
390 }
391
392 SetPolicy(policy);
393 }
394
395 bool CrosUserPolicyCache::DecodePolicyData(const em::PolicyData& policy_data,
396 PolicyMap* mandatory,
397 PolicyMap* recommended) {
398 em::CloudPolicySettings policy;
399 if (!policy.ParseFromString(policy_data.policy_value())) {
400 LOG(WARNING) << "Failed to parse CloudPolicySettings protobuf.";
401 return false;
402 }
403 DecodePolicy(policy, mandatory, recommended);
404 return true;
405 }
406
407 void CrosUserPolicyCache::OnTokenCacheLoaded(const std::string& token,
408 const std::string& device_id) {
409 if (!token.empty() && !device_id.empty()) {
410 identity_strategy_->SetDeviceCredentials(device_id, token);
411 } else {
412 identity_strategy_->EnableRegistration();
413 }
414 }
415
416 void CrosUserPolicyCache::OnPolicyStored(bool result) {
417 DCHECK(store_operation_);
418 if (result) {
419 // Policy is stored successfully, reload from session_manager and apply.
420 // This helps us making sure we only use policy that session_manager has
421 // checked and confirmed to be good.
gfeher 2011/06/22 22:18:17 What's the relation of the signature check in this
422 CancelRetrieve();
423 retrieve_operation_ =
424 RetrievePolicyOperation::Run(
425 key_,
426 login_library_,
427 store_operation_->policy().has_new_public_key(),
428 base::Bind(&CrosUserPolicyCache::OnPolicyReloadDone,
429 base::Unretained(this)));
430
431 // Now that we have installed the new policy blob, we can make sure that the
432 // old cache directory is removed.
433 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
434 NewRunnableFunction(&RemoveLegacyCacheDir,
435 legacy_cache_file_.DirName()));
436 } else {
437 InformNotifier(CloudPolicySubsystem::LOCAL_ERROR,
438 CloudPolicySubsystem::POLICY_LOCAL_ERROR);
439 }
440 CancelStore();
441 }
442
443 void CrosUserPolicyCache::OnPolicyLoadDone(
444 bool result,
445 const em::PolicyFetchResponse& policy) {
446 DCHECK(retrieve_operation_);
447 CancelRetrieve();
448 if (!result) {
449 // No policy present. Try to load the legacy token cache.
450 legacy_token_cache_->Load();
451 return;
452 }
453
454 em::PolicyData policy_data;
455 if (!policy_data.ParseFromString(policy.policy_data())) {
456 LOG(WARNING) << "Failed to parse PolicyData protobuf.";
457 InformNotifier(CloudPolicySubsystem::LOCAL_ERROR,
458 CloudPolicySubsystem::POLICY_LOCAL_ERROR);
459 identity_strategy_->EnableRegistration();
460 return;
461 }
462 if (policy_data.request_token().empty() ||
463 policy_data.username().empty() ||
464 policy_data.device_id().empty()) {
465 LOG(WARNING) << "Policy protobuf is missing credentials";
466 InformNotifier(CloudPolicySubsystem::LOCAL_ERROR,
467 CloudPolicySubsystem::POLICY_LOCAL_ERROR);
468 identity_strategy_->EnableRegistration();
469 return;
470 }
471 identity_strategy_->SetDeviceCredentials(policy_data.device_id(),
472 policy_data.request_token());
473 SetPolicyInternal(policy, NULL, true);
474 }
475
476 void CrosUserPolicyCache::OnPolicyReloadDone(
477 bool result,
478 const em::PolicyFetchResponse& policy) {
479 DCHECK(retrieve_operation_);
480 CancelRetrieve();
481 if (result) {
482 SetPolicyInternal(policy, NULL, false);
483 } else {
484 InformNotifier(CloudPolicySubsystem::LOCAL_ERROR,
485 CloudPolicySubsystem::POLICY_LOCAL_ERROR);
486 }
487 }
488
489 void CrosUserPolicyCache::CancelStore() {
490 if (store_operation_) {
491 store_operation_->Cancel();
492 store_operation_ = NULL;
493 }
494 }
495
496 void CrosUserPolicyCache::CancelRetrieve() {
497 if (retrieve_operation_) {
498 retrieve_operation_->Cancel();
499 retrieve_operation_ = NULL;
500 }
501 }
502
503 // static
504 void CrosUserPolicyCache::RemoveLegacyCacheDir(const FilePath& dir) {
505 if (!file_util::Delete(dir, true))
506 PLOG(ERROR) << "Failed to remove " << dir.value();
507 }
508
509 } // namespace policy
OLDNEW
« no previous file with comments | « chrome/browser/policy/cros_user_policy_cache.h ('k') | chrome/browser/policy/cros_user_policy_identity_strategy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698