OLD | NEW |
| (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_policy_cache.h" | |
6 | |
7 #include <limits> | |
8 #include <string> | |
9 | |
10 #include "base/basictypes.h" | |
11 #include "base/file_path.h" | |
12 #include "base/logging.h" | |
13 #include "base/metrics/histogram.h" | |
14 #include "chrome/browser/policy/enterprise_metrics.h" | |
15 #include "chrome/browser/policy/policy_map.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/proto/old_generic_format.pb.h" | |
19 | |
20 namespace em = enterprise_management; | |
21 | |
22 namespace policy { | |
23 | |
24 // Decodes a CloudPolicySettings object into a PolicyMap. All the policies will | |
25 // be POLICY_SCOPE_USER. The PolicyLevel is decoded from the protobuf. | |
26 // The implementation is generated code in policy/cloud_policy_generated.cc. | |
27 void DecodePolicy(const em::CloudPolicySettings& policy, PolicyMap* map); | |
28 | |
29 UserPolicyCache::UserPolicyCache(const FilePath& backing_file_path, | |
30 bool wait_for_policy_fetch) | |
31 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), | |
32 disk_cache_ready_(false), | |
33 fetch_ready_(!wait_for_policy_fetch) { | |
34 disk_cache_ = new UserPolicyDiskCache(weak_ptr_factory_.GetWeakPtr(), | |
35 backing_file_path); | |
36 } | |
37 | |
38 UserPolicyCache::~UserPolicyCache() { | |
39 } | |
40 | |
41 void UserPolicyCache::Load() { | |
42 disk_cache_->Load(); | |
43 } | |
44 | |
45 bool UserPolicyCache::SetPolicy(const em::PolicyFetchResponse& policy) { | |
46 base::Time now = base::Time::NowFromSystemTime(); | |
47 set_last_policy_refresh_time(now); | |
48 base::Time timestamp; | |
49 if (!SetPolicyInternal(policy, ×tamp, false)) | |
50 return false; | |
51 UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, kMetricPolicyFetchOK, | |
52 kMetricPolicySize); | |
53 | |
54 if (timestamp > base::Time::NowFromSystemTime() + | |
55 base::TimeDelta::FromMinutes(1)) { | |
56 LOG(WARNING) << "Server returned policy with timestamp from the future, " | |
57 "not persisting to disk."; | |
58 return false; | |
59 } | |
60 | |
61 em::CachedCloudPolicyResponse cached_policy; | |
62 cached_policy.mutable_cloud_policy()->CopyFrom(policy); | |
63 disk_cache_->Store(cached_policy); | |
64 return true; | |
65 } | |
66 | |
67 void UserPolicyCache::SetUnmanaged() { | |
68 DCHECK(CalledOnValidThread()); | |
69 SetUnmanagedInternal(base::Time::NowFromSystemTime()); | |
70 | |
71 em::CachedCloudPolicyResponse cached_policy; | |
72 cached_policy.set_unmanaged(true); | |
73 cached_policy.set_timestamp(base::Time::NowFromSystemTime().ToTimeT()); | |
74 disk_cache_->Store(cached_policy); | |
75 } | |
76 | |
77 void UserPolicyCache::SetFetchingDone() { | |
78 CloudPolicyCacheBase::SetFetchingDone(); | |
79 if (!fetch_ready_) | |
80 DVLOG(1) << "SetFetchingDone, cache is now fetch_ready_"; | |
81 fetch_ready_ = true; | |
82 CheckIfReady(); | |
83 } | |
84 | |
85 void UserPolicyCache::OnDiskCacheLoaded( | |
86 UserPolicyDiskCache::LoadResult result, | |
87 const em::CachedCloudPolicyResponse& cached_response) { | |
88 if (IsReady()) | |
89 return; | |
90 | |
91 if (result == UserPolicyDiskCache::LOAD_RESULT_SUCCESS) { | |
92 if (cached_response.unmanaged()) { | |
93 SetUnmanagedInternal(base::Time::FromTimeT(cached_response.timestamp())); | |
94 } else if (cached_response.has_cloud_policy()) { | |
95 base::Time timestamp; | |
96 if (SetPolicyInternal(cached_response.cloud_policy(), ×tamp, true)) | |
97 set_last_policy_refresh_time(timestamp); | |
98 } | |
99 } | |
100 | |
101 // Ready to feed policy up the chain! | |
102 disk_cache_ready_ = true; | |
103 CheckIfReady(); | |
104 } | |
105 | |
106 bool UserPolicyCache::DecodePolicyData(const em::PolicyData& policy_data, | |
107 PolicyMap* policies) { | |
108 // TODO(jkummerow): Verify policy_data.device_token(). Needs final | |
109 // specification which token we're actually sending / expecting to get back. | |
110 em::CloudPolicySettings policy; | |
111 if (!policy.ParseFromString(policy_data.policy_value())) { | |
112 LOG(WARNING) << "Failed to parse CloudPolicySettings protobuf."; | |
113 return false; | |
114 } | |
115 DecodePolicy(policy, policies); | |
116 MaybeDecodeOldstylePolicy(policy_data.policy_value(), policies); | |
117 return true; | |
118 } | |
119 | |
120 void UserPolicyCache::CheckIfReady() { | |
121 if (!IsReady() && disk_cache_ready_ && fetch_ready_) | |
122 SetReady(); | |
123 } | |
124 | |
125 // Everything below is only needed for supporting old-style GenericNamedValue | |
126 // based policy data and can be removed once this support is no longer needed. | |
127 | |
128 using google::protobuf::RepeatedField; | |
129 using google::protobuf::RepeatedPtrField; | |
130 | |
131 void UserPolicyCache::MaybeDecodeOldstylePolicy( | |
132 const std::string& policy_data, | |
133 PolicyMap* policies) { | |
134 // Return immediately if we already have policy information in the maps. | |
135 if (!policies->empty()) | |
136 return; | |
137 em::LegacyChromeSettingsProto policy; | |
138 // Return if the input string doesn't match the protobuf definition. | |
139 if (!policy.ParseFromString(policy_data)) | |
140 return; | |
141 // Return if there's no old-style policy to decode. | |
142 if (policy.named_value_size() == 0) | |
143 return; | |
144 | |
145 // Inspect GenericNamedValues and decode them. | |
146 DictionaryValue result; | |
147 RepeatedPtrField<em::GenericNamedValue>::const_iterator named_value; | |
148 for (named_value = policy.named_value().begin(); | |
149 named_value != policy.named_value().end(); | |
150 ++named_value) { | |
151 if (named_value->has_value()) { | |
152 Value* decoded_value = DecodeValue(named_value->value()); | |
153 if (decoded_value) | |
154 result.Set(named_value->name(), decoded_value); | |
155 } | |
156 } | |
157 policies->LoadFrom(&result, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER); | |
158 } | |
159 | |
160 Value* UserPolicyCache::DecodeIntegerValue( | |
161 google::protobuf::int64 value) const { | |
162 if (value < std::numeric_limits<int>::min() || | |
163 value > std::numeric_limits<int>::max()) { | |
164 LOG(WARNING) << "Integer value " << value | |
165 << " out of numeric limits, ignoring."; | |
166 return NULL; | |
167 } | |
168 | |
169 return Value::CreateIntegerValue(static_cast<int>(value)); | |
170 } | |
171 | |
172 Value* UserPolicyCache::DecodeValue(const em::GenericValue& value) const { | |
173 if (!value.has_value_type()) | |
174 return NULL; | |
175 | |
176 switch (value.value_type()) { | |
177 case em::GenericValue::VALUE_TYPE_BOOL: | |
178 if (value.has_bool_value()) | |
179 return Value::CreateBooleanValue(value.bool_value()); | |
180 return NULL; | |
181 case em::GenericValue::VALUE_TYPE_INT64: | |
182 if (value.has_int64_value()) | |
183 return DecodeIntegerValue(value.int64_value()); | |
184 return NULL; | |
185 case em::GenericValue::VALUE_TYPE_STRING: | |
186 if (value.has_string_value()) | |
187 return Value::CreateStringValue(value.string_value()); | |
188 return NULL; | |
189 case em::GenericValue::VALUE_TYPE_DOUBLE: | |
190 if (value.has_double_value()) | |
191 return Value::CreateDoubleValue(value.double_value()); | |
192 return NULL; | |
193 case em::GenericValue::VALUE_TYPE_BYTES: | |
194 if (value.has_bytes_value()) { | |
195 std::string bytes = value.bytes_value(); | |
196 return base::BinaryValue::CreateWithCopiedBuffer(bytes.c_str(), | |
197 bytes.size()); | |
198 } | |
199 return NULL; | |
200 case em::GenericValue::VALUE_TYPE_BOOL_ARRAY: { | |
201 ListValue* list = new ListValue; | |
202 RepeatedField<bool>::const_iterator i; | |
203 for (i = value.bool_array().begin(); i != value.bool_array().end(); ++i) | |
204 list->Append(Value::CreateBooleanValue(*i)); | |
205 return list; | |
206 } | |
207 case em::GenericValue::VALUE_TYPE_INT64_ARRAY: { | |
208 ListValue* list = new ListValue; | |
209 RepeatedField<google::protobuf::int64>::const_iterator i; | |
210 for (i = value.int64_array().begin(); | |
211 i != value.int64_array().end(); ++i) { | |
212 Value* int_value = DecodeIntegerValue(*i); | |
213 if (int_value) | |
214 list->Append(int_value); | |
215 } | |
216 return list; | |
217 } | |
218 case em::GenericValue::VALUE_TYPE_STRING_ARRAY: { | |
219 ListValue* list = new ListValue; | |
220 RepeatedPtrField<std::string>::const_iterator i; | |
221 for (i = value.string_array().begin(); | |
222 i != value.string_array().end(); ++i) | |
223 list->Append(Value::CreateStringValue(*i)); | |
224 return list; | |
225 } | |
226 case em::GenericValue::VALUE_TYPE_DOUBLE_ARRAY: { | |
227 ListValue* list = new ListValue; | |
228 RepeatedField<double>::const_iterator i; | |
229 for (i = value.double_array().begin(); | |
230 i != value.double_array().end(); ++i) | |
231 list->Append(Value::CreateDoubleValue(*i)); | |
232 return list; | |
233 } | |
234 default: | |
235 NOTREACHED() << "Unhandled value type"; | |
236 } | |
237 | |
238 return NULL; | |
239 } | |
240 | |
241 } // namespace policy | |
OLD | NEW |