Update broken references to image assets
[chromium-blink-merge.git] / chromeos / network / onc / onc_merger.cc
blob2237b3a9c2b3a36fa28d8c6f1557dd848a3e40e7
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 "chromeos/network/onc/onc_merger.h"
7 #include <set>
8 #include <string>
9 #include <vector>
11 #include "base/basictypes.h"
12 #include "base/logging.h"
13 #include "base/values.h"
14 #include "chromeos/network/onc/onc_signature.h"
15 #include "components/onc/onc_constants.h"
17 namespace chromeos {
18 namespace onc {
19 namespace {
21 typedef scoped_ptr<base::DictionaryValue> DictionaryPtr;
23 // Returns true if the field is the identifier of a configuration, i.e. the GUID
24 // of a network or a certificate.
25 bool IsIdentifierField(const OncValueSignature& value_signature,
26 const std::string& field_name) {
27 if (&value_signature == &kNetworkConfigurationSignature)
28 return field_name == ::onc::network_config::kGUID;
29 if (&value_signature == &kCertificateSignature)
30 return field_name == ::onc::certificate::kGUID;
31 return false;
34 // Identifier fields and other read-only fields (specifically Type) are
35 // handled specially during merging because they are always identical for the
36 // various setting sources.
37 bool IsReadOnlyField(const OncValueSignature& value_signature,
38 const std::string& field_name) {
39 if (IsIdentifierField(value_signature, field_name))
40 return true;
41 if (&value_signature == &kNetworkConfigurationSignature)
42 return field_name == ::onc::network_config::kType;
43 return false;
46 // Inserts |true| at every field name in |result| that is recommended in
47 // |policy|.
48 void MarkRecommendedFieldnames(const base::DictionaryValue& policy,
49 base::DictionaryValue* result) {
50 const base::ListValue* recommended_value = NULL;
51 if (!policy.GetListWithoutPathExpansion(::onc::kRecommended,
52 &recommended_value))
53 return;
54 for (base::ListValue::const_iterator it = recommended_value->begin();
55 it != recommended_value->end(); ++it) {
56 std::string entry;
57 if ((*it)->GetAsString(&entry))
58 result->SetBooleanWithoutPathExpansion(entry, true);
62 // Returns a dictionary which contains |true| at each path that is editable by
63 // the user. No other fields are set.
64 DictionaryPtr GetEditableFlags(const base::DictionaryValue& policy) {
65 DictionaryPtr result_editable(new base::DictionaryValue);
66 MarkRecommendedFieldnames(policy, result_editable.get());
68 // Recurse into nested dictionaries.
69 for (base::DictionaryValue::Iterator it(policy); !it.IsAtEnd();
70 it.Advance()) {
71 const base::DictionaryValue* child_policy = NULL;
72 if (it.key() == ::onc::kRecommended ||
73 !it.value().GetAsDictionary(&child_policy)) {
74 continue;
77 result_editable->SetWithoutPathExpansion(
78 it.key(), GetEditableFlags(*child_policy).release());
80 return result_editable.Pass();
83 // This is the base class for merging a list of DictionaryValues in
84 // parallel. See MergeDictionaries function.
85 class MergeListOfDictionaries {
86 public:
87 typedef std::vector<const base::DictionaryValue*> DictPtrs;
89 MergeListOfDictionaries() {
92 virtual ~MergeListOfDictionaries() {
95 // For each path in any of the dictionaries |dicts|, the function
96 // MergeListOfValues is called with the list of values that are located at
97 // that path in each of the dictionaries. This function returns a new
98 // dictionary containing all results of MergeListOfValues at the respective
99 // paths. The resulting dictionary doesn't contain empty dictionaries.
100 DictionaryPtr MergeDictionaries(const DictPtrs &dicts) {
101 DictionaryPtr result(new base::DictionaryValue);
102 std::set<std::string> visited;
103 for (DictPtrs::const_iterator it_outer = dicts.begin();
104 it_outer != dicts.end(); ++it_outer) {
105 if (!*it_outer)
106 continue;
108 for (base::DictionaryValue::Iterator field(**it_outer); !field.IsAtEnd();
109 field.Advance()) {
110 const std::string& key = field.key();
111 if (key == ::onc::kRecommended || !visited.insert(key).second)
112 continue;
114 scoped_ptr<base::Value> merged_value;
115 if (field.value().IsType(base::Value::TYPE_DICTIONARY)) {
116 DictPtrs nested_dicts;
117 for (DictPtrs::const_iterator it_inner = dicts.begin();
118 it_inner != dicts.end(); ++it_inner) {
119 const base::DictionaryValue* nested_dict = NULL;
120 if (*it_inner)
121 (*it_inner)->GetDictionaryWithoutPathExpansion(key, &nested_dict);
122 nested_dicts.push_back(nested_dict);
124 DictionaryPtr merged_dict(MergeNestedDictionaries(key, nested_dicts));
125 if (!merged_dict->empty())
126 merged_value = merged_dict.Pass();
127 } else {
128 std::vector<const base::Value*> values;
129 for (DictPtrs::const_iterator it_inner = dicts.begin();
130 it_inner != dicts.end(); ++it_inner) {
131 const base::Value* value = NULL;
132 if (*it_inner)
133 (*it_inner)->GetWithoutPathExpansion(key, &value);
134 values.push_back(value);
136 merged_value = MergeListOfValues(key, values);
139 if (merged_value)
140 result->SetWithoutPathExpansion(key, merged_value.release());
143 return result.Pass();
146 protected:
147 // This function is called by MergeDictionaries for each list of values that
148 // are located at the same path in each of the dictionaries. The order of the
149 // values is the same as of the given dictionaries |dicts|. If a dictionary
150 // doesn't contain a path then it's value is NULL.
151 virtual scoped_ptr<base::Value> MergeListOfValues(
152 const std::string& key,
153 const std::vector<const base::Value*>& values) = 0;
155 virtual DictionaryPtr MergeNestedDictionaries(const std::string& key,
156 const DictPtrs &dicts) {
157 return MergeDictionaries(dicts);
160 private:
161 DISALLOW_COPY_AND_ASSIGN(MergeListOfDictionaries);
164 // This is the base class for merging policies and user settings.
165 class MergeSettingsAndPolicies : public MergeListOfDictionaries {
166 public:
167 struct ValueParams {
168 const base::Value* user_policy;
169 const base::Value* device_policy;
170 const base::Value* user_setting;
171 const base::Value* shared_setting;
172 const base::Value* active_setting;
173 bool user_editable;
174 bool device_editable;
177 MergeSettingsAndPolicies() {}
179 // Merge the provided dictionaries. For each path in any of the dictionaries,
180 // MergeValues is called. Its results are collected in a new dictionary which
181 // is then returned. The resulting dictionary never contains empty
182 // dictionaries.
183 DictionaryPtr MergeDictionaries(
184 const base::DictionaryValue* user_policy,
185 const base::DictionaryValue* device_policy,
186 const base::DictionaryValue* user_settings,
187 const base::DictionaryValue* shared_settings,
188 const base::DictionaryValue* active_settings) {
189 hasUserPolicy_ = (user_policy != NULL);
190 hasDevicePolicy_ = (device_policy != NULL);
192 DictionaryPtr user_editable;
193 if (user_policy != NULL)
194 user_editable = GetEditableFlags(*user_policy);
196 DictionaryPtr device_editable;
197 if (device_policy != NULL)
198 device_editable = GetEditableFlags(*device_policy);
200 std::vector<const base::DictionaryValue*> dicts(kLastIndex, NULL);
201 dicts[kUserPolicyIndex] = user_policy;
202 dicts[kDevicePolicyIndex] = device_policy;
203 dicts[kUserSettingsIndex] = user_settings;
204 dicts[kSharedSettingsIndex] = shared_settings;
205 dicts[kActiveSettingsIndex] = active_settings;
206 dicts[kUserEditableIndex] = user_editable.get();
207 dicts[kDeviceEditableIndex] = device_editable.get();
208 return MergeListOfDictionaries::MergeDictionaries(dicts);
211 protected:
212 // This function is called by MergeDictionaries for each list of values that
213 // are located at the same path in each of the dictionaries. Implementations
214 // can use the Has*Policy functions.
215 virtual scoped_ptr<base::Value> MergeValues(const std::string& key,
216 const ValueParams& values) = 0;
218 // Whether a user policy was provided.
219 bool HasUserPolicy() {
220 return hasUserPolicy_;
223 // Whether a device policy was provided.
224 bool HasDevicePolicy() {
225 return hasDevicePolicy_;
228 // MergeListOfDictionaries override.
229 scoped_ptr<base::Value> MergeListOfValues(
230 const std::string& key,
231 const std::vector<const base::Value*>& values) override {
232 bool user_editable = !HasUserPolicy();
233 if (values[kUserEditableIndex])
234 values[kUserEditableIndex]->GetAsBoolean(&user_editable);
236 bool device_editable = !HasDevicePolicy();
237 if (values[kDeviceEditableIndex])
238 values[kDeviceEditableIndex]->GetAsBoolean(&device_editable);
240 ValueParams params;
241 params.user_policy = values[kUserPolicyIndex];
242 params.device_policy = values[kDevicePolicyIndex];
243 params.user_setting = values[kUserSettingsIndex];
244 params.shared_setting = values[kSharedSettingsIndex];
245 params.active_setting = values[kActiveSettingsIndex];
246 params.user_editable = user_editable;
247 params.device_editable = device_editable;
248 return MergeValues(key, params);
251 private:
252 enum {
253 kUserPolicyIndex,
254 kDevicePolicyIndex,
255 kUserSettingsIndex,
256 kSharedSettingsIndex,
257 kActiveSettingsIndex,
258 kUserEditableIndex,
259 kDeviceEditableIndex,
260 kLastIndex
263 bool hasUserPolicy_, hasDevicePolicy_;
265 DISALLOW_COPY_AND_ASSIGN(MergeSettingsAndPolicies);
268 // Call MergeDictionaries to merge policies and settings to the effective
269 // values. This ignores the active settings of Shill. See the description of
270 // MergeSettingsAndPoliciesToEffective.
271 class MergeToEffective : public MergeSettingsAndPolicies {
272 public:
273 MergeToEffective() {}
275 protected:
276 // Merges |values| to the effective value (Mandatory policy overwrites user
277 // settings overwrites shared settings overwrites recommended policy). |which|
278 // is set to the respective onc::kAugmentation* constant that indicates which
279 // source of settings is effective. Note that this function may return a NULL
280 // pointer and set |which| to ::onc::kAugmentationUserPolicy, which means that
281 // the
282 // user policy didn't set a value but also didn't recommend it, thus enforcing
283 // the empty value.
284 scoped_ptr<base::Value> MergeValues(const std::string& key,
285 const ValueParams& values,
286 std::string* which) {
287 const base::Value* result = NULL;
288 which->clear();
289 if (!values.user_editable) {
290 result = values.user_policy;
291 *which = ::onc::kAugmentationUserPolicy;
292 } else if (!values.device_editable) {
293 result = values.device_policy;
294 *which = ::onc::kAugmentationDevicePolicy;
295 } else if (values.user_setting) {
296 result = values.user_setting;
297 *which = ::onc::kAugmentationUserSetting;
298 } else if (values.shared_setting) {
299 result = values.shared_setting;
300 *which = ::onc::kAugmentationSharedSetting;
301 } else if (values.user_policy) {
302 result = values.user_policy;
303 *which = ::onc::kAugmentationUserPolicy;
304 } else if (values.device_policy) {
305 result = values.device_policy;
306 *which = ::onc::kAugmentationDevicePolicy;
307 } else {
308 // Can be reached if the current field is recommended, but none of the
309 // dictionaries contained a value for it.
311 if (result)
312 return make_scoped_ptr(result->DeepCopy());
313 return scoped_ptr<base::Value>();
316 // MergeSettingsAndPolicies override.
317 scoped_ptr<base::Value> MergeValues(const std::string& key,
318 const ValueParams& values) override {
319 std::string which;
320 return MergeValues(key, values, &which);
323 private:
324 DISALLOW_COPY_AND_ASSIGN(MergeToEffective);
327 namespace {
329 // Returns true if all not-null values in |values| are equal to |value|.
330 bool AllPresentValuesEqual(const MergeSettingsAndPolicies::ValueParams& values,
331 const base::Value& value) {
332 if (values.user_policy && !value.Equals(values.user_policy))
333 return false;
334 if (values.device_policy && !value.Equals(values.device_policy))
335 return false;
336 if (values.user_setting && !value.Equals(values.user_setting))
337 return false;
338 if (values.shared_setting && !value.Equals(values.shared_setting))
339 return false;
340 if (values.active_setting && !value.Equals(values.active_setting))
341 return false;
342 return true;
345 } // namespace
347 // Call MergeDictionaries to merge policies and settings to an augmented
348 // dictionary which contains a dictionary for each value in the original
349 // dictionaries. See the description of MergeSettingsAndPoliciesToAugmented.
350 class MergeToAugmented : public MergeToEffective {
351 public:
352 MergeToAugmented() {}
354 DictionaryPtr MergeDictionaries(
355 const OncValueSignature& signature,
356 const base::DictionaryValue* user_policy,
357 const base::DictionaryValue* device_policy,
358 const base::DictionaryValue* user_settings,
359 const base::DictionaryValue* shared_settings,
360 const base::DictionaryValue* active_settings) {
361 signature_ = &signature;
362 return MergeToEffective::MergeDictionaries(user_policy,
363 device_policy,
364 user_settings,
365 shared_settings,
366 active_settings);
369 protected:
370 // MergeSettingsAndPolicies override.
371 scoped_ptr<base::Value> MergeValues(const std::string& key,
372 const ValueParams& values) override {
373 const OncFieldSignature* field = NULL;
374 if (signature_)
375 field = GetFieldSignature(*signature_, key);
377 if (!field) {
378 // This field is not part of the provided ONCSignature, thus it cannot be
379 // controlled by policy. Return the plain active value instead of an
380 // augmented dictionary.
381 if (values.active_setting)
382 return make_scoped_ptr(values.active_setting->DeepCopy());
383 return nullptr;
386 // This field is part of the provided ONCSignature, thus it can be
387 // controlled by policy.
388 std::string which_effective;
389 scoped_ptr<base::Value> effective_value =
390 MergeToEffective::MergeValues(key, values, &which_effective);
392 if (IsReadOnlyField(*signature_, key)) {
393 // Don't augment read-only fields (GUID and Type).
394 if (effective_value) {
395 // DCHECK that all provided fields are identical.
396 DCHECK(AllPresentValuesEqual(values, *effective_value))
397 << "Values do not match: " << key
398 << " Effective: " << *effective_value;
399 // Return the un-augmented field.
400 return effective_value.Pass();
402 if (values.active_setting) {
403 // Unmanaged networks have assigned (active) values.
404 return make_scoped_ptr(values.active_setting->DeepCopy());
406 LOG(ERROR) << "Field has no effective value: " << key;
407 return nullptr;
410 scoped_ptr<base::DictionaryValue> augmented_value(
411 new base::DictionaryValue);
413 if (values.active_setting) {
414 augmented_value->SetWithoutPathExpansion(
415 ::onc::kAugmentationActiveSetting, values.active_setting->DeepCopy());
418 if (!which_effective.empty()) {
419 augmented_value->SetStringWithoutPathExpansion(
420 ::onc::kAugmentationEffectiveSetting, which_effective);
423 // Prevent credentials from being forwarded in cleartext to
424 // UI. User/shared credentials are not stored separately, so they cannot
425 // leak here.
426 bool is_credential = onc::FieldIsCredential(*signature_, key);
427 if (!is_credential) {
428 if (values.user_policy) {
429 augmented_value->SetWithoutPathExpansion(
430 ::onc::kAugmentationUserPolicy, values.user_policy->DeepCopy());
432 if (values.device_policy) {
433 augmented_value->SetWithoutPathExpansion(
434 ::onc::kAugmentationDevicePolicy,
435 values.device_policy->DeepCopy());
438 if (values.user_setting) {
439 augmented_value->SetWithoutPathExpansion(
440 ::onc::kAugmentationUserSetting, values.user_setting->DeepCopy());
442 if (values.shared_setting) {
443 augmented_value->SetWithoutPathExpansion(
444 ::onc::kAugmentationSharedSetting,
445 values.shared_setting->DeepCopy());
447 if (HasUserPolicy() && values.user_editable) {
448 augmented_value->SetBooleanWithoutPathExpansion(
449 ::onc::kAugmentationUserEditable, true);
451 if (HasDevicePolicy() && values.device_editable) {
452 augmented_value->SetBooleanWithoutPathExpansion(
453 ::onc::kAugmentationDeviceEditable, true);
455 if (augmented_value->empty())
456 augmented_value.reset();
457 return augmented_value.Pass();
460 // MergeListOfDictionaries override.
461 DictionaryPtr MergeNestedDictionaries(const std::string& key,
462 const DictPtrs& dicts) override {
463 DictionaryPtr result;
464 if (signature_) {
465 const OncValueSignature* enclosing_signature = signature_;
466 signature_ = NULL;
468 const OncFieldSignature* field =
469 GetFieldSignature(*enclosing_signature, key);
470 if (field)
471 signature_ = field->value_signature;
472 result = MergeToEffective::MergeNestedDictionaries(key, dicts);
474 signature_ = enclosing_signature;
475 } else {
476 result = MergeToEffective::MergeNestedDictionaries(key, dicts);
478 return result.Pass();
481 private:
482 const OncValueSignature* signature_;
483 DISALLOW_COPY_AND_ASSIGN(MergeToAugmented);
486 } // namespace
488 DictionaryPtr MergeSettingsAndPoliciesToEffective(
489 const base::DictionaryValue* user_policy,
490 const base::DictionaryValue* device_policy,
491 const base::DictionaryValue* user_settings,
492 const base::DictionaryValue* shared_settings) {
493 MergeToEffective merger;
494 return merger.MergeDictionaries(
495 user_policy, device_policy, user_settings, shared_settings, NULL);
498 DictionaryPtr MergeSettingsAndPoliciesToAugmented(
499 const OncValueSignature& signature,
500 const base::DictionaryValue* user_policy,
501 const base::DictionaryValue* device_policy,
502 const base::DictionaryValue* user_settings,
503 const base::DictionaryValue* shared_settings,
504 const base::DictionaryValue* active_settings) {
505 MergeToAugmented merger;
506 return merger.MergeDictionaries(
507 signature, user_policy, device_policy, user_settings, shared_settings,
508 active_settings);
511 } // namespace onc
512 } // namespace chromeos