onc_validator_unittest.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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_validator.h"
6
7#include <string>
8#include <utility>
9
10#include "base/logging.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/values.h"
13#include "chromeos/network/onc/onc_signature.h"
14#include "chromeos/network/onc/onc_test_utils.h"
15#include "chromeos/network/onc/onc_utils.h"
16#include "components/onc/onc_constants.h"
17#include "testing/gtest/include/gtest/gtest.h"
18
19namespace chromeos {
20namespace onc {
21
22class ONCValidatorTest : public ::testing::Test {
23 public:
24  // Validate |onc_object| with the given |signature|. The object is considered
25  // to be managed if |managed_onc| is true. A strict validator is used if
26  // |strict| is true. |onc_object| and the resulting repaired object of the
27  // validation is stored, so that expectations can be checked afterwards using
28  // one of the Expect* functions below.
29  void Validate(bool strict,
30                scoped_ptr<base::DictionaryValue> onc_object,
31                const OncValueSignature* signature,
32                bool managed_onc,
33                ::onc::ONCSource onc_source) {
34    scoped_ptr<Validator> validator;
35    if (strict) {
36      // Create a strict validator that complains about every error.
37      validator.reset(new Validator(true, true, true, managed_onc));
38    } else {
39      // Create a liberal validator that ignores or repairs non-critical errors.
40      validator.reset(new Validator(false, false, false, managed_onc));
41    }
42    validator->SetOncSource(onc_source);
43    original_object_ = onc_object.Pass();
44    repaired_object_ = validator->ValidateAndRepairObject(signature,
45                                                          *original_object_,
46                                                          &validation_result_);
47  }
48
49  void ExpectValid() {
50    EXPECT_EQ(Validator::VALID, validation_result_);
51    EXPECT_TRUE(test_utils::Equals(original_object_.get(),
52                                   repaired_object_.get()));
53  }
54
55  void ExpectRepairWithWarnings(
56      const base::DictionaryValue& expected_repaired) {
57    EXPECT_EQ(Validator::VALID_WITH_WARNINGS, validation_result_);
58    EXPECT_TRUE(test_utils::Equals(&expected_repaired, repaired_object_.get()));
59  }
60
61  void ExpectInvalid() {
62    EXPECT_EQ(Validator::INVALID, validation_result_);
63    EXPECT_EQ(NULL, repaired_object_.get());
64  }
65
66 private:
67  Validator::Result validation_result_;
68  scoped_ptr<const base::DictionaryValue> original_object_;
69  scoped_ptr<const base::DictionaryValue> repaired_object_;
70};
71
72namespace {
73
74struct OncParams {
75  // |location_of_object| is a string to identify the object to be tested. It
76  // may be used as a filename or as a dictionary key.
77  OncParams(const std::string& location_of_object,
78            const OncValueSignature* onc_signature,
79            bool is_managed_onc,
80            ::onc::ONCSource onc_source = ::onc::ONC_SOURCE_NONE)
81      : location(location_of_object),
82        signature(onc_signature),
83        is_managed(is_managed_onc),
84        onc_source(onc_source) {
85  }
86
87  std::string location;
88  const OncValueSignature* signature;
89  bool is_managed;
90  ::onc::ONCSource onc_source;
91};
92
93::std::ostream& operator<<(::std::ostream& os, const OncParams& onc) {
94  return os << "(" << onc.location << ", " << onc.signature << ", "
95            << (onc.is_managed ? "managed" : "unmanaged") << ", "
96            << GetSourceAsString(onc.onc_source) << ")";
97}
98
99}  // namespace
100
101// Ensure that the constant |kEmptyUnencryptedConfiguration| describes a valid
102// ONC toplevel object.
103TEST_F(ONCValidatorTest, EmptyUnencryptedConfiguration) {
104  Validate(true, ReadDictionaryFromJson(kEmptyUnencryptedConfiguration),
105           &kToplevelConfigurationSignature, false, ::onc::ONC_SOURCE_NONE);
106  ExpectValid();
107}
108
109// This test case is about validating valid ONC objects without any errors. Both
110// the strict and the liberal validator accept the object.
111class ONCValidatorValidTest : public ONCValidatorTest,
112                              public ::testing::WithParamInterface<OncParams> {
113};
114
115TEST_P(ONCValidatorValidTest, StrictValidationValid) {
116  OncParams onc = GetParam();
117  Validate(true, test_utils::ReadTestDictionary(onc.location), onc.signature,
118           onc.is_managed, onc.onc_source);
119  ExpectValid();
120}
121
122TEST_P(ONCValidatorValidTest, LiberalValidationValid) {
123  OncParams onc = GetParam();
124  Validate(false, test_utils::ReadTestDictionary(onc.location), onc.signature,
125           onc.is_managed, onc.onc_source);
126  ExpectValid();
127}
128
129// The parameters are:
130// OncParams(string: Filename of a ONC file that is to be validated,
131//           OncValueSignature: signature of that ONC,
132//           bool: true if the ONC is managed).
133INSTANTIATE_TEST_CASE_P(
134    ONCValidatorValidTest,
135    ONCValidatorValidTest,
136    ::testing::Values(
137        OncParams("managed_toplevel1.onc",
138                  &kToplevelConfigurationSignature,
139                  true),
140        OncParams("managed_toplevel2.onc",
141                  &kToplevelConfigurationSignature,
142                  true),
143        OncParams("managed_toplevel_with_global_config.onc",
144                  &kToplevelConfigurationSignature,
145                  true),
146        // Check that at least one configuration is accepted for
147        // device policies.
148        OncParams("managed_toplevel_wifi_peap.onc",
149                  &kToplevelConfigurationSignature,
150                  true,
151                  ::onc::ONC_SOURCE_DEVICE_POLICY),
152        OncParams("managed_toplevel_l2tpipsec.onc",
153                  &kToplevelConfigurationSignature,
154                  true),
155        OncParams("toplevel_wifi_wpa_psk.onc",
156                  &kToplevelConfigurationSignature,
157                  false),
158        OncParams("toplevel_wifi_wep_proxy.onc",
159                  &kToplevelConfigurationSignature,
160                  false),
161        OncParams("toplevel_wifi_leap.onc",
162                  &kToplevelConfigurationSignature,
163                  false),
164        OncParams("toplevel_wifi_eap_clientcert_with_cert_pems.onc",
165                  &kToplevelConfigurationSignature,
166                  false),
167        OncParams("toplevel_wifi_remove.onc",
168                  &kToplevelConfigurationSignature,
169                  false),
170        OncParams("toplevel_wifi_open.onc",
171                  &kToplevelConfigurationSignature,
172                  false),
173        OncParams("toplevel_openvpn_clientcert_with_cert_pems.onc",
174                  &kToplevelConfigurationSignature,
175                  false),
176        OncParams("toplevel_empty.onc",
177                  &kToplevelConfigurationSignature,
178                  false),
179        OncParams("toplevel_only_global_config.onc",
180                  &kToplevelConfigurationSignature,
181                  true),
182        OncParams("encrypted.onc", &kToplevelConfigurationSignature, true),
183        OncParams("managed_vpn.onc", &kNetworkConfigurationSignature, true),
184        OncParams("ethernet.onc", &kNetworkConfigurationSignature, true),
185        OncParams("ethernet_with_eap.onc",
186                  &kNetworkConfigurationSignature,
187                  true),
188        OncParams("translation_of_shill_ethernet_with_ipconfig.onc",
189                  &kNetworkWithStateSignature,
190                  true),
191        OncParams("translation_of_shill_wifi_with_state.onc",
192                  &kNetworkWithStateSignature,
193                  false),
194        OncParams("valid_openvpn_with_cert_pems.onc",
195                  &kNetworkConfigurationSignature,
196                  false)));
197
198namespace {
199
200struct RepairParams {
201  // Both arguments are strings to identify the object that is expected as the
202  // validation result. They may either be used as filenames or as dictionary
203  // keys.
204  RepairParams(std::string strict_repaired,
205               std::string liberal_repaired)
206      : location_of_strict_repaired(strict_repaired),
207        location_of_liberal_repaired(liberal_repaired) {
208  }
209
210  std::string location_of_strict_repaired;
211  std::string location_of_liberal_repaired;
212};
213
214::std::ostream& operator<<(::std::ostream& os, const RepairParams& rp) {
215  return os << "(" << rp.location_of_strict_repaired << ", "
216            << rp.location_of_liberal_repaired << ")";
217}
218
219}  // namespace
220
221// This test case is about validating ONC objects that contain errors which can
222// be repaired (then the errors count as warnings). If a location of the
223// expected repaired object is given, then it is checked that the validator
224// (either strict or liberal) returns this repaired object and the result is
225// VALID_WITH_WARNINGS. If the location is the empty string, then it is expected
226// that the validator returns NULL and the result INVALID.
227class ONCValidatorTestRepairable
228    : public ONCValidatorTest,
229      public ::testing::WithParamInterface<std::pair<OncParams,
230                                                     RepairParams> > {
231 public:
232  // Load the common test data and return the dictionary at the field with
233  // name |name|.
234  scoped_ptr<base::DictionaryValue> GetDictionaryFromTestFile(
235      const std::string &name) {
236    scoped_ptr<const base::DictionaryValue> dict(
237        test_utils::ReadTestDictionary("invalid_settings_with_repairs.json"));
238    const base::DictionaryValue* onc_object = NULL;
239    CHECK(dict->GetDictionary(name, &onc_object));
240    return make_scoped_ptr(onc_object->DeepCopy());
241  }
242};
243
244TEST_P(ONCValidatorTestRepairable, StrictValidation) {
245  OncParams onc = GetParam().first;
246  Validate(true, GetDictionaryFromTestFile(onc.location), onc.signature,
247           onc.is_managed, onc.onc_source);
248  std::string location_of_repaired =
249      GetParam().second.location_of_strict_repaired;
250  if (location_of_repaired.empty())
251    ExpectInvalid();
252  else
253    ExpectRepairWithWarnings(*GetDictionaryFromTestFile(location_of_repaired));
254}
255
256TEST_P(ONCValidatorTestRepairable, LiberalValidation) {
257  OncParams onc = GetParam().first;
258  Validate(false, GetDictionaryFromTestFile(onc.location), onc.signature,
259           onc.is_managed, onc.onc_source);
260  std::string location_of_repaired =
261      GetParam().second.location_of_liberal_repaired;
262  if (location_of_repaired.empty())
263    ExpectInvalid();
264  else
265    ExpectRepairWithWarnings(*GetDictionaryFromTestFile(location_of_repaired));
266}
267
268// The parameters for all test case instantations below are:
269// OncParams(string: A fieldname in the dictionary from the file
270//                   "invalid_settings_with_repairs.json". That nested
271//                   dictionary will be tested.
272//           OncValueSignature: signature of that ONC,
273//           bool: true if the ONC is managed).
274// RepairParams(string: A fieldname in the dictionary from the file
275//                      "invalid_settings_with_repairs.json". That nested
276//                      dictionary is the expected result from strict
277//                      validation,
278//              string: A fieldname in the dictionary from the file
279//                      "invalid_settings_with_repairs.json". That nested
280//                      dictionary is the expected result from liberal
281//                      validation).
282
283// Strict validator returns INVALID. Liberal validator repairs.
284INSTANTIATE_TEST_CASE_P(
285    StrictInvalidLiberalRepair,
286    ONCValidatorTestRepairable,
287    ::testing::Values(
288        std::make_pair(OncParams("network-unknown-fieldname",
289                                 &kNetworkConfigurationSignature,
290                                 false),
291                       RepairParams("", "network-repaired")),
292        std::make_pair(OncParams("managed-network-unknown-fieldname",
293                                 &kNetworkConfigurationSignature,
294                                 true),
295                       RepairParams("", "managed-network-repaired")),
296        std::make_pair(OncParams("managed-network-unknown-recommended",
297                                 &kNetworkConfigurationSignature,
298                                 true),
299                       RepairParams("", "managed-network-repaired")),
300        std::make_pair(OncParams("managed-network-dict-recommended",
301                                 &kNetworkConfigurationSignature,
302                                 true),
303                       RepairParams("", "managed-network-repaired")),
304        std::make_pair(OncParams("network-missing-required",
305                                 &kNetworkConfigurationSignature,
306                                 false),
307                       RepairParams("", "network-missing-required")),
308        std::make_pair(OncParams("managed-network-missing-required",
309                                 &kNetworkConfigurationSignature,
310                                 true),
311                       RepairParams("", "managed-network-missing-required")),
312        // Ensure that state values from Shill aren't accepted as
313        // configuration.
314        std::make_pair(OncParams("network-state-field",
315                                 &kNetworkConfigurationSignature,
316                                 false),
317                       RepairParams("", "network-repaired")),
318        std::make_pair(OncParams("network-nested-state-field",
319                                 &kNetworkConfigurationSignature,
320                                 false),
321                       RepairParams("", "network-nested-state-field-repaired")),
322        std::make_pair(OncParams("network-with-ipconfigs",
323                                 &kNetworkConfigurationSignature,
324                                 false),
325                       RepairParams("", "network-repaired")),
326        std::make_pair(OncParams("openvpn-missing-verify-x509-name",
327                                 &kNetworkConfigurationSignature, false),
328                        RepairParams("", "openvpn-missing-verify-x509-name")),
329        std::make_pair(OncParams("ipsec-with-client-cert-missing-cacert",
330                                 &kIPsecSignature,
331                                 false),
332                       RepairParams("",
333                                    "ipsec-with-client-cert-missing-cacert")),
334        std::make_pair(OncParams("toplevel-with-repairable-networks",
335                                 &kToplevelConfigurationSignature,
336                                 false,
337                                 ::onc::ONC_SOURCE_DEVICE_POLICY),
338                       RepairParams("", "toplevel-with-repaired-networks"))));
339
340// Strict and liberal validator repair identically.
341INSTANTIATE_TEST_CASE_P(
342    StrictAndLiberalRepairIdentically,
343    ONCValidatorTestRepairable,
344    ::testing::Values(
345         std::make_pair(OncParams("toplevel-invalid-network",
346                                  &kToplevelConfigurationSignature,
347                                  false),
348                        RepairParams("toplevel-repaired",
349                                     "toplevel-repaired")),
350         std::make_pair(OncParams("duplicate-network-guid",
351                                  &kToplevelConfigurationSignature,
352                                  false),
353                        RepairParams("repaired-duplicate-network-guid",
354                                     "repaired-duplicate-network-guid")),
355         std::make_pair(OncParams("duplicate-cert-guid",
356                                  &kToplevelConfigurationSignature,
357                                  false),
358                        RepairParams("repaired-duplicate-cert-guid",
359                                     "repaired-duplicate-cert-guid")),
360         std::make_pair(OncParams("toplevel-invalid-network",
361                                  &kToplevelConfigurationSignature,
362                                  true),
363                        RepairParams("toplevel-repaired",
364                                     "toplevel-repaired")),
365         // Ignore recommended arrays in unmanaged ONC.
366         std::make_pair(OncParams("network-with-illegal-recommended",
367                                  &kNetworkConfigurationSignature,
368                                  false),
369                        RepairParams("network-repaired", "network-repaired")),
370         std::make_pair(OncParams("toplevel-with-vpn",
371                                  &kToplevelConfigurationSignature,
372                                  false,
373                                  ::onc::ONC_SOURCE_DEVICE_POLICY),
374                        RepairParams("toplevel-empty", "toplevel-empty")),
375         std::make_pair(OncParams("toplevel-with-server-and-ca-cert",
376                                  &kToplevelConfigurationSignature,
377                                  true,
378                                  ::onc::ONC_SOURCE_DEVICE_POLICY),
379                        RepairParams("toplevel-server-and-ca-cert-dropped",
380                                     "toplevel-server-and-ca-cert-dropped"))));
381
382// Strict and liberal validator both repair, but with different results.
383INSTANTIATE_TEST_CASE_P(
384    StrictAndLiberalRepairDifferently,
385    ONCValidatorTestRepairable,
386    ::testing::Values(
387         std::make_pair(OncParams("toplevel-with-nested-warning",
388                                  &kToplevelConfigurationSignature,
389                                  false),
390                        RepairParams("toplevel-empty", "toplevel-repaired"))));
391
392// Strict and liberal validator return both INVALID.
393INSTANTIATE_TEST_CASE_P(
394    StrictAndLiberalInvalid,
395    ONCValidatorTestRepairable,
396    ::testing::Values(
397         std::make_pair(OncParams("network-unknown-value",
398                                  &kNetworkConfigurationSignature, false),
399                        RepairParams("", "")),
400         std::make_pair(OncParams("managed-network-unknown-value",
401                                  &kNetworkConfigurationSignature, true),
402                        RepairParams("", "")),
403         std::make_pair(OncParams("network-value-out-of-range",
404                                  &kNetworkConfigurationSignature, false),
405                        RepairParams("", "")),
406         std::make_pair(OncParams("ipsec-with-psk-and-cacert",
407                                  &kIPsecSignature, false),
408                        RepairParams("", "")),
409         std::make_pair(OncParams("ipsec-with-empty-cacertrefs",
410                                  &kIPsecSignature, false),
411                        RepairParams("", "")),
412         std::make_pair(OncParams("ipsec-with-servercaref-and-servercarefs",
413                                  &kIPsecSignature, false),
414                        RepairParams("", "")),
415         std::make_pair(OncParams("openvpn-with-servercaref-and-servercarefs",
416                                  &kOpenVPNSignature, false),
417                        RepairParams("", "")),
418         std::make_pair(OncParams("eap-with-servercaref-and-servercarefs",
419                                  &kEAPSignature, false),
420                        RepairParams("", "")),
421         std::make_pair(OncParams("managed-network-value-out-of-range",
422                                  &kNetworkConfigurationSignature, true),
423                        RepairParams("", "")),
424         std::make_pair(OncParams("network-wrong-type",
425                                  &kNetworkConfigurationSignature, false),
426                        RepairParams("", "")),
427         std::make_pair(OncParams("managed-network-wrong-type",
428                                  &kNetworkConfigurationSignature, true),
429                        RepairParams("", "")),
430         std::make_pair(OncParams("network-with-client-cert-pattern",
431                                  &kNetworkConfigurationSignature, true,
432                                  ::onc::ONC_SOURCE_DEVICE_POLICY),
433                        RepairParams("", "")),
434         std::make_pair(OncParams("openvpn-invalid-verify-x509-type",
435                                  &kNetworkConfigurationSignature, false),
436                        RepairParams("", ""))
437         ));
438
439}  // namespace onc
440}  // namespace chromeos
441