Update broken references to image assets
[chromium-blink-merge.git] / chrome / browser / chromeos / policy / user_cloud_policy_store_chromeos.cc
blob43b72890b144aaf3e8df9b175a1362166c39dd8a
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.
5 #include "chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/files/file_util.h"
11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/metrics/histogram.h"
14 #include "base/sequenced_task_runner.h"
15 #include "base/stl_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "chrome/browser/chromeos/policy/user_policy_disk_cache.h"
18 #include "chrome/browser/chromeos/policy/user_policy_token_loader.h"
19 #include "chromeos/dbus/cryptohome_client.h"
20 #include "chromeos/dbus/session_manager_client.h"
21 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
22 #include "google_apis/gaia/gaia_auth_util.h"
23 #include "policy/proto/cloud_policy.pb.h"
24 #include "policy/proto/device_management_local.pb.h"
26 namespace em = enterprise_management;
28 namespace policy {
30 namespace {
32 // Path within |user_policy_key_dir_| that contains the policy key.
33 // "%s" must be substituted with the sanitized username.
34 const base::FilePath::CharType kPolicyKeyFile[] =
35 FILE_PATH_LITERAL("%s/policy.pub");
37 // Maximum key size that will be loaded, in bytes.
38 const size_t kKeySizeLimit = 16 * 1024;
40 enum ValidationFailure {
41 VALIDATION_FAILURE_DBUS,
42 VALIDATION_FAILURE_LOAD_KEY,
43 VALIDATION_FAILURE_SIZE,
46 void SampleValidationFailure(ValidationFailure sample) {
47 UMA_HISTOGRAM_ENUMERATION("Enterprise.UserPolicyValidationFailure",
48 sample,
49 VALIDATION_FAILURE_SIZE);
52 // Extracts the domain name from the passed username.
53 std::string ExtractDomain(const std::string& username) {
54 return gaia::ExtractDomainName(gaia::CanonicalizeEmail(username));
57 } // namespace
59 // Helper class for loading legacy policy caches.
60 class LegacyPolicyCacheLoader : public UserPolicyTokenLoader::Delegate,
61 public UserPolicyDiskCache::Delegate {
62 public:
63 typedef base::Callback<void(const std::string&,
64 const std::string&,
65 CloudPolicyStore::Status,
66 scoped_ptr<em::PolicyFetchResponse>)> Callback;
68 LegacyPolicyCacheLoader(
69 const base::FilePath& token_cache_file,
70 const base::FilePath& policy_cache_file,
71 scoped_refptr<base::SequencedTaskRunner> background_task_runner);
72 ~LegacyPolicyCacheLoader() override;
74 // Starts loading, and reports the result to |callback| when done.
75 void Load(const Callback& callback);
77 // UserPolicyTokenLoader::Delegate:
78 void OnTokenLoaded(const std::string& token,
79 const std::string& device_id) override;
81 // UserPolicyDiskCache::Delegate:
82 void OnDiskCacheLoaded(UserPolicyDiskCache::LoadResult result,
83 const em::CachedCloudPolicyResponse& policy) override;
85 private:
86 // Checks whether the load operations from the legacy caches completed. If so,
87 // fires the appropriate notification.
88 void CheckLoadFinished();
90 // Maps a disk cache LoadResult to a CloudPolicyStore::Status.
91 static CloudPolicyStore::Status TranslateLoadResult(
92 UserPolicyDiskCache::LoadResult result);
94 scoped_refptr<UserPolicyTokenLoader> token_loader_;
95 scoped_refptr<UserPolicyDiskCache> policy_cache_;
97 std::string dm_token_;
98 std::string device_id_;
99 scoped_ptr<em::PolicyFetchResponse> policy_;
100 CloudPolicyStore::Status status_;
102 Callback callback_;
104 base::WeakPtrFactory<LegacyPolicyCacheLoader> weak_factory_;
106 DISALLOW_COPY_AND_ASSIGN(LegacyPolicyCacheLoader);
109 LegacyPolicyCacheLoader::LegacyPolicyCacheLoader(
110 const base::FilePath& token_cache_file,
111 const base::FilePath& policy_cache_file,
112 scoped_refptr<base::SequencedTaskRunner> background_task_runner)
113 : status_(CloudPolicyStore::STATUS_OK),
114 weak_factory_(this) {
115 token_loader_ = new UserPolicyTokenLoader(weak_factory_.GetWeakPtr(),
116 token_cache_file,
117 background_task_runner);
118 policy_cache_ = new UserPolicyDiskCache(weak_factory_.GetWeakPtr(),
119 policy_cache_file,
120 background_task_runner);
123 LegacyPolicyCacheLoader::~LegacyPolicyCacheLoader() {}
125 void LegacyPolicyCacheLoader::Load(const Callback& callback) {
126 callback_ = callback;
127 token_loader_->Load();
128 policy_cache_->Load();
131 void LegacyPolicyCacheLoader::OnTokenLoaded(const std::string& token,
132 const std::string& device_id) {
133 dm_token_ = token;
134 device_id_ = device_id;
135 token_loader_ = NULL;
136 CheckLoadFinished();
139 void LegacyPolicyCacheLoader::OnDiskCacheLoaded(
140 UserPolicyDiskCache::LoadResult result,
141 const em::CachedCloudPolicyResponse& policy) {
142 status_ = TranslateLoadResult(result);
143 if (result == UserPolicyDiskCache::LOAD_RESULT_SUCCESS) {
144 if (policy.has_cloud_policy())
145 policy_.reset(new em::PolicyFetchResponse(policy.cloud_policy()));
146 } else {
147 LOG(WARNING) << "Failed to load legacy policy cache: " << result;
149 policy_cache_ = NULL;
150 CheckLoadFinished();
153 void LegacyPolicyCacheLoader::CheckLoadFinished() {
154 if (!token_loader_.get() && !policy_cache_.get())
155 callback_.Run(dm_token_, device_id_, status_, policy_.Pass());
158 // static
159 CloudPolicyStore::Status LegacyPolicyCacheLoader::TranslateLoadResult(
160 UserPolicyDiskCache::LoadResult result) {
161 switch (result) {
162 case UserPolicyDiskCache::LOAD_RESULT_SUCCESS:
163 case UserPolicyDiskCache::LOAD_RESULT_NOT_FOUND:
164 return CloudPolicyStore::STATUS_OK;
165 case UserPolicyDiskCache::LOAD_RESULT_PARSE_ERROR:
166 case UserPolicyDiskCache::LOAD_RESULT_READ_ERROR:
167 return CloudPolicyStore::STATUS_LOAD_ERROR;
169 NOTREACHED();
170 return CloudPolicyStore::STATUS_OK;
173 UserCloudPolicyStoreChromeOS::UserCloudPolicyStoreChromeOS(
174 chromeos::CryptohomeClient* cryptohome_client,
175 chromeos::SessionManagerClient* session_manager_client,
176 scoped_refptr<base::SequencedTaskRunner> background_task_runner,
177 const std::string& username,
178 const base::FilePath& user_policy_key_dir,
179 const base::FilePath& legacy_token_cache_file,
180 const base::FilePath& legacy_policy_cache_file)
181 : UserCloudPolicyStoreBase(background_task_runner),
182 cryptohome_client_(cryptohome_client),
183 session_manager_client_(session_manager_client),
184 username_(username),
185 user_policy_key_dir_(user_policy_key_dir),
186 legacy_cache_dir_(legacy_token_cache_file.DirName()),
187 legacy_loader_(new LegacyPolicyCacheLoader(legacy_token_cache_file,
188 legacy_policy_cache_file,
189 background_task_runner)),
190 legacy_caches_loaded_(false),
191 policy_key_loaded_(false),
192 weak_factory_(this) {}
194 UserCloudPolicyStoreChromeOS::~UserCloudPolicyStoreChromeOS() {}
196 void UserCloudPolicyStoreChromeOS::Store(
197 const em::PolicyFetchResponse& policy) {
198 // Cancel all pending requests.
199 weak_factory_.InvalidateWeakPtrs();
200 scoped_ptr<em::PolicyFetchResponse> response(
201 new em::PolicyFetchResponse(policy));
202 EnsurePolicyKeyLoaded(
203 base::Bind(&UserCloudPolicyStoreChromeOS::ValidatePolicyForStore,
204 weak_factory_.GetWeakPtr(),
205 base::Passed(&response)));
208 void UserCloudPolicyStoreChromeOS::Load() {
209 // Cancel all pending requests.
210 weak_factory_.InvalidateWeakPtrs();
211 session_manager_client_->RetrievePolicyForUser(
212 username_,
213 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyRetrieved,
214 weak_factory_.GetWeakPtr()));
217 void UserCloudPolicyStoreChromeOS::LoadImmediately() {
218 // This blocking DBus call is in the startup path and will block the UI
219 // thread. This only happens when the Profile is created synchronously, which
220 // on ChromeOS happens whenever the browser is restarted into the same
221 // session. That happens when the browser crashes, or right after signin if
222 // the user has flags configured in about:flags.
223 // However, on those paths we must load policy synchronously so that the
224 // Profile initialization never sees unmanaged prefs, which would lead to
225 // data loss. http://crbug.com/263061
226 std::string policy_blob =
227 session_manager_client_->BlockingRetrievePolicyForUser(username_);
228 if (policy_blob.empty()) {
229 // The session manager doesn't have policy, or the call failed.
230 // Just notify that the load is done, and don't bother with the legacy
231 // caches in this case.
232 NotifyStoreLoaded();
233 return;
236 scoped_ptr<em::PolicyFetchResponse> policy(new em::PolicyFetchResponse());
237 if (!policy->ParseFromString(policy_blob)) {
238 status_ = STATUS_PARSE_ERROR;
239 NotifyStoreError();
240 return;
243 std::string sanitized_username =
244 cryptohome_client_->BlockingGetSanitizedUsername(username_);
245 if (sanitized_username.empty()) {
246 status_ = STATUS_LOAD_ERROR;
247 NotifyStoreError();
248 return;
251 policy_key_path_ = user_policy_key_dir_.Append(
252 base::StringPrintf(kPolicyKeyFile, sanitized_username.c_str()));
253 LoadPolicyKey(policy_key_path_, &policy_key_);
254 policy_key_loaded_ = true;
256 scoped_ptr<UserCloudPolicyValidator> validator =
257 CreateValidatorForLoad(policy.Pass());
258 validator->RunValidation();
259 OnRetrievedPolicyValidated(validator.get());
262 void UserCloudPolicyStoreChromeOS::ValidatePolicyForStore(
263 scoped_ptr<em::PolicyFetchResponse> policy) {
264 // Create and configure a validator.
265 scoped_ptr<UserCloudPolicyValidator> validator =
266 CreateValidator(policy.Pass(),
267 CloudPolicyValidatorBase::TIMESTAMP_REQUIRED);
268 validator->ValidateUsername(username_, true);
269 if (policy_key_.empty()) {
270 validator->ValidateInitialKey(GetPolicyVerificationKey(),
271 ExtractDomain(username_));
272 } else {
273 const bool allow_rotation = true;
274 validator->ValidateSignature(policy_key_,
275 GetPolicyVerificationKey(),
276 ExtractDomain(username_),
277 allow_rotation);
280 // Start validation. The Validator will delete itself once validation is
281 // complete.
282 validator.release()->StartValidation(
283 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated,
284 weak_factory_.GetWeakPtr()));
287 void UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated(
288 UserCloudPolicyValidator* validator) {
289 validation_status_ = validator->status();
291 UMA_HISTOGRAM_ENUMERATION(
292 "Enterprise.UserPolicyValidationStoreStatus",
293 validation_status_,
294 UserCloudPolicyValidator::VALIDATION_STATUS_SIZE);
296 if (!validator->success()) {
297 status_ = STATUS_VALIDATION_ERROR;
298 NotifyStoreError();
299 return;
302 std::string policy_blob;
303 if (!validator->policy()->SerializeToString(&policy_blob)) {
304 status_ = STATUS_SERIALIZE_ERROR;
305 NotifyStoreError();
306 return;
309 session_manager_client_->StorePolicyForUser(
310 username_,
311 policy_blob,
312 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyStored,
313 weak_factory_.GetWeakPtr()));
316 void UserCloudPolicyStoreChromeOS::OnPolicyStored(bool success) {
317 if (!success) {
318 status_ = STATUS_STORE_ERROR;
319 NotifyStoreError();
320 } else {
321 // Load the policy right after storing it, to make sure it was accepted by
322 // the session manager. An additional validation is performed after the
323 // load; reload the key for that validation too, in case it was rotated.
324 ReloadPolicyKey(base::Bind(&UserCloudPolicyStoreChromeOS::Load,
325 weak_factory_.GetWeakPtr()));
329 void UserCloudPolicyStoreChromeOS::OnPolicyRetrieved(
330 const std::string& policy_blob) {
331 if (policy_blob.empty()) {
332 // Policy fetch failed. Try legacy caches if we haven't done that already.
333 if (!legacy_caches_loaded_ && legacy_loader_.get()) {
334 legacy_caches_loaded_ = true;
335 legacy_loader_->Load(
336 base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished,
337 weak_factory_.GetWeakPtr()));
338 } else {
339 // session_manager doesn't have policy. Adjust internal state and notify
340 // the world about the policy update.
341 policy_.reset();
342 NotifyStoreLoaded();
344 return;
347 // Policy is supplied by session_manager. Disregard legacy data from now on.
348 legacy_loader_.reset();
350 scoped_ptr<em::PolicyFetchResponse> policy(new em::PolicyFetchResponse());
351 if (!policy->ParseFromString(policy_blob)) {
352 status_ = STATUS_PARSE_ERROR;
353 NotifyStoreError();
354 return;
357 // Load |policy_key_| to verify the loaded policy.
358 EnsurePolicyKeyLoaded(
359 base::Bind(&UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy,
360 weak_factory_.GetWeakPtr(),
361 base::Passed(&policy)));
364 void UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy(
365 scoped_ptr<em::PolicyFetchResponse> policy) {
366 // Create and configure a validator for the loaded policy.
367 scoped_ptr<UserCloudPolicyValidator> validator =
368 CreateValidatorForLoad(policy.Pass());
369 // Start validation. The Validator will delete itself once validation is
370 // complete.
371 validator.release()->StartValidation(
372 base::Bind(&UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated,
373 weak_factory_.GetWeakPtr()));
376 void UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated(
377 UserCloudPolicyValidator* validator) {
378 validation_status_ = validator->status();
380 UMA_HISTOGRAM_ENUMERATION(
381 "Enterprise.UserPolicyValidationLoadStatus",
382 validation_status_,
383 UserCloudPolicyValidator::VALIDATION_STATUS_SIZE);
385 if (!validator->success()) {
386 status_ = STATUS_VALIDATION_ERROR;
387 NotifyStoreError();
388 return;
391 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
392 status_ = STATUS_OK;
394 // Policy has been loaded successfully. This indicates that new-style policy
395 // is working, so the legacy cache directory can be removed.
396 if (!legacy_cache_dir_.empty()) {
397 background_task_runner()->PostTask(
398 FROM_HERE,
399 base::Bind(&UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir,
400 legacy_cache_dir_));
401 legacy_cache_dir_.clear();
403 NotifyStoreLoaded();
406 void UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished(
407 const std::string& dm_token,
408 const std::string& device_id,
409 Status status,
410 scoped_ptr<em::PolicyFetchResponse> policy) {
411 status_ = status;
412 if (policy.get()) {
413 // Create and configure a validator for the loaded legacy policy. Note that
414 // the signature on this policy is not verified.
415 scoped_ptr<UserCloudPolicyValidator> validator =
416 CreateValidator(policy.Pass(),
417 CloudPolicyValidatorBase::TIMESTAMP_REQUIRED);
418 validator->ValidateUsername(username_, true);
419 validator.release()->StartValidation(
420 base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated,
421 weak_factory_.GetWeakPtr(),
422 dm_token,
423 device_id));
424 } else {
425 InstallLegacyTokens(dm_token, device_id);
429 void UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated(
430 const std::string& dm_token,
431 const std::string& device_id,
432 UserCloudPolicyValidator* validator) {
433 validation_status_ = validator->status();
434 if (validator->success()) {
435 status_ = STATUS_OK;
436 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
438 // Clear the public key version. The public key version field would
439 // otherwise indicate that we have key installed in the store when in fact
440 // we haven't. This may result in policy updates failing signature
441 // verification.
442 policy_->clear_public_key_version();
443 } else {
444 status_ = STATUS_VALIDATION_ERROR;
447 InstallLegacyTokens(dm_token, device_id);
450 void UserCloudPolicyStoreChromeOS::InstallLegacyTokens(
451 const std::string& dm_token,
452 const std::string& device_id) {
453 // Write token and device ID to |policy_|, giving them precedence over the
454 // policy blob. This is to match the legacy behavior, which used token and
455 // device id exclusively from the token cache file.
456 if (!dm_token.empty() && !device_id.empty()) {
457 if (!policy_.get())
458 policy_.reset(new em::PolicyData());
459 policy_->set_request_token(dm_token);
460 policy_->set_device_id(device_id);
463 // Tell the rest of the world that the policy load completed.
464 NotifyStoreLoaded();
467 // static
468 void UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir(
469 const base::FilePath& dir) {
470 if (base::PathExists(dir) && !base::DeleteFile(dir, true))
471 LOG(ERROR) << "Failed to remove cache dir " << dir.value();
474 void UserCloudPolicyStoreChromeOS::ReloadPolicyKey(
475 const base::Closure& callback) {
476 std::string* key = new std::string();
477 background_task_runner()->PostTaskAndReply(
478 FROM_HERE,
479 base::Bind(&UserCloudPolicyStoreChromeOS::LoadPolicyKey,
480 policy_key_path_,
481 key),
482 base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyKeyReloaded,
483 weak_factory_.GetWeakPtr(),
484 base::Owned(key),
485 callback));
488 // static
489 void UserCloudPolicyStoreChromeOS::LoadPolicyKey(const base::FilePath& path,
490 std::string* key) {
491 if (!base::PathExists(path)) {
492 // There is no policy key the first time that a user fetches policy. If
493 // |path| does not exist then that is the most likely scenario, so there's
494 // no need to sample a failure.
495 VLOG(1) << "No key at " << path.value();
496 return;
499 const bool read_success = base::ReadFileToString(path, key, kKeySizeLimit);
500 // If the read was successful and the file size is 0 or if the read fails
501 // due to file size exceeding |kKeySizeLimit|, log error.
502 if ((read_success && key->length() == 0) ||
503 (!read_success && key->length() == kKeySizeLimit)) {
504 LOG(ERROR) << "Key at " << path.value()
505 << (read_success ? " is empty." : " exceeds size limit");
506 key->clear();
507 } else if (!read_success) {
508 LOG(ERROR) << "Failed to read key at " << path.value();
511 if (key->empty())
512 SampleValidationFailure(VALIDATION_FAILURE_LOAD_KEY);
515 void UserCloudPolicyStoreChromeOS::OnPolicyKeyReloaded(
516 std::string* key,
517 const base::Closure& callback) {
518 policy_key_ = *key;
519 policy_key_loaded_ = true;
520 callback.Run();
523 void UserCloudPolicyStoreChromeOS::EnsurePolicyKeyLoaded(
524 const base::Closure& callback) {
525 if (policy_key_loaded_) {
526 callback.Run();
527 } else {
528 // Get the hashed username that's part of the key's path, to determine
529 // |policy_key_path_|.
530 cryptohome_client_->GetSanitizedUsername(username_,
531 base::Bind(&UserCloudPolicyStoreChromeOS::OnGetSanitizedUsername,
532 weak_factory_.GetWeakPtr(),
533 callback));
537 void UserCloudPolicyStoreChromeOS::OnGetSanitizedUsername(
538 const base::Closure& callback,
539 chromeos::DBusMethodCallStatus call_status,
540 const std::string& sanitized_username) {
541 // The default empty path will always yield an empty key.
542 if (call_status == chromeos::DBUS_METHOD_CALL_SUCCESS &&
543 !sanitized_username.empty()) {
544 policy_key_path_ = user_policy_key_dir_.Append(
545 base::StringPrintf(kPolicyKeyFile, sanitized_username.c_str()));
546 } else {
547 SampleValidationFailure(VALIDATION_FAILURE_DBUS);
549 ReloadPolicyKey(callback);
552 scoped_ptr<UserCloudPolicyValidator>
553 UserCloudPolicyStoreChromeOS::CreateValidatorForLoad(
554 scoped_ptr<em::PolicyFetchResponse> policy) {
555 scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator(
556 policy.Pass(), CloudPolicyValidatorBase::TIMESTAMP_NOT_BEFORE);
557 validator->ValidateUsername(username_, true);
558 const bool allow_rotation = false;
559 const std::string empty_key = std::string();
560 // The policy loaded from session manager need not be validated using the
561 // verification key since it is secure, and since there may be legacy policy
562 // data that was stored without a verification key. Hence passing an empty
563 // value for the verification key.
564 validator->ValidateSignature(
565 policy_key_, empty_key, ExtractDomain(username_), allow_rotation);
566 return validator.Pass();
568 } // namespace policy