user_cloud_policy_store.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/policy/core/common/cloud/user_cloud_policy_store.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/bind.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/location.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/metrics/histogram.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/task_runner_util.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gaia/gaia_auth_util.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "policy/proto/cloud_policy.pb.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "policy/proto/device_management_backend.pb.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "policy/proto/policy_signing_key.pb.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace em = enterprise_management;
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace policy {
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// This enum is used to define the buckets for an enumerated UMA histogram.
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Hence,
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//   (a) existing enumerated constants should never be deleted or reordered, and
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//   (b) new constants should only be appended at the end of the enumeration.
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Keep this in sync with EnterprisePolicyLoadStatus in histograms.xml.
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum PolicyLoadStatus {
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Policy blob was successfully loaded and parsed.
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOAD_RESULT_SUCCESS,
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // No previously stored policy was found.
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOAD_RESULT_NO_POLICY_FILE,
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Could not load the previously stored policy due to either a parse or
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // file read error.
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LOAD_RESULT_LOAD_ERROR,
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // LOAD_RESULT_SIZE is the number of items in this enum and is used when
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // logging histograms to set the bucket size, so should always be the last
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // item.
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  LOAD_RESULT_SIZE,
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Struct containing the result of a policy load - if |status| ==
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// LOAD_RESULT_SUCCESS, |policy| is initialized from the policy file on disk.
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)struct PolicyLoadResult {
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PolicyLoadStatus status;
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  em::PolicyFetchResponse policy;
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  em::PolicySigningKey key;
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Subdirectory in the user's profile for storing user policies.
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const base::FilePath::CharType kPolicyDir[] = FILE_PATH_LITERAL("Policy");
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// File in the above directory for storing user policy data.
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const base::FilePath::CharType kPolicyCacheFile[] =
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    FILE_PATH_LITERAL("User Policy");
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// File in the above directory for storing policy signing key data.
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const base::FilePath::CharType kKeyCacheFile[] =
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    FILE_PATH_LITERAL("Signing Key");
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kMetricPolicyHasVerifiedCachedKey[] =
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "Enterprise.PolicyHasVerifiedCachedKey";
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Maximum policy and key size that will be loaded, in bytes.
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const size_t kPolicySizeLimit = 1024 * 1024;
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const size_t kKeySizeLimit = 16 * 1024;
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Loads policy from the backing file. Returns a PolicyLoadResult with the
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// results of the fetch.
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)policy::PolicyLoadResult LoadPolicyFromDisk(
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& policy_path,
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& key_path) {
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  policy::PolicyLoadResult result;
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If the backing file does not exist, just return. We don't verify the key
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // path here, because the key is optional (the validation code will fail if
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the key does not exist but the loaded policy is unsigned).
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!base::PathExists(policy_path)) {
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result.status = policy::LOAD_RESULT_NO_POLICY_FILE;
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return result;
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string data;
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!base::ReadFileToString(policy_path, &data, kPolicySizeLimit) ||
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !result.policy.ParseFromString(data)) {
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(WARNING) << "Failed to read or parse policy data from "
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 << policy_path.value();
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result.status = policy::LOAD_RESULT_LOAD_ERROR;
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return result;
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!base::ReadFileToString(key_path, &data, kKeySizeLimit) ||
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !result.key.ParseFromString(data)) {
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Log an error on missing key data, but do not trigger a load failure
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // for now since there are still old unsigned cached policy blobs in the
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // wild with no associated key (see kMetricPolicyHasVerifiedCachedKey UMA
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // stat below).
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Failed to read or parse key data from " << key_path.value();
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result.key.clear_signing_key();
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Track the occurrence of valid cached keys - when this ratio gets high
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // enough, we can update the code to reject unsigned policy or unverified
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // keys.
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN(kMetricPolicyHasVerifiedCachedKey,
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        result.key.has_signing_key());
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  result.status = policy::LOAD_RESULT_SUCCESS;
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return result;
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool WriteStringToFile(const base::FilePath path, const std::string& data) {
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!base::CreateDirectory(path.DirName())) {
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DLOG(WARNING) << "Failed to create directory " << path.DirName().value();
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int size = data.size();
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (base::WriteFile(path, data.c_str(), size) != size) {
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DLOG(WARNING) << "Failed to write " << path.value();
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Stores policy to the backing file (must be called via a task on
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the background thread).
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void StorePolicyToDiskOnBackgroundThread(
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& policy_path,
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& key_path,
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& verification_key,
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const em::PolicyFetchResponse& policy) {
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Storing policy to " << policy_path.value();
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string data;
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!policy.SerializeToString(&data)) {
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DLOG(WARNING) << "Failed to serialize policy data";
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!WriteStringToFile(policy_path, data))
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (policy.has_new_public_key()) {
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Write the new public key and its verification signature/key to a file.
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    em::PolicySigningKey key_info;
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    key_info.set_signing_key(policy.new_public_key());
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    key_info.set_signing_key_signature(
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        policy.new_public_key_verification_signature());
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    key_info.set_verification_key(verification_key);
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string key_data;
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!key_info.SerializeToString(&key_data)) {
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DLOG(WARNING) << "Failed to serialize policy signing key";
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    WriteStringToFile(key_path, key_data);
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)UserCloudPolicyStore::UserCloudPolicyStore(
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& policy_path,
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& key_path,
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& verification_key,
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> background_task_runner)
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : UserCloudPolicyStoreBase(background_task_runner),
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      policy_path_(policy_path),
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      key_path_(key_path),
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      verification_key_(verification_key),
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      weak_factory_(this) {}
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)UserCloudPolicyStore::~UserCloudPolicyStore() {}
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<UserCloudPolicyStore> UserCloudPolicyStore::Create(
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& profile_path,
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& verification_key,
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::FilePath policy_path =
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      profile_path.Append(kPolicyDir).Append(kPolicyCacheFile);
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::FilePath key_path =
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      profile_path.Append(kPolicyDir).Append(kKeyCacheFile);
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return make_scoped_ptr(new UserCloudPolicyStore(
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      policy_path, key_path, verification_key, background_task_runner));
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void UserCloudPolicyStore::SetSigninUsername(const std::string& username) {
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  signin_username_ = username;
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void UserCloudPolicyStore::LoadImmediately() {
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Initiating immediate policy load from disk";
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Cancel any pending Load/Store/Validate operations.
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  weak_factory_.InvalidateWeakPtrs();
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Load the policy from disk...
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PolicyLoadResult result = LoadPolicyFromDisk(policy_path_, key_path_);
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // ...and install it, reporting success/failure to any observers.
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PolicyLoaded(false, result);
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void UserCloudPolicyStore::Clear() {
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  background_task_runner()->PostTask(
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(base::IgnoreResult(&base::DeleteFile), policy_path_, false));
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  background_task_runner()->PostTask(
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(base::IgnoreResult(&base::DeleteFile), key_path_, false));
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  policy_.reset();
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  policy_map_.Clear();
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  policy_key_.clear();
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NotifyStoreLoaded();
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void UserCloudPolicyStore::Load() {
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Initiating policy load from disk";
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Cancel any pending Load/Store/Validate operations.
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  weak_factory_.InvalidateWeakPtrs();
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Start a new Load operation and have us get called back when it is
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // complete.
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::PostTaskAndReplyWithResult(
2261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      background_task_runner().get(),
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&LoadPolicyFromDisk, policy_path_, key_path_),
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&UserCloudPolicyStore::PolicyLoaded,
2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 weak_factory_.GetWeakPtr(),
2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 true));
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void UserCloudPolicyStore::PolicyLoaded(bool validate_in_background,
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        PolicyLoadResult result) {
2365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Enterprise.UserCloudPolicyStore.LoadStatus",
2375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            result.status,
2385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            LOAD_RESULT_SIZE);
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  switch (result.status) {
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case LOAD_RESULT_LOAD_ERROR:
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      status_ = STATUS_LOAD_ERROR;
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NotifyStoreError();
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case LOAD_RESULT_NO_POLICY_FILE:
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DVLOG(1) << "No policy found on disk";
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NotifyStoreLoaded();
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case LOAD_RESULT_SUCCESS: {
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Found policy on disk - need to validate it before it can be used.
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scoped_ptr<em::PolicyFetchResponse> cloud_policy(
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          new em::PolicyFetchResponse(result.policy));
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scoped_ptr<em::PolicySigningKey> key(
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          new em::PolicySigningKey(result.key));
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      bool doing_key_rotation = false;
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const std::string& verification_key = verification_key_;
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (!key->has_verification_key() ||
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          key->verification_key() != verification_key_) {
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // The cached key didn't match our current key, so we're doing a key
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // rotation - make sure we request a new key from the server on our
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // next fetch.
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        doing_key_rotation = true;
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        DLOG(WARNING) << "Verification key rotation detected";
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // TODO(atwilson): Add code to update |verification_key| to point to
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // the correct key to validate the existing blob (can't do this until
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // we've done our first key rotation).
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      Validate(cloud_policy.Pass(),
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               key.Pass(),
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               verification_key,
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               validate_in_background,
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               base::Bind(
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   &UserCloudPolicyStore::InstallLoadedPolicyAfterValidation,
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   weak_factory_.GetWeakPtr(),
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   doing_key_rotation,
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   result.key.has_signing_key() ?
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       result.key.signing_key() : std::string()));
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    default:
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NOTREACHED();
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void UserCloudPolicyStore::InstallLoadedPolicyAfterValidation(
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool doing_key_rotation,
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& signing_key,
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UserCloudPolicyValidator* validator) {
2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION(
2935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      "Enterprise.UserCloudPolicyStore.LoadValidationStatus",
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      validator->status(),
2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      CloudPolicyValidatorBase::VALIDATION_STATUS_SIZE);
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  validation_status_ = validator->status();
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!validator->success()) {
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Validation failed: status=" << validation_status_;
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    status_ = STATUS_VALIDATION_ERROR;
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    NotifyStoreError();
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Validation succeeded - installing policy with dm_token: " <<
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      validator->policy_data()->request_token();
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Device ID: " << validator->policy_data()->device_id();
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If we're doing a key rotation, clear the public key version so a future
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // policy fetch will force regeneration of the keys.
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (doing_key_rotation) {
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    validator->policy_data()->clear_public_key_version();
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    policy_key_.clear();
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Policy validation succeeded, so we know the signing key is good.
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    policy_key_ = signing_key;
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  status_ = STATUS_OK;
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NotifyStoreLoaded();
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void UserCloudPolicyStore::Store(const em::PolicyFetchResponse& policy) {
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Stop any pending requests to store policy, then validate the new policy
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // before storing it.
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  weak_factory_.InvalidateWeakPtrs();
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<em::PolicyFetchResponse> policy_copy(
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new em::PolicyFetchResponse(policy));
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Validate(policy_copy.Pass(),
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           scoped_ptr<em::PolicySigningKey>(),
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           verification_key_,
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           true,
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           base::Bind(&UserCloudPolicyStore::StorePolicyAfterValidation,
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      weak_factory_.GetWeakPtr()));
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void UserCloudPolicyStore::Validate(
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<em::PolicyFetchResponse> policy,
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<em::PolicySigningKey> cached_key,
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& verification_key,
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool validate_in_background,
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UserCloudPolicyValidator::CompletionCallback& callback) {
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Configure the validator.
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator(
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      policy.Pass(),
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      CloudPolicyValidatorBase::TIMESTAMP_NOT_BEFORE);
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Extract the owning domain from the signed-in user (if any is set yet).
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If there's no owning domain, then the code just ensures that the policy
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // is self-consistent (that the keys are signed with the same domain that the
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // username field in the policy contains). UserPolicySigninServerBase will
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // verify that the username matches the signed in user once profile
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // initialization is complete (http://crbug.com/342327).
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string owning_domain;
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Validate the username if the user is signed in. The signin_username_ can
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // be empty during initial policy load because this happens before the
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Prefs subsystem is initialized.
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!signin_username_.empty()) {
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Validating username: " << signin_username_;
361a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    validator->ValidateUsername(signin_username_, true);
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    owning_domain = gaia::ExtractDomainName(
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        gaia::CanonicalizeEmail(gaia::SanitizeEmail(signin_username_)));
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // There are 4 cases:
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // 1) Validation after loading from cache with no cached key.
36903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Action: Just validate signature with an empty key - this will result in
37003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // a failed validation and the cached policy will be rejected.
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // 2) Validation after loading from cache with a cached key
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Action: Validate signature on policy blob but don't allow key rotation.
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // 3) Validation after loading new policy from the server with no cached key
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Action: Validate as initial key provisioning (case where we are migrating
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // from unsigned policy)
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // 4) Validation after loading new policy from the server with a cached key
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Action: Validate as normal, and allow key rotation.
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (cached_key) {
38203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // Case #1/#2 - loading from cache. Validate the cached key (if no key,
38303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // then the validation will fail), then do normal policy data signature
38403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // validation using the cached key.
38503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Loading from cache should not change the cached keys.
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(policy_key_.empty() || policy_key_ == cached_key->signing_key());
38803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    DLOG_IF(WARNING, !cached_key->has_signing_key()) <<
38903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        "Unsigned policy blob detected";
39003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
39103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    validator->ValidateCachedKey(cached_key->signing_key(),
39203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                 cached_key->signing_key_signature(),
39303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                 verification_key,
39403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                 owning_domain);
39503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // Loading from cache, so don't allow key rotation.
39603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const bool no_rotation = false;
39703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    validator->ValidateSignature(cached_key->signing_key(),
39803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                 verification_key,
39903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                 owning_domain,
40003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                 no_rotation);
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // No passed cached_key - this is not validating the initial policy load
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // from cache, but rather an update from the server.
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (policy_key_.empty()) {
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Case #3 - no valid existing policy key (either this is the initial
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // policy fetch, or we're doing a key rotation), so this new policy fetch
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // should include an initial key provision.
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      validator->ValidateInitialKey(verification_key, owning_domain);
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else {
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Case #4 - verify new policy with existing key. We always allow key
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // rotation - the verification key will prevent invalid policy from being
4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // injected. |policy_key_| is already known to be valid, so no need to
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // verify via ValidateCachedKey().
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const bool allow_rotation = true;
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      validator->ValidateSignature(
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          policy_key_, verification_key, owning_domain, allow_rotation);
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (validate_in_background) {
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Start validation in the background. The Validator will free itself once
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // validation is complete.
4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    validator.release()->StartValidation(callback);
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Run validation immediately and invoke the callback with the results.
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    validator->RunValidation();
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(validator.get());
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void UserCloudPolicyStore::StorePolicyAfterValidation(
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UserCloudPolicyValidator* validator) {
4335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION(
4345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      "Enterprise.UserCloudPolicyStore.StoreValidationStatus",
4355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      validator->status(),
4365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      CloudPolicyValidatorBase::VALIDATION_STATUS_SIZE);
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  validation_status_ = validator->status();
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Policy validation complete: status = " << validation_status_;
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!validator->success()) {
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    status_ = STATUS_VALIDATION_ERROR;
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    NotifyStoreError();
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Persist the validated policy (just fire a task - don't bother getting a
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // reply because we can't do anything if it fails).
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  background_task_runner()->PostTask(
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&StorePolicyToDiskOnBackgroundThread,
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 policy_path_, key_path_, verification_key_,
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 *validator->policy()));
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If the key was rotated, update our local cache of the key.
4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (validator->policy()->has_new_public_key())
4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    policy_key_ = validator->policy()->new_public_key();
4575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  status_ = STATUS_OK;
4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NotifyStoreLoaded();
4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace policy
462