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_constants.h" 14 #include "chromeos/network/onc/onc_signature.h" 15 #include "chromeos/network/onc/onc_test_utils.h" 16 #include "chromeos/network/onc/onc_utils.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 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 ONCSource onc_source = 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 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_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(OncParams("managed_toplevel1.onc", 137 &kToplevelConfigurationSignature, 138 true), 139 OncParams("managed_toplevel2.onc", 140 &kToplevelConfigurationSignature, 141 true), 142 // Check that at least one configuration is accepted for 143 // device policies. 144 OncParams("managed_toplevel_wifi_peap.onc", 145 &kToplevelConfigurationSignature, 146 true, 147 ONC_SOURCE_DEVICE_POLICY), 148 OncParams("toplevel_wifi_wpa_psk.onc", 149 &kToplevelConfigurationSignature, 150 false), 151 OncParams("encrypted.onc", 152 &kToplevelConfigurationSignature, 153 true), 154 OncParams("managed_vpn.onc", 155 &kNetworkConfigurationSignature, 156 true), 157 OncParams("managed_ethernet.onc", 158 &kNetworkConfigurationSignature, 159 true), 160 OncParams("translation_of_shill_wifi_with_state.onc", 161 &kNetworkWithStateSignature, 162 false))); 163 164 namespace { 165 166 struct RepairParams { 167 // Both arguments are strings to identify the object that is expected as the 168 // validation result. They may either be used as filenames or as dictionary 169 // keys. 170 RepairParams(std::string strict_repaired, 171 std::string liberal_repaired) 172 : location_of_strict_repaired(strict_repaired), 173 location_of_liberal_repaired(liberal_repaired) { 174 } 175 176 std::string location_of_strict_repaired; 177 std::string location_of_liberal_repaired; 178 }; 179 180 ::std::ostream& operator<<(::std::ostream& os, const RepairParams& rp) { 181 return os << "(" << rp.location_of_strict_repaired << ", " 182 << rp.location_of_liberal_repaired << ")"; 183 } 184 185 } // namespace 186 187 // This test case is about validating ONC objects that contain errors which can 188 // be repaired (then the errors count as warnings). If a location of the 189 // expected repaired object is given, then it is checked that the validator 190 // (either strict or liberal) returns this repaired object and the result is 191 // VALID_WITH_WARNINGS. If the location is the empty string, then it is expected 192 // that the validator returns NULL and the result INVALID. 193 class ONCValidatorTestRepairable 194 : public ONCValidatorTest, 195 public ::testing::WithParamInterface<std::pair<OncParams, 196 RepairParams> > { 197 public: 198 // Load the common test data and return the dictionary at the field with 199 // name |name|. 200 scoped_ptr<base::DictionaryValue> GetDictionaryFromTestFile( 201 const std::string &name) { 202 scoped_ptr<const base::DictionaryValue> dict( 203 test_utils::ReadTestDictionary("invalid_settings_with_repairs.json")); 204 const base::DictionaryValue* onc_object = NULL; 205 CHECK(dict->GetDictionary(name, &onc_object)); 206 return make_scoped_ptr(onc_object->DeepCopy()); 207 } 208 }; 209 210 TEST_P(ONCValidatorTestRepairable, StrictValidation) { 211 OncParams onc = GetParam().first; 212 Validate(true, GetDictionaryFromTestFile(onc.location), onc.signature, 213 onc.is_managed, onc.onc_source); 214 std::string location_of_repaired = 215 GetParam().second.location_of_strict_repaired; 216 if (location_of_repaired.empty()) 217 ExpectInvalid(); 218 else 219 ExpectRepairWithWarnings(*GetDictionaryFromTestFile(location_of_repaired)); 220 } 221 222 TEST_P(ONCValidatorTestRepairable, LiberalValidation) { 223 OncParams onc = GetParam().first; 224 Validate(false, GetDictionaryFromTestFile(onc.location), onc.signature, 225 onc.is_managed, onc.onc_source); 226 std::string location_of_repaired = 227 GetParam().second.location_of_liberal_repaired; 228 if (location_of_repaired.empty()) 229 ExpectInvalid(); 230 else 231 ExpectRepairWithWarnings(*GetDictionaryFromTestFile(location_of_repaired)); 232 } 233 234 // The parameters for all test case instantations below are: 235 // OncParams(string: A fieldname in the dictionary from the file 236 // "invalid_settings_with_repairs.json". That nested 237 // dictionary will be tested. 238 // OncValueSignature: signature of that ONC, 239 // bool: true if the ONC is managed). 240 // RepairParams(string: A fieldname in the dictionary from the file 241 // "invalid_settings_with_repairs.json". That nested 242 // dictionary is the expected result from strict 243 // validation, 244 // string: A fieldname in the dictionary from the file 245 // "invalid_settings_with_repairs.json". That nested 246 // dictionary is the expected result from liberal 247 // validation). 248 249 // Strict validator returns INVALID. Liberal validator repairs. 250 INSTANTIATE_TEST_CASE_P( 251 StrictInvalidLiberalRepair, 252 ONCValidatorTestRepairable, 253 ::testing::Values( 254 std::make_pair(OncParams("network-unknown-fieldname", 255 &kNetworkConfigurationSignature, 256 false), 257 RepairParams("", "network-repaired")), 258 std::make_pair(OncParams("managed-network-unknown-fieldname", 259 &kNetworkConfigurationSignature, 260 true), 261 RepairParams("", "managed-network-repaired")), 262 std::make_pair(OncParams("managed-network-unknown-recommended", 263 &kNetworkConfigurationSignature, 264 true), 265 RepairParams("", "managed-network-repaired")), 266 std::make_pair(OncParams("managed-network-dict-recommended", 267 &kNetworkConfigurationSignature, 268 true), 269 RepairParams("", "managed-network-repaired")), 270 std::make_pair(OncParams("network-missing-required", 271 &kNetworkConfigurationSignature, 272 false), 273 RepairParams("", "network-missing-required")), 274 std::make_pair(OncParams("managed-network-missing-required", 275 &kNetworkConfigurationSignature, 276 true), 277 RepairParams("", "managed-network-missing-required")), 278 // Ensure that state values from Shill aren't accepted as 279 // configuration. 280 std::make_pair(OncParams("network-state-field", 281 &kNetworkConfigurationSignature, 282 false), 283 RepairParams("", "network-repaired")), 284 std::make_pair(OncParams("network-nested-state-field", 285 &kNetworkConfigurationSignature, 286 false), 287 RepairParams("", 288 "network-nested-state-field-repaired")), 289 std::make_pair(OncParams("toplevel-with-repairable-networks", 290 &kToplevelConfigurationSignature, 291 false, 292 ONC_SOURCE_DEVICE_POLICY), 293 RepairParams("", "toplevel-with-repaired-networks")))); 294 295 // Strict and liberal validator repair identically. 296 INSTANTIATE_TEST_CASE_P( 297 StrictAndLiberalRepairIdentically, 298 ONCValidatorTestRepairable, 299 ::testing::Values( 300 std::make_pair(OncParams("toplevel-invalid-network", 301 &kToplevelConfigurationSignature, 302 false), 303 RepairParams("toplevel-repaired", 304 "toplevel-repaired")), 305 std::make_pair(OncParams("toplevel-invalid-network", 306 &kToplevelConfigurationSignature, 307 true), 308 RepairParams("toplevel-repaired", 309 "toplevel-repaired")), 310 // Ignore recommended arrays in unmanaged ONC. 311 std::make_pair(OncParams("network-with-illegal-recommended", 312 &kNetworkConfigurationSignature, 313 false), 314 RepairParams("network-repaired", "network-repaired")), 315 std::make_pair(OncParams("toplevel-with-vpn", 316 &kToplevelConfigurationSignature, 317 false, 318 ONC_SOURCE_DEVICE_POLICY), 319 RepairParams("toplevel-empty", "toplevel-empty")), 320 std::make_pair(OncParams("toplevel-with-server-and-ca-cert", 321 &kToplevelConfigurationSignature, 322 true, 323 ONC_SOURCE_DEVICE_POLICY), 324 RepairParams("toplevel-server-and-ca-cert-dropped", 325 "toplevel-server-and-ca-cert-dropped")))); 326 327 // Strict and liberal validator both repair, but with different results. 328 INSTANTIATE_TEST_CASE_P( 329 StrictAndLiberalRepairDifferently, 330 ONCValidatorTestRepairable, 331 ::testing::Values( 332 std::make_pair(OncParams("toplevel-with-nested-warning", 333 &kToplevelConfigurationSignature, 334 false), 335 RepairParams("toplevel-empty", "toplevel-repaired")))); 336 337 // Strict and liberal validator return both INVALID. 338 INSTANTIATE_TEST_CASE_P( 339 StrictAndLiberalInvalid, 340 ONCValidatorTestRepairable, 341 ::testing::Values( 342 std::make_pair(OncParams("network-unknown-value", 343 &kNetworkConfigurationSignature, false), 344 RepairParams("", "")), 345 std::make_pair(OncParams("managed-network-unknown-value", 346 &kNetworkConfigurationSignature, true), 347 RepairParams("", "")), 348 std::make_pair(OncParams("network-value-out-of-range", 349 &kNetworkConfigurationSignature, false), 350 RepairParams("", "")), 351 std::make_pair(OncParams("managed-network-value-out-of-range", 352 &kNetworkConfigurationSignature, true), 353 RepairParams("", "")), 354 std::make_pair(OncParams("network-wrong-type", 355 &kNetworkConfigurationSignature, false), 356 RepairParams("", "")), 357 std::make_pair(OncParams("managed-network-wrong-type", 358 &kNetworkConfigurationSignature, true), 359 RepairParams("", "")), 360 std::make_pair(OncParams("network-with-client-cert-pattern", 361 &kNetworkConfigurationSignature, true, 362 ONC_SOURCE_DEVICE_POLICY), 363 RepairParams("", "")))); 364 365 } // namespace onc 366 } // namespace chromeos 367