- add sources.
[platform/framework/web/crosswalk.git] / src / chromeos / network / onc / onc_merger.cc
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 "chromeos/network/onc/onc_merger.h"
6
7 #include <set>
8 #include <string>
9 #include <vector>
10
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"
16
17 namespace chromeos {
18 namespace onc {
19 namespace {
20
21 typedef scoped_ptr<base::DictionaryValue> DictionaryPtr;
22
23 // Inserts |true| at every field name in |result| that is recommended in
24 // |policy|.
25 void MarkRecommendedFieldnames(const base::DictionaryValue& policy,
26                                base::DictionaryValue* result) {
27   const base::ListValue* recommended_value = NULL;
28   if (!policy.GetListWithoutPathExpansion(::onc::kRecommended,
29                                           &recommended_value))
30     return;
31   for (base::ListValue::const_iterator it = recommended_value->begin();
32        it != recommended_value->end(); ++it) {
33     std::string entry;
34     if ((*it)->GetAsString(&entry))
35       result->SetBooleanWithoutPathExpansion(entry, true);
36   }
37 }
38
39 // Returns a dictionary which contains |true| at each path that is editable by
40 // the user. No other fields are set.
41 DictionaryPtr GetEditableFlags(const base::DictionaryValue& policy) {
42   DictionaryPtr result_editable(new base::DictionaryValue);
43   MarkRecommendedFieldnames(policy, result_editable.get());
44
45   // Recurse into nested dictionaries.
46   for (base::DictionaryValue::Iterator it(policy); !it.IsAtEnd();
47        it.Advance()) {
48     const base::DictionaryValue* child_policy = NULL;
49     if (it.key() == ::onc::kRecommended ||
50         !it.value().GetAsDictionary(&child_policy)) {
51       continue;
52     }
53
54     result_editable->SetWithoutPathExpansion(
55         it.key(), GetEditableFlags(*child_policy).release());
56   }
57   return result_editable.Pass();
58 }
59
60 // This is the base class for merging a list of DictionaryValues in
61 // parallel. See MergeDictionaries function.
62 class MergeListOfDictionaries {
63  public:
64   typedef std::vector<const base::DictionaryValue*> DictPtrs;
65
66   MergeListOfDictionaries() {
67   }
68
69   virtual ~MergeListOfDictionaries() {
70   }
71
72   // For each path in any of the dictionaries |dicts|, the function
73   // MergeListOfValues is called with the list of values that are located at
74   // that path in each of the dictionaries. This function returns a new
75   // dictionary containing all results of MergeListOfValues at the respective
76   // paths. The resulting dictionary doesn't contain empty dictionaries.
77   DictionaryPtr MergeDictionaries(const DictPtrs &dicts) {
78     DictionaryPtr result(new base::DictionaryValue);
79     std::set<std::string> visited;
80     for (DictPtrs::const_iterator it_outer = dicts.begin();
81          it_outer != dicts.end(); ++it_outer) {
82       if (!*it_outer)
83         continue;
84
85       for (base::DictionaryValue::Iterator field(**it_outer); !field.IsAtEnd();
86            field.Advance()) {
87         const std::string& key = field.key();
88         if (key == ::onc::kRecommended || !visited.insert(key).second)
89           continue;
90
91         scoped_ptr<base::Value> merged_value;
92         if (field.value().IsType(base::Value::TYPE_DICTIONARY)) {
93           DictPtrs nested_dicts;
94           for (DictPtrs::const_iterator it_inner = dicts.begin();
95                it_inner != dicts.end(); ++it_inner) {
96             const base::DictionaryValue* nested_dict = NULL;
97             if (*it_inner)
98               (*it_inner)->GetDictionaryWithoutPathExpansion(key, &nested_dict);
99             nested_dicts.push_back(nested_dict);
100           }
101           DictionaryPtr merged_dict(MergeNestedDictionaries(key, nested_dicts));
102           if (!merged_dict->empty())
103             merged_value = merged_dict.Pass();
104         } else {
105           std::vector<const base::Value*> values;
106           for (DictPtrs::const_iterator it_inner = dicts.begin();
107                it_inner != dicts.end(); ++it_inner) {
108             const base::Value* value = NULL;
109             if (*it_inner)
110               (*it_inner)->GetWithoutPathExpansion(key, &value);
111             values.push_back(value);
112           }
113           merged_value = MergeListOfValues(key, values);
114         }
115
116         if (merged_value)
117           result->SetWithoutPathExpansion(key, merged_value.release());
118       }
119     }
120     return result.Pass();
121   }
122
123  protected:
124   // This function is called by MergeDictionaries for each list of values that
125   // are located at the same path in each of the dictionaries. The order of the
126   // values is the same as of the given dictionaries |dicts|. If a dictionary
127   // doesn't contain a path then it's value is NULL.
128   virtual scoped_ptr<base::Value> MergeListOfValues(
129       const std::string& key,
130       const std::vector<const base::Value*>& values) = 0;
131
132   virtual DictionaryPtr MergeNestedDictionaries(const std::string& key,
133                                                 const DictPtrs &dicts) {
134     return MergeDictionaries(dicts);
135   }
136
137  private:
138   DISALLOW_COPY_AND_ASSIGN(MergeListOfDictionaries);
139 };
140
141 // This is the base class for merging policies and user settings.
142 class MergeSettingsAndPolicies : public MergeListOfDictionaries {
143  public:
144   struct ValueParams {
145     const base::Value* user_policy;
146     const base::Value* device_policy;
147     const base::Value* user_setting;
148     const base::Value* shared_setting;
149     const base::Value* active_setting;
150     bool user_editable;
151     bool device_editable;
152   };
153
154   MergeSettingsAndPolicies() {}
155
156   // Merge the provided dictionaries. For each path in any of the dictionaries,
157   // MergeValues is called. Its results are collected in a new dictionary which
158   // is then returned. The resulting dictionary never contains empty
159   // dictionaries.
160   DictionaryPtr MergeDictionaries(
161       const base::DictionaryValue* user_policy,
162       const base::DictionaryValue* device_policy,
163       const base::DictionaryValue* user_settings,
164       const base::DictionaryValue* shared_settings,
165       const base::DictionaryValue* active_settings) {
166     hasUserPolicy_ = (user_policy != NULL);
167     hasDevicePolicy_ = (device_policy != NULL);
168
169     DictionaryPtr user_editable;
170     if (user_policy != NULL)
171       user_editable = GetEditableFlags(*user_policy);
172
173     DictionaryPtr device_editable;
174     if (device_policy != NULL)
175       device_editable = GetEditableFlags(*device_policy);
176
177     std::vector<const base::DictionaryValue*> dicts(kLastIndex, NULL);
178     dicts[kUserPolicyIndex] = user_policy;
179     dicts[kDevicePolicyIndex] = device_policy;
180     dicts[kUserSettingsIndex] = user_settings;
181     dicts[kSharedSettingsIndex] = shared_settings;
182     dicts[kActiveSettingsIndex] = active_settings;
183     dicts[kUserEditableIndex] = user_editable.get();
184     dicts[kDeviceEditableIndex] = device_editable.get();
185     return MergeListOfDictionaries::MergeDictionaries(dicts);
186   }
187
188  protected:
189   // This function is called by MergeDictionaries for each list of values that
190   // are located at the same path in each of the dictionaries. Implementations
191   // can use the Has*Policy functions.
192   virtual scoped_ptr<base::Value> MergeValues(const std::string& key,
193                                               const ValueParams& values) = 0;
194
195   // Whether a user policy was provided.
196   bool HasUserPolicy() {
197     return hasUserPolicy_;
198   }
199
200   // Whether a device policy was provided.
201   bool HasDevicePolicy() {
202     return hasDevicePolicy_;
203   }
204
205   // MergeListOfDictionaries override.
206   virtual scoped_ptr<base::Value> MergeListOfValues(
207       const std::string& key,
208       const std::vector<const base::Value*>& values) OVERRIDE {
209     bool user_editable = !HasUserPolicy();
210     if (values[kUserEditableIndex])
211       values[kUserEditableIndex]->GetAsBoolean(&user_editable);
212
213     bool device_editable = !HasDevicePolicy();
214     if (values[kDeviceEditableIndex])
215       values[kDeviceEditableIndex]->GetAsBoolean(&device_editable);
216
217     ValueParams params;
218     params.user_policy = values[kUserPolicyIndex];
219     params.device_policy = values[kDevicePolicyIndex];
220     params.user_setting = values[kUserSettingsIndex];
221     params.shared_setting = values[kSharedSettingsIndex];
222     params.active_setting = values[kActiveSettingsIndex];
223     params.user_editable = user_editable;
224     params.device_editable = device_editable;
225     return MergeValues(key, params);
226   }
227
228  private:
229   enum {
230     kUserPolicyIndex,
231     kDevicePolicyIndex,
232     kUserSettingsIndex,
233     kSharedSettingsIndex,
234     kActiveSettingsIndex,
235     kUserEditableIndex,
236     kDeviceEditableIndex,
237     kLastIndex
238   };
239
240   bool hasUserPolicy_, hasDevicePolicy_;
241
242   DISALLOW_COPY_AND_ASSIGN(MergeSettingsAndPolicies);
243 };
244
245 // Call MergeDictionaries to merge policies and settings to the effective
246 // values. This ignores the active settings of Shill. See the description of
247 // MergeSettingsAndPoliciesToEffective.
248 class MergeToEffective : public MergeSettingsAndPolicies {
249  public:
250   MergeToEffective() {}
251
252  protected:
253   // Merges |values| to the effective value (Mandatory policy overwrites user
254   // settings overwrites shared settings overwrites recommended policy). |which|
255   // is set to the respective onc::kAugmentation* constant that indicates which
256   // source of settings is effective. Note that this function may return a NULL
257   // pointer and set |which| to ::onc::kAugmentationUserPolicy, which means that
258   // the
259   // user policy didn't set a value but also didn't recommend it, thus enforcing
260   // the empty value.
261   scoped_ptr<base::Value> MergeValues(const std::string& key,
262                                       const ValueParams& values,
263                                       std::string* which) {
264     const base::Value* result = NULL;
265     which->clear();
266     if (!values.user_editable) {
267       result = values.user_policy;
268       *which = ::onc::kAugmentationUserPolicy;
269     } else if (!values.device_editable) {
270       result = values.device_policy;
271       *which = ::onc::kAugmentationDevicePolicy;
272     } else if (values.user_setting) {
273       result = values.user_setting;
274       *which = ::onc::kAugmentationUserSetting;
275     } else if (values.shared_setting) {
276       result = values.shared_setting;
277       *which = ::onc::kAugmentationSharedSetting;
278     } else if (values.user_policy) {
279       result = values.user_policy;
280       *which = ::onc::kAugmentationUserPolicy;
281     } else if (values.device_policy) {
282       result = values.device_policy;
283       *which = ::onc::kAugmentationDevicePolicy;
284     } else {
285       // Can be reached if the current field is recommended, but none of the
286       // dictionaries contained a value for it.
287     }
288     if (result)
289       return make_scoped_ptr(result->DeepCopy());
290     return scoped_ptr<base::Value>();
291   }
292
293   // MergeSettingsAndPolicies override.
294   virtual scoped_ptr<base::Value> MergeValues(
295       const std::string& key,
296       const ValueParams& values) OVERRIDE {
297     std::string which;
298     return MergeValues(key, values, &which);
299   }
300
301  private:
302   DISALLOW_COPY_AND_ASSIGN(MergeToEffective);
303 };
304
305 // Call MergeDictionaries to merge policies and settings to an augmented
306 // dictionary which contains a dictionary for each value in the original
307 // dictionaries. See the description of MergeSettingsAndPoliciesToAugmented.
308 class MergeToAugmented : public MergeToEffective {
309  public:
310   MergeToAugmented() {}
311
312   DictionaryPtr MergeDictionaries(
313       const OncValueSignature& signature,
314       const base::DictionaryValue* user_policy,
315       const base::DictionaryValue* device_policy,
316       const base::DictionaryValue* user_settings,
317       const base::DictionaryValue* shared_settings,
318       const base::DictionaryValue* active_settings) {
319     signature_ = &signature;
320     return MergeToEffective::MergeDictionaries(user_policy,
321                                                device_policy,
322                                                user_settings,
323                                                shared_settings,
324                                                active_settings);
325   }
326
327  protected:
328   // MergeSettingsAndPolicies override.
329   virtual scoped_ptr<base::Value> MergeValues(
330       const std::string& key,
331       const ValueParams& values) OVERRIDE {
332     scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue);
333     if (values.active_setting) {
334       result->SetWithoutPathExpansion(::onc::kAugmentationActiveSetting,
335                                       values.active_setting->DeepCopy());
336     }
337
338     const OncFieldSignature* field = NULL;
339     if (signature_)
340       field = GetFieldSignature(*signature_, key);
341
342     if (field) {
343       // This field is part of the provided ONCSignature, thus it can be
344       // controlled by policy.
345       std::string which_effective;
346       MergeToEffective::MergeValues(key, values, &which_effective).reset();
347       if (!which_effective.empty()) {
348         result->SetStringWithoutPathExpansion(
349             ::onc::kAugmentationEffectiveSetting, which_effective);
350       }
351       bool is_credential = onc::FieldIsCredential(*signature_, key);
352
353       // Prevent credentials from being forwarded in cleartext to
354       // UI. User/shared credentials are not stored separately, so they cannot
355       // leak here.
356       if (!is_credential) {
357         if (values.user_policy) {
358           result->SetWithoutPathExpansion(::onc::kAugmentationUserPolicy,
359                                           values.user_policy->DeepCopy());
360         }
361         if (values.device_policy) {
362           result->SetWithoutPathExpansion(::onc::kAugmentationDevicePolicy,
363                                           values.device_policy->DeepCopy());
364         }
365       }
366       if (values.user_setting) {
367         result->SetWithoutPathExpansion(::onc::kAugmentationUserSetting,
368                                         values.user_setting->DeepCopy());
369       }
370       if (values.shared_setting) {
371         result->SetWithoutPathExpansion(::onc::kAugmentationSharedSetting,
372                                         values.shared_setting->DeepCopy());
373       }
374       if (HasUserPolicy() && values.user_editable) {
375         result->SetBooleanWithoutPathExpansion(::onc::kAugmentationUserEditable,
376                                                true);
377       }
378       if (HasDevicePolicy() && values.device_editable) {
379         result->SetBooleanWithoutPathExpansion(
380             ::onc::kAugmentationDeviceEditable, true);
381       }
382     } else {
383       // This field is not part of the provided ONCSignature, thus it cannot be
384       // controlled by policy.
385       result->SetStringWithoutPathExpansion(
386           ::onc::kAugmentationEffectiveSetting, ::onc::kAugmentationUnmanaged);
387     }
388     if (result->empty())
389       result.reset();
390     return result.PassAs<base::Value>();
391   }
392
393   // MergeListOfDictionaries override.
394   virtual DictionaryPtr MergeNestedDictionaries(
395       const std::string& key,
396       const DictPtrs &dicts) OVERRIDE {
397     DictionaryPtr result;
398     if (signature_) {
399       const OncValueSignature* enclosing_signature = signature_;
400       signature_ = NULL;
401
402       const OncFieldSignature* field =
403           GetFieldSignature(*enclosing_signature, key);
404       if (field)
405         signature_ = field->value_signature;
406       result = MergeToEffective::MergeNestedDictionaries(key, dicts);
407
408       signature_ = enclosing_signature;
409     } else {
410       result = MergeToEffective::MergeNestedDictionaries(key, dicts);
411     }
412     return result.Pass();
413   }
414
415  private:
416   const OncValueSignature* signature_;
417   DISALLOW_COPY_AND_ASSIGN(MergeToAugmented);
418 };
419
420 }  // namespace
421
422 DictionaryPtr MergeSettingsAndPoliciesToEffective(
423     const base::DictionaryValue* user_policy,
424     const base::DictionaryValue* device_policy,
425     const base::DictionaryValue* user_settings,
426     const base::DictionaryValue* shared_settings) {
427   MergeToEffective merger;
428   return merger.MergeDictionaries(
429       user_policy, device_policy, user_settings, shared_settings, NULL);
430 }
431
432 DictionaryPtr MergeSettingsAndPoliciesToAugmented(
433     const OncValueSignature& signature,
434     const base::DictionaryValue* user_policy,
435     const base::DictionaryValue* device_policy,
436     const base::DictionaryValue* user_settings,
437     const base::DictionaryValue* shared_settings,
438     const base::DictionaryValue* active_settings) {
439   MergeToAugmented merger;
440   return merger.MergeDictionaries(
441       signature, user_policy, device_policy, user_settings, shared_settings,
442       active_settings);
443 }
444
445 }  // namespace onc
446 }  // namespace chromeos