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

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

Issue 12189011: Split up chrome/browser/policy subdirectory (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase, add chrome/browser/chromeos/policy/OWNERS Created 7 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) 2012 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/user_cloud_policy_store_chromeos.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/file_util.h"
11 #include "base/logging.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/metrics/histogram.h"
14 #include "base/stl_util.h"
15 #include "base/stringprintf.h"
16 #include "chrome/browser/policy/proto/cloud_policy.pb.h"
17 #include "chrome/browser/policy/proto/device_management_local.pb.h"
18 #include "chrome/browser/policy/user_policy_disk_cache.h"
19 #include "chrome/browser/policy/user_policy_token_loader.h"
20 #include "chromeos/dbus/cryptohome_client.h"
21 #include "chromeos/dbus/session_manager_client.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "google_apis/gaia/gaia_auth_util.h"
24
25 namespace em = enterprise_management;
26
27 namespace policy {
28
29 namespace {
30
31 // Path within |user_policy_key_dir_| that contains the policy key.
32 // "%s" must be substituted with the sanitized username.
33 const base::FilePath::CharType kPolicyKeyFile[] =
34 FILE_PATH_LITERAL("%s/policy.pub");
35
36 // Maximum key size that will be loaded, in bytes.
37 const int kKeySizeLimit = 16 * 1024;
38
39 enum ValidationFailure {
40 VALIDATION_FAILURE_DBUS,
41 VALIDATION_FAILURE_LOAD_KEY,
42 VALIDATION_FAILURE_SIZE,
43 };
44
45 void SampleValidationFailure(ValidationFailure sample) {
46 UMA_HISTOGRAM_ENUMERATION("Enterprise.UserPolicyValidationFailure",
47 sample,
48 VALIDATION_FAILURE_SIZE);
49 }
50
51 } // namespace
52
53 // Helper class for loading legacy policy caches.
54 class LegacyPolicyCacheLoader : public UserPolicyTokenLoader::Delegate,
55 public UserPolicyDiskCache::Delegate {
56 public:
57 typedef base::Callback<void(const std::string&,
58 const std::string&,
59 CloudPolicyStore::Status,
60 scoped_ptr<em::PolicyFetchResponse>)> Callback;
61
62 LegacyPolicyCacheLoader(const base::FilePath& token_cache_file,
63 const base::FilePath& policy_cache_file);
64 virtual ~LegacyPolicyCacheLoader();
65
66 // Starts loading, and reports the result to |callback| when done.
67 void Load(const Callback& callback);
68
69 // UserPolicyTokenLoader::Delegate:
70 virtual void OnTokenLoaded(const std::string& token,
71 const std::string& device_id) OVERRIDE;
72
73 // UserPolicyDiskCache::Delegate:
74 virtual void OnDiskCacheLoaded(
75 UserPolicyDiskCache::LoadResult result,
76 const em::CachedCloudPolicyResponse& policy) OVERRIDE;
77
78 private:
79 // Checks whether the load operations from the legacy caches completed. If so,
80 // fires the appropriate notification.
81 void CheckLoadFinished();
82
83 // Maps a disk cache LoadResult to a CloudPolicyStore::Status.
84 static CloudPolicyStore::Status TranslateLoadResult(
85 UserPolicyDiskCache::LoadResult result);
86
87 base::WeakPtrFactory<LegacyPolicyCacheLoader> weak_factory_;
88
89 scoped_refptr<UserPolicyTokenLoader> token_loader_;
90 scoped_refptr<UserPolicyDiskCache> policy_cache_;
91
92 std::string dm_token_;
93 std::string device_id_;
94 bool has_policy_;
95 scoped_ptr<em::PolicyFetchResponse> policy_;
96 CloudPolicyStore::Status status_;
97
98 Callback callback_;
99
100 DISALLOW_COPY_AND_ASSIGN(LegacyPolicyCacheLoader);
101 };
102
103 LegacyPolicyCacheLoader::LegacyPolicyCacheLoader(
104 const base::FilePath& token_cache_file,
105 const base::FilePath& policy_cache_file)
106 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
107 has_policy_(false),
108 status_(CloudPolicyStore::STATUS_OK) {
109 token_loader_ = new UserPolicyTokenLoader(weak_factory_.GetWeakPtr(),
110 token_cache_file);
111 policy_cache_ = new UserPolicyDiskCache(weak_factory_.GetWeakPtr(),
112 policy_cache_file);
113 }
114
115 LegacyPolicyCacheLoader::~LegacyPolicyCacheLoader() {}
116
117 void LegacyPolicyCacheLoader::Load(const Callback& callback) {
118 callback_ = callback;
119 token_loader_->Load();
120 policy_cache_->Load();
121 }
122
123 void LegacyPolicyCacheLoader::OnTokenLoaded(const std::string& token,
124 const std::string& device_id) {
125 dm_token_ = token;
126 device_id_ = device_id;
127 token_loader_ = NULL;
128 CheckLoadFinished();
129 }
130
131 void LegacyPolicyCacheLoader::OnDiskCacheLoaded(
132 UserPolicyDiskCache::LoadResult result,
133 const em::CachedCloudPolicyResponse& policy) {
134 status_ = TranslateLoadResult(result);
135 if (result == UserPolicyDiskCache::LOAD_RESULT_SUCCESS) {
136 if (policy.has_cloud_policy())
137 policy_.reset(new em::PolicyFetchResponse(policy.cloud_policy()));
138 } else {
139 LOG(WARNING) << "Failed to load legacy policy cache: " << result;
140 }
141 policy_cache_ = NULL;
142 CheckLoadFinished();
143 }
144
145 void LegacyPolicyCacheLoader::CheckLoadFinished() {
146 if (!token_loader_.get() && !policy_cache_.get())
147 callback_.Run(dm_token_, device_id_, status_, policy_.Pass());
148 }
149
150 // static
151 CloudPolicyStore::Status LegacyPolicyCacheLoader::TranslateLoadResult(
152 UserPolicyDiskCache::LoadResult result) {
153 switch (result) {
154 case UserPolicyDiskCache::LOAD_RESULT_SUCCESS:
155 case UserPolicyDiskCache::LOAD_RESULT_NOT_FOUND:
156 return CloudPolicyStore::STATUS_OK;
157 case UserPolicyDiskCache::LOAD_RESULT_PARSE_ERROR:
158 case UserPolicyDiskCache::LOAD_RESULT_READ_ERROR:
159 return CloudPolicyStore::STATUS_LOAD_ERROR;
160 }
161 NOTREACHED();
162 return CloudPolicyStore::STATUS_OK;
163 }
164
165 UserCloudPolicyStoreChromeOS::UserCloudPolicyStoreChromeOS(
166 chromeos::CryptohomeClient* cryptohome_client,
167 chromeos::SessionManagerClient* session_manager_client,
168 const std::string& username,
169 const base::FilePath& user_policy_key_dir,
170 const base::FilePath& legacy_token_cache_file,
171 const base::FilePath& legacy_policy_cache_file)
172 : cryptohome_client_(cryptohome_client),
173 session_manager_client_(session_manager_client),
174 username_(username),
175 user_policy_key_dir_(user_policy_key_dir),
176 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
177 legacy_cache_dir_(legacy_token_cache_file.DirName()),
178 legacy_loader_(new LegacyPolicyCacheLoader(legacy_token_cache_file,
179 legacy_policy_cache_file)),
180 legacy_caches_loaded_(false),
181 policy_key_loaded_(false) {}
182
183 UserCloudPolicyStoreChromeOS::~UserCloudPolicyStoreChromeOS() {}
184
185 void UserCloudPolicyStoreChromeOS::Store(
186 const em::PolicyFetchResponse& policy) {
187 // Cancel all pending requests.
188 weak_factory_.InvalidateWeakPtrs();
189 scoped_ptr<em::PolicyFetchResponse> response(
190 new em::PolicyFetchResponse(policy));
191 EnsurePolicyKeyLoaded(
192 base::Bind(&UserCloudPolicyStoreChromeOS::ValidatePolicyForStore,
193 weak_factory_.GetWeakPtr(),
194 base::Passed(&response)));
195 }
196
197 void UserCloudPolicyStoreChromeOS::Load() {
198 // Cancel all pending requests.
199 weak_factory_.InvalidateWeakPtrs();
200 session_manager_client_->RetrieveUserPolicy(
201 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyRetrieved,
202 weak_factory_.GetWeakPtr()));
203 }
204
205 void UserCloudPolicyStoreChromeOS::ValidatePolicyForStore(
206 scoped_ptr<em::PolicyFetchResponse> policy) {
207 // Create and configure a validator.
208 scoped_ptr<UserCloudPolicyValidator> validator =
209 CreateValidator(policy.Pass());
210 validator->ValidateUsername(username_);
211 if (policy_key_.empty()) {
212 validator->ValidateInitialKey();
213 } else {
214 const bool allow_rotation = true;
215 validator->ValidateSignature(policy_key_, allow_rotation);
216 }
217
218 // Start validation. The Validator will delete itself once validation is
219 // complete.
220 validator.release()->StartValidation(
221 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated,
222 weak_factory_.GetWeakPtr()));
223 }
224
225 void UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated(
226 UserCloudPolicyValidator* validator) {
227 validation_status_ = validator->status();
228
229 UMA_HISTOGRAM_ENUMERATION(
230 "Enterprise.UserPolicyValidationStoreStatus",
231 validation_status_,
232 UserCloudPolicyValidator::VALIDATION_POLICY_PARSE_ERROR + 1);
233
234 if (!validator->success()) {
235 status_ = STATUS_VALIDATION_ERROR;
236 NotifyStoreError();
237 return;
238 }
239
240 std::string policy_blob;
241 if (!validator->policy()->SerializeToString(&policy_blob)) {
242 status_ = STATUS_SERIALIZE_ERROR;
243 NotifyStoreError();
244 return;
245 }
246
247 session_manager_client_->StoreUserPolicy(
248 policy_blob,
249 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyStored,
250 weak_factory_.GetWeakPtr()));
251 }
252
253 void UserCloudPolicyStoreChromeOS::OnPolicyStored(bool success) {
254 if (!success) {
255 status_ = STATUS_STORE_ERROR;
256 NotifyStoreError();
257 } else {
258 // Load the policy right after storing it, to make sure it was accepted by
259 // the session manager. An additional validation is performed after the
260 // load; reload the key for that validation too, in case it was rotated.
261 ReloadPolicyKey(base::Bind(&UserCloudPolicyStoreChromeOS::Load,
262 weak_factory_.GetWeakPtr()));
263 }
264 }
265
266 void UserCloudPolicyStoreChromeOS::OnPolicyRetrieved(
267 const std::string& policy_blob) {
268 if (policy_blob.empty()) {
269 // Policy fetch failed. Try legacy caches if we haven't done that already.
270 if (!legacy_caches_loaded_ && legacy_loader_.get()) {
271 legacy_caches_loaded_ = true;
272 legacy_loader_->Load(
273 base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished,
274 weak_factory_.GetWeakPtr()));
275 } else {
276 // session_manager doesn't have policy. Adjust internal state and notify
277 // the world about the policy update.
278 policy_.reset();
279 NotifyStoreLoaded();
280 }
281 return;
282 }
283
284 // Policy is supplied by session_manager. Disregard legacy data from now on.
285 legacy_loader_.reset();
286
287 scoped_ptr<em::PolicyFetchResponse> policy(new em::PolicyFetchResponse());
288 if (!policy->ParseFromString(policy_blob)) {
289 status_ = STATUS_PARSE_ERROR;
290 NotifyStoreError();
291 return;
292 }
293
294 // Load |policy_key_| to verify the loaded policy.
295 EnsurePolicyKeyLoaded(
296 base::Bind(&UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy,
297 weak_factory_.GetWeakPtr(),
298 base::Passed(&policy)));
299 }
300
301 void UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy(
302 scoped_ptr<em::PolicyFetchResponse> policy) {
303 // Create and configure a validator for the loaded policy.
304 scoped_ptr<UserCloudPolicyValidator> validator =
305 CreateValidator(policy.Pass());
306 validator->ValidateUsername(username_);
307 const bool allow_rotation = false;
308 validator->ValidateSignature(policy_key_, allow_rotation);
309 // Start validation. The Validator will delete itself once validation is
310 // complete.
311 validator.release()->StartValidation(
312 base::Bind(&UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated,
313 weak_factory_.GetWeakPtr()));
314 }
315
316 void UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated(
317 UserCloudPolicyValidator* validator) {
318 validation_status_ = validator->status();
319
320 UMA_HISTOGRAM_ENUMERATION(
321 "Enterprise.UserPolicyValidationLoadStatus",
322 validation_status_,
323 UserCloudPolicyValidator::VALIDATION_POLICY_PARSE_ERROR + 1);
324
325 if (!validator->success()) {
326 status_ = STATUS_VALIDATION_ERROR;
327 NotifyStoreError();
328 return;
329 }
330
331 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
332 status_ = STATUS_OK;
333
334 // Policy has been loaded successfully. This indicates that new-style policy
335 // is working, so the legacy cache directory can be removed.
336 if (!legacy_cache_dir_.empty()) {
337 content::BrowserThread::PostBlockingPoolTask(
338 FROM_HERE,
339 base::Bind(&UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir,
340 legacy_cache_dir_));
341 legacy_cache_dir_.clear();
342 }
343 NotifyStoreLoaded();
344 }
345
346 void UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished(
347 const std::string& dm_token,
348 const std::string& device_id,
349 Status status,
350 scoped_ptr<em::PolicyFetchResponse> policy) {
351 status_ = status;
352 if (policy.get()) {
353 // Create and configure a validator for the loaded legacy policy. Note that
354 // the signature on this policy is not verified.
355 scoped_ptr<UserCloudPolicyValidator> validator =
356 CreateValidator(policy.Pass());
357 validator->ValidateUsername(username_);
358 validator.release()->StartValidation(
359 base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated,
360 weak_factory_.GetWeakPtr(),
361 dm_token,
362 device_id));
363 } else {
364 InstallLegacyTokens(dm_token, device_id);
365 }
366 }
367
368 void UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated(
369 const std::string& dm_token,
370 const std::string& device_id,
371 UserCloudPolicyValidator* validator) {
372 validation_status_ = validator->status();
373 if (validator->success()) {
374 status_ = STATUS_OK;
375 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
376
377 // Clear the public key version. The public key version field would
378 // otherwise indicate that we have key installed in the store when in fact
379 // we haven't. This may result in policy updates failing signature
380 // verification.
381 policy_->clear_public_key_version();
382 } else {
383 status_ = STATUS_VALIDATION_ERROR;
384 }
385
386 InstallLegacyTokens(dm_token, device_id);
387 }
388
389 void UserCloudPolicyStoreChromeOS::InstallLegacyTokens(
390 const std::string& dm_token,
391 const std::string& device_id) {
392 // Write token and device ID to |policy_|, giving them precedence over the
393 // policy blob. This is to match the legacy behavior, which used token and
394 // device id exclusively from the token cache file.
395 if (!dm_token.empty() && !device_id.empty()) {
396 if (!policy_.get())
397 policy_.reset(new em::PolicyData());
398 policy_->set_request_token(dm_token);
399 policy_->set_device_id(device_id);
400 }
401
402 // Tell the rest of the world that the policy load completed.
403 NotifyStoreLoaded();
404 }
405
406 // static
407 void UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir(
408 const base::FilePath& dir) {
409 if (file_util::PathExists(dir) && !file_util::Delete(dir, true))
410 LOG(ERROR) << "Failed to remove cache dir " << dir.value();
411 }
412
413 void UserCloudPolicyStoreChromeOS::ReloadPolicyKey(
414 const base::Closure& callback) {
415 std::vector<uint8>* key = new std::vector<uint8>();
416 content::BrowserThread::PostBlockingPoolTaskAndReply(
417 FROM_HERE,
418 base::Bind(&UserCloudPolicyStoreChromeOS::LoadPolicyKey,
419 policy_key_path_,
420 key),
421 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyKeyReloaded,
422 weak_factory_.GetWeakPtr(),
423 base::Owned(key),
424 callback));
425 }
426
427 // static
428 void UserCloudPolicyStoreChromeOS::LoadPolicyKey(const base::FilePath& path,
429 std::vector<uint8>* key) {
430 if (!file_util::PathExists(path)) {
431 // There is no policy key the first time that a user fetches policy. If
432 // |path| does not exist then that is the most likely scenario, so there's
433 // no need to sample a failure.
434 VLOG(1) << "No key at " << path.value();
435 return;
436 }
437
438 int64 size;
439 if (!file_util::GetFileSize(path, &size)) {
440 LOG(ERROR) << "Could not get size of " << path.value();
441 } else if (size == 0 || size > kKeySizeLimit) {
442 LOG(ERROR) << "Key at " << path.value() << " has bad size " << size;
443 } else {
444 key->resize(size);
445 int read_size = file_util::ReadFile(
446 path, reinterpret_cast<char*>(vector_as_array(key)), size);
447 if (read_size != size) {
448 LOG(ERROR) << "Failed to read key at " << path.value();
449 key->clear();
450 }
451 }
452
453 if (key->empty())
454 SampleValidationFailure(VALIDATION_FAILURE_LOAD_KEY);
455 }
456
457 void UserCloudPolicyStoreChromeOS::OnPolicyKeyReloaded(
458 std::vector<uint8>* key,
459 const base::Closure& callback) {
460 policy_key_.swap(*key);
461 policy_key_loaded_ = true;
462 callback.Run();
463 }
464
465 void UserCloudPolicyStoreChromeOS::EnsurePolicyKeyLoaded(
466 const base::Closure& callback) {
467 if (policy_key_loaded_) {
468 callback.Run();
469 } else {
470 // Get the hashed username that's part of the key's path, to determine
471 // |policy_key_path_|.
472 cryptohome_client_->GetSanitizedUsername(username_,
473 base::Bind(&UserCloudPolicyStoreChromeOS::OnGetSanitizedUsername,
474 weak_factory_.GetWeakPtr(),
475 callback));
476 }
477 }
478
479 void UserCloudPolicyStoreChromeOS::OnGetSanitizedUsername(
480 const base::Closure& callback,
481 chromeos::DBusMethodCallStatus call_status,
482 const std::string& sanitized_username) {
483 // The default empty path will always yield an empty key.
484 if (call_status == chromeos::DBUS_METHOD_CALL_SUCCESS &&
485 !sanitized_username.empty()) {
486 policy_key_path_ = user_policy_key_dir_.Append(
487 base::StringPrintf(kPolicyKeyFile, sanitized_username.c_str()));
488 } else {
489 SampleValidationFailure(VALIDATION_FAILURE_DBUS);
490 }
491 ReloadPolicyKey(callback);
492 }
493
494 } // namespace policy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698