1// Copyright (c) 2013 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 "components/policy/core/common/cloud/component_cloud_policy_updater.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/logging.h"
10#include "base/sequenced_task_runner.h"
11#include "base/strings/string_number_conversions.h"
12#include "components/policy/core/common/cloud/component_cloud_policy_store.h"
13#include "components/policy/core/common/cloud/external_policy_data_fetcher.h"
14#include "policy/proto/chrome_extension_policy.pb.h"
15#include "policy/proto/device_management_backend.pb.h"
16
17namespace em = enterprise_management;
18
19namespace policy {
20
21namespace {
22
23// The maximum size of the serialized policy protobuf.
24const size_t kPolicyProtoMaxSize = 16 * 1024;
25
26// The maximum size of the downloaded policy data.
27const int64 kPolicyDataMaxSize = 5 * 1024 * 1024;
28
29// Tha maximum number of policy data fetches to run in parallel.
30const int64 kMaxParallelPolicyDataFetches = 2;
31
32}  // namespace
33
34ComponentCloudPolicyUpdater::ComponentCloudPolicyUpdater(
35    scoped_refptr<base::SequencedTaskRunner> task_runner,
36    scoped_ptr<ExternalPolicyDataFetcher> external_policy_data_fetcher,
37    ComponentCloudPolicyStore* store)
38    : store_(store),
39      external_policy_data_updater_(task_runner,
40                                    external_policy_data_fetcher.Pass(),
41                                    kMaxParallelPolicyDataFetches) {
42}
43
44ComponentCloudPolicyUpdater::~ComponentCloudPolicyUpdater() {
45}
46
47void ComponentCloudPolicyUpdater::UpdateExternalPolicy(
48    scoped_ptr<em::PolicyFetchResponse> response) {
49  // Keep a serialized copy of |response|, to cache it later.
50  // The policy is also rejected if it exceeds the maximum size.
51  std::string serialized_response;
52  if (!response->SerializeToString(&serialized_response) ||
53      serialized_response.size() > kPolicyProtoMaxSize) {
54    return;
55  }
56
57  // Validate the policy before doing anything else.
58  PolicyNamespace ns;
59  em::ExternalPolicyData data;
60  if (!store_->ValidatePolicy(response.Pass(), &ns, &data)) {
61    LOG(ERROR) << "Failed to validate component policy fetched from DMServer";
62    return;
63  }
64
65  // Maybe the data for this hash has already been downloaded and cached.
66  const std::string& cached_hash = store_->GetCachedHash(ns);
67  if (!cached_hash.empty() && data.secure_hash() == cached_hash)
68    return;
69
70  // TODO(joaodasilva): implement the other two auth methods.
71  if (data.download_auth_method() != em::ExternalPolicyData::NONE)
72    return;
73
74  const std::string key = NamespaceToKey(ns);
75
76  if (data.download_url().empty() || !data.has_secure_hash()) {
77    // If there is no policy for this component or the policy has been removed,
78    // cancel any existing request to fetch policy for this component.
79    external_policy_data_updater_.CancelExternalDataFetch(key);
80
81    // Delete any existing policy for this component.
82    store_->Delete(ns);
83  } else {
84    // Make a request to fetch policy for this component. If another fetch
85    // request is already pending for the component, it will be canceled.
86    external_policy_data_updater_.FetchExternalData(
87        key,
88        ExternalPolicyDataUpdater::Request(data.download_url(),
89                                           data.secure_hash(),
90                                           kPolicyDataMaxSize),
91        base::Bind(&ComponentCloudPolicyStore::Store, base::Unretained(store_),
92                   ns,
93                   serialized_response,
94                   data.secure_hash()));
95  }
96}
97
98void ComponentCloudPolicyUpdater::CancelUpdate(const PolicyNamespace& ns) {
99  external_policy_data_updater_.CancelExternalDataFetch(NamespaceToKey(ns));
100}
101
102std::string ComponentCloudPolicyUpdater::NamespaceToKey(
103    const PolicyNamespace& ns) {
104  const std::string domain = base::IntToString(ns.domain);
105  const std::string size = base::IntToString(domain.size());
106  return size + ":" + domain + ":" + ns.component_id;
107}
108
109}  // namespace policy
110