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/cloud_policy_cache_base.h"
6
7#include <string>
8
9#include "base/logging.h"
10#include "base/values.h"
11#include "chrome/browser/policy/configuration_policy_pref_store.h"
12#include "chrome/browser/policy/policy_notifier.h"
13
14namespace policy {
15
16// A thin ConfigurationPolicyProvider implementation sitting on top of
17// CloudPolicyCacheBase for hooking up with ConfigurationPolicyPrefStore.
18class CloudPolicyCacheBase::CloudPolicyProvider
19    : public ConfigurationPolicyProvider {
20 public:
21  CloudPolicyProvider(const PolicyDefinitionList* policy_list,
22                      CloudPolicyCacheBase* cache,
23                      CloudPolicyCacheBase::PolicyLevel level)
24      : ConfigurationPolicyProvider(policy_list),
25        cache_(cache),
26        level_(level) {}
27  virtual ~CloudPolicyProvider() {}
28
29  virtual bool Provide(ConfigurationPolicyStoreInterface* store) {
30    if (level_ == POLICY_LEVEL_MANDATORY)
31      ApplyPolicyMap(&cache_->mandatory_policy_, store);
32    else if (level_ == POLICY_LEVEL_RECOMMENDED)
33      ApplyPolicyMap(&cache_->recommended_policy_, store);
34    return true;
35  }
36
37  virtual bool IsInitializationComplete() const {
38    return cache_->initialization_complete_;
39  }
40
41  virtual void AddObserver(ConfigurationPolicyProvider::Observer* observer) {
42    cache_->observer_list_.AddObserver(observer);
43  }
44  virtual void RemoveObserver(ConfigurationPolicyProvider::Observer* observer) {
45    cache_->observer_list_.RemoveObserver(observer);
46  }
47
48 private:
49  // The underlying policy cache.
50  CloudPolicyCacheBase* cache_;
51  // Policy level this provider will handle.
52  CloudPolicyCacheBase::PolicyLevel level_;
53
54  DISALLOW_COPY_AND_ASSIGN(CloudPolicyProvider);
55};
56
57CloudPolicyCacheBase::CloudPolicyCacheBase()
58    : notifier_(NULL),
59      initialization_complete_(false),
60      is_unmanaged_(false) {
61  public_key_version_.valid = false;
62  managed_policy_provider_.reset(
63      new CloudPolicyProvider(
64          ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(),
65          this,
66          POLICY_LEVEL_MANDATORY));
67  recommended_policy_provider_.reset(
68      new CloudPolicyProvider(
69          ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(),
70          this,
71          POLICY_LEVEL_RECOMMENDED));
72}
73
74CloudPolicyCacheBase::~CloudPolicyCacheBase() {
75  FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
76                    observer_list_, OnProviderGoingAway());
77}
78
79bool CloudPolicyCacheBase::GetPublicKeyVersion(int* version) {
80  if (public_key_version_.valid)
81    *version = public_key_version_.version;
82
83  return public_key_version_.valid;
84}
85
86bool CloudPolicyCacheBase::SetPolicyInternal(
87    const em::PolicyFetchResponse& policy,
88    base::Time* timestamp,
89    bool check_for_timestamp_validity) {
90  DCHECK(CalledOnValidThread());
91  bool initialization_was_not_complete = !initialization_complete_;
92  is_unmanaged_ = false;
93  PolicyMap mandatory_policy;
94  PolicyMap recommended_policy;
95  base::Time temp_timestamp;
96  PublicKeyVersion temp_public_key_version;
97  bool ok = DecodePolicyResponse(policy, &mandatory_policy, &recommended_policy,
98                                 &temp_timestamp, &temp_public_key_version);
99  if (!ok) {
100    LOG(WARNING) << "Decoding policy data failed.";
101    return false;
102  }
103  if (timestamp) {
104    *timestamp = temp_timestamp;
105  }
106  if (check_for_timestamp_validity &&
107      temp_timestamp > base::Time::NowFromSystemTime()) {
108    LOG(WARNING) << "Rejected policy data, file is from the future.";
109    return false;
110  }
111  public_key_version_.version = temp_public_key_version.version;
112  public_key_version_.valid = temp_public_key_version.valid;
113
114  const bool new_policy_differs =
115      !mandatory_policy_.Equals(mandatory_policy) ||
116      !recommended_policy_.Equals(recommended_policy);
117  mandatory_policy_.Swap(&mandatory_policy);
118  recommended_policy_.Swap(&recommended_policy);
119  initialization_complete_ = true;
120
121  if (new_policy_differs || initialization_was_not_complete) {
122    FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
123                      observer_list_, OnUpdatePolicy());
124  }
125  InformNotifier(CloudPolicySubsystem::SUCCESS,
126                 CloudPolicySubsystem::NO_DETAILS);
127  return true;
128}
129
130void CloudPolicyCacheBase::SetUnmanagedInternal(const base::Time& timestamp) {
131  is_unmanaged_ = true;
132  initialization_complete_ = true;
133  public_key_version_.valid = false;
134  mandatory_policy_.Clear();
135  recommended_policy_.Clear();
136  last_policy_refresh_time_ = timestamp;
137
138  FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
139                    observer_list_, OnUpdatePolicy());
140}
141
142ConfigurationPolicyProvider* CloudPolicyCacheBase::GetManagedPolicyProvider() {
143  DCHECK(CalledOnValidThread());
144  return managed_policy_provider_.get();
145}
146
147ConfigurationPolicyProvider*
148    CloudPolicyCacheBase::GetRecommendedPolicyProvider() {
149  DCHECK(CalledOnValidThread());
150  return recommended_policy_provider_.get();
151}
152
153bool CloudPolicyCacheBase::DecodePolicyResponse(
154    const em::PolicyFetchResponse& policy_response,
155    PolicyMap* mandatory,
156    PolicyMap* recommended,
157    base::Time* timestamp,
158    PublicKeyVersion* public_key_version) {
159  std::string data = policy_response.policy_data();
160  em::PolicyData policy_data;
161  if (!policy_data.ParseFromString(data)) {
162    LOG(WARNING) << "Failed to parse PolicyData protobuf.";
163    return false;
164  }
165  if (timestamp) {
166    *timestamp = base::Time::UnixEpoch() +
167                 base::TimeDelta::FromMilliseconds(policy_data.timestamp());
168  }
169  if (public_key_version) {
170    public_key_version->valid = policy_data.has_public_key_version();
171    if (public_key_version->valid)
172      public_key_version->version = policy_data.public_key_version();
173  }
174
175  return DecodePolicyData(policy_data, mandatory, recommended);
176}
177
178void CloudPolicyCacheBase::InformNotifier(
179    CloudPolicySubsystem::PolicySubsystemState state,
180    CloudPolicySubsystem::ErrorDetails error_details) {
181  // TODO(jkummerow): To obsolete this NULL-check, make all uses of
182  // UserPolicyCache explicitly set a notifier using |set_policy_notifier()|.
183  if (notifier_)
184    notifier_->Inform(state, error_details, PolicyNotifier::POLICY_CACHE);
185}
186
187}  // namespace policy
188