Home | History | Annotate | Download | only in onc
      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 
     19 namespace chromeos {
     20 namespace onc {
     21 
     22 class 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 
     72 namespace {
     73 
     74 struct 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.
    103 TEST_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.
    111 class ONCValidatorValidTest : public ONCValidatorTest,
    112                               public ::testing::WithParamInterface<OncParams> {
    113 };
    114 
    115 TEST_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 
    122 TEST_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).
    133 INSTANTIATE_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 
    198 namespace {
    199 
    200 struct 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.
    227 class 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 
    244 TEST_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 
    256 TEST_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.
    284 INSTANTIATE_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.
    341 INSTANTIATE_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.
    383 INSTANTIATE_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.
    393 INSTANTIATE_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