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 "chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.h" 6 7 #include "base/callback.h" 8 #include "base/files/file_path.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/run_loop.h" 12 #include "base/values.h" 13 #include "chrome/browser/chromeos/cros/mock_network_library.h" 14 #include "chrome/browser/policy/external_data_fetcher.h" 15 #include "chrome/browser/policy/mock_configuration_policy_provider.h" 16 #include "chrome/browser/policy/policy_map.h" 17 #include "chrome/browser/policy/policy_service_impl.h" 18 #include "chromeos/network/onc/mock_certificate_importer.h" 19 #include "chromeos/network/onc/onc_constants.h" 20 #include "chromeos/network/onc/onc_test_utils.h" 21 #include "chromeos/network/onc/onc_utils.h" 22 #include "content/public/test/test_browser_thread.h" 23 #include "content/public/test/test_utils.h" 24 #include "net/base/test_data_directory.h" 25 #include "net/cert/cert_trust_anchor_provider.h" 26 #include "net/cert/x509_certificate.h" 27 #include "net/test/cert_test_util.h" 28 #include "policy/policy_constants.h" 29 #include "testing/gmock/include/gmock/gmock.h" 30 #include "testing/gtest/include/gtest/gtest.h" 31 32 using testing::AnyNumber; 33 using testing::Mock; 34 using testing::Ne; 35 using testing::Return; 36 using testing::StrictMock; 37 using testing::_; 38 39 namespace onc = ::chromeos::onc; 40 41 namespace policy { 42 43 namespace { 44 45 const char kFakeONC[] = 46 "{ \"NetworkConfigurations\": [" 47 " { \"GUID\": \"{485d6076-dd44-6b6d-69787465725f5040}\"," 48 " \"Type\": \"WiFi\"," 49 " \"Name\": \"My WiFi Network\"," 50 " \"WiFi\": {" 51 " \"SSID\": \"ssid-none\"," 52 " \"Security\": \"None\" }" 53 " }" 54 " ]," 55 " \"Certificates\": [" 56 " { \"GUID\": \"{f998f760-272b-6939-4c2beffe428697ac}\"," 57 " \"PKCS12\": \"abc\"," 58 " \"Type\": \"Client\" }" 59 " ]," 60 " \"Type\": \"UnencryptedConfiguration\"" 61 "}"; 62 63 std::string ValueToString(const base::Value* value) { 64 std::stringstream str; 65 str << *value; 66 return str.str(); 67 } 68 69 // Matcher to match base::Value. 70 MATCHER_P(IsEqualTo, 71 value, 72 std::string(negation ? "isn't" : "is") + " equal to " + 73 ValueToString(value)) { 74 return value->Equals(&arg); 75 } 76 77 ACTION_P(SetCertificateList, list) { 78 *arg2 = list; 79 return true; 80 } 81 82 ACTION_P(SetImportedCerts, map) { 83 *arg3 = map; 84 return true; 85 } 86 87 } // namespace 88 89 // Tests of NetworkConfigurationUpdaterImplCros 90 class NetworkConfigurationUpdaterTest : public testing::Test { 91 protected: 92 NetworkConfigurationUpdaterTest() 93 : ui_thread_(content::BrowserThread::UI, &loop_), 94 io_thread_(content::BrowserThread::IO, &loop_) {} 95 96 virtual void SetUp() OVERRIDE { 97 EXPECT_CALL(provider_, IsInitializationComplete(_)) 98 .WillRepeatedly(Return(true)); 99 provider_.Init(); 100 PolicyServiceImpl::Providers providers; 101 providers.push_back(&provider_); 102 policy_service_.reset(new PolicyServiceImpl(providers)); 103 104 empty_network_configs_.reset(new base::ListValue); 105 empty_certificates_.reset(new base::ListValue); 106 107 scoped_ptr<base::DictionaryValue> fake_toplevel_onc = 108 onc::ReadDictionaryFromJson(kFakeONC); 109 110 scoped_ptr<base::Value> network_configs_value; 111 base::ListValue* network_configs = NULL; 112 fake_toplevel_onc->RemoveWithoutPathExpansion( 113 onc::toplevel_config::kNetworkConfigurations, 114 &network_configs_value); 115 network_configs_value.release()->GetAsList(&network_configs); 116 fake_network_configs_.reset(network_configs); 117 118 scoped_ptr<base::Value> certs_value; 119 base::ListValue* certs = NULL; 120 fake_toplevel_onc->RemoveWithoutPathExpansion( 121 onc::toplevel_config::kCertificates, 122 &certs_value); 123 certs_value.release()->GetAsList(&certs); 124 fake_certificates_.reset(certs); 125 } 126 127 virtual void TearDown() OVERRIDE { 128 provider_.Shutdown(); 129 content::RunAllPendingInMessageLoop(content::BrowserThread::IO); 130 } 131 132 void UpdateProviderPolicy(const PolicyMap& policy) { 133 provider_.UpdateChromePolicy(policy); 134 base::RunLoop loop; 135 loop.RunUntilIdle(); 136 } 137 138 // Maps configuration policy name to corresponding ONC source. 139 static onc::ONCSource NameToONCSource( 140 const std::string& name) { 141 if (name == key::kDeviceOpenNetworkConfiguration) 142 return onc::ONC_SOURCE_DEVICE_POLICY; 143 if (name == key::kOpenNetworkConfiguration) 144 return onc::ONC_SOURCE_USER_POLICY; 145 return onc::ONC_SOURCE_NONE; 146 } 147 148 scoped_ptr<base::ListValue> empty_network_configs_; 149 scoped_ptr<base::ListValue> empty_certificates_; 150 scoped_ptr<base::ListValue> fake_network_configs_; 151 scoped_ptr<base::ListValue> fake_certificates_; 152 StrictMock<chromeos::MockNetworkLibrary> network_library_; 153 StrictMock<MockConfigurationPolicyProvider> provider_; 154 scoped_ptr<PolicyServiceImpl> policy_service_; 155 base::MessageLoop loop_; 156 content::TestBrowserThread ui_thread_; 157 content::TestBrowserThread io_thread_; 158 }; 159 160 TEST_F(NetworkConfigurationUpdaterTest, PolicyIsValidatedAndRepaired) { 161 std::string onc_policy = 162 onc::test_utils::ReadTestData("toplevel_partially_invalid.onc"); 163 164 scoped_ptr<base::DictionaryValue> onc_repaired = 165 onc::test_utils::ReadTestDictionary( 166 "repaired_toplevel_partially_invalid.onc"); 167 168 base::ListValue* network_configs_repaired = NULL; 169 onc_repaired->GetListWithoutPathExpansion( 170 onc::toplevel_config::kNetworkConfigurations, 171 &network_configs_repaired); 172 ASSERT_TRUE(network_configs_repaired); 173 174 PolicyMap policy; 175 policy.Set(key::kOpenNetworkConfiguration, POLICY_LEVEL_MANDATORY, 176 POLICY_SCOPE_USER, Value::CreateStringValue(onc_policy), NULL); 177 UpdateProviderPolicy(policy); 178 179 EXPECT_CALL(network_library_, AddNetworkProfileObserver(_)); 180 181 // Ignore the device policy update. 182 EXPECT_CALL(network_library_, LoadOncNetworks(_, _)); 183 StrictMock<chromeos::onc::MockCertificateImporter>* certificate_importer = 184 new StrictMock<chromeos::onc::MockCertificateImporter>(); 185 EXPECT_CALL(*certificate_importer, ImportCertificates(_, _, _)); 186 187 NetworkConfigurationUpdaterImplCros updater( 188 policy_service_.get(), 189 &network_library_, 190 make_scoped_ptr<chromeos::onc::CertificateImporter>( 191 certificate_importer)); 192 Mock::VerifyAndClearExpectations(&network_library_); 193 Mock::VerifyAndClearExpectations(&certificate_importer); 194 195 // After the user policy is initialized, we always push both policies to the 196 // NetworkLibrary. Ignore the device policy. 197 EXPECT_CALL(network_library_, LoadOncNetworks( 198 _, onc::ONC_SOURCE_DEVICE_POLICY)); 199 EXPECT_CALL(network_library_, LoadOncNetworks( 200 IsEqualTo(network_configs_repaired), 201 onc::ONC_SOURCE_USER_POLICY)); 202 EXPECT_CALL(*certificate_importer, 203 ImportCertificates(_, chromeos::onc::ONC_SOURCE_DEVICE_POLICY, 204 _)); 205 EXPECT_CALL(*certificate_importer, 206 ImportCertificates(_, chromeos::onc::ONC_SOURCE_USER_POLICY, 207 _)); 208 209 EXPECT_CALL(network_library_, RemoveNetworkProfileObserver(_)); 210 211 updater.SetUserPolicyService(false, "hash", policy_service_.get()); 212 updater.UnsetUserPolicyService(); 213 } 214 215 class NetworkConfigurationUpdaterTestWithParam 216 : public NetworkConfigurationUpdaterTest, 217 public testing::WithParamInterface<const char*> { 218 }; 219 220 TEST_P(NetworkConfigurationUpdaterTestWithParam, InitialUpdates) { 221 PolicyMap policy; 222 policy.Set(GetParam(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, 223 Value::CreateStringValue(kFakeONC), NULL); 224 UpdateProviderPolicy(policy); 225 226 EXPECT_CALL(network_library_, AddNetworkProfileObserver(_)); 227 228 // Initially, only the device policy is applied. The user policy is only 229 // applied after the user profile was initialized. 230 base::ListValue* device_networks; 231 base::ListValue* device_certs; 232 base::ListValue* user_networks; 233 base::ListValue* user_certs; 234 if (GetParam() == key::kDeviceOpenNetworkConfiguration) { 235 device_networks = fake_network_configs_.get(); 236 device_certs = fake_certificates_.get(); 237 user_networks = empty_network_configs_.get(); 238 user_certs = empty_certificates_.get(); 239 } else { 240 device_networks = empty_network_configs_.get(); 241 device_certs = empty_certificates_.get(); 242 user_networks = fake_network_configs_.get(); 243 user_certs = fake_certificates_.get(); 244 } 245 246 EXPECT_CALL(network_library_, LoadOncNetworks( 247 IsEqualTo(device_networks), onc::ONC_SOURCE_DEVICE_POLICY)); 248 StrictMock<chromeos::onc::MockCertificateImporter>* certificate_importer = 249 new StrictMock<chromeos::onc::MockCertificateImporter>(); 250 EXPECT_CALL(*certificate_importer, ImportCertificates( 251 IsEqualTo(device_certs), onc::ONC_SOURCE_DEVICE_POLICY, _)); 252 253 NetworkConfigurationUpdaterImplCros updater( 254 policy_service_.get(), 255 &network_library_, 256 make_scoped_ptr<chromeos::onc::CertificateImporter>( 257 certificate_importer)); 258 Mock::VerifyAndClearExpectations(&network_library_); 259 Mock::VerifyAndClearExpectations(&certificate_importer); 260 261 // After the user policy is initialized, we always push both policies to the 262 // NetworkLibrary. 263 EXPECT_CALL(network_library_, LoadOncNetworks( 264 IsEqualTo(device_networks), onc::ONC_SOURCE_DEVICE_POLICY)); 265 EXPECT_CALL(*certificate_importer, ImportCertificates( 266 IsEqualTo(device_certs), onc::ONC_SOURCE_DEVICE_POLICY, _)); 267 268 EXPECT_CALL(network_library_, LoadOncNetworks( 269 IsEqualTo(user_networks), onc::ONC_SOURCE_USER_POLICY)); 270 EXPECT_CALL(*certificate_importer, ImportCertificates( 271 IsEqualTo(user_certs), onc::ONC_SOURCE_USER_POLICY, _)); 272 273 EXPECT_CALL(network_library_, RemoveNetworkProfileObserver(_)); 274 275 // We just need an initialized PolicyService, so we can reuse 276 // |policy_service_|. 277 updater.SetUserPolicyService(false, "hash", policy_service_.get()); 278 updater.UnsetUserPolicyService(); 279 } 280 281 TEST_P(NetworkConfigurationUpdaterTestWithParam, 282 AllowTrustedCertificatesFromPolicy) { 283 EXPECT_CALL(network_library_, AddNetworkProfileObserver(_)); 284 285 const net::CertificateList empty_cert_list; 286 287 const net::CertificateList cert_list = 288 net::CreateCertificateListFromFile(net::GetTestCertsDirectory(), 289 "ok_cert.pem", 290 net::X509Certificate::FORMAT_AUTO); 291 ASSERT_EQ(1u, cert_list.size()); 292 293 EXPECT_CALL(network_library_, LoadOncNetworks(_, _)).Times(AnyNumber()); 294 StrictMock<chromeos::onc::MockCertificateImporter>* certificate_importer = 295 new StrictMock<chromeos::onc::MockCertificateImporter>(); 296 EXPECT_CALL(*certificate_importer, ImportCertificates(_, _, _)) 297 .WillRepeatedly(SetCertificateList(empty_cert_list)); 298 NetworkConfigurationUpdaterImplCros updater( 299 policy_service_.get(), 300 &network_library_, 301 make_scoped_ptr<chromeos::onc::CertificateImporter>( 302 certificate_importer)); 303 net::CertTrustAnchorProvider* trust_provider = 304 updater.GetCertTrustAnchorProvider(); 305 ASSERT_TRUE(trust_provider); 306 // The initial list of trust anchors is empty. 307 content::RunAllPendingInMessageLoop(content::BrowserThread::IO); 308 EXPECT_TRUE(trust_provider->GetAdditionalTrustAnchors().empty()); 309 310 // Initially, certificates imported from policy don't have trust flags. 311 updater.SetUserPolicyService(false, "hash", policy_service_.get()); 312 content::RunAllPendingInMessageLoop(content::BrowserThread::IO); 313 Mock::VerifyAndClearExpectations(&network_library_); 314 Mock::VerifyAndClearExpectations(&certificate_importer); 315 EXPECT_TRUE(trust_provider->GetAdditionalTrustAnchors().empty()); 316 317 // Certificates with the "Web" trust flag set should be forwarded to the 318 // trust provider. 319 EXPECT_CALL(network_library_, LoadOncNetworks(_, _)); 320 EXPECT_CALL(*certificate_importer, ImportCertificates(_, _, _)) 321 .WillRepeatedly(SetCertificateList(empty_cert_list)); 322 onc::ONCSource current_source = NameToONCSource(GetParam()); 323 EXPECT_CALL(network_library_, LoadOncNetworks(_, current_source)); 324 EXPECT_CALL(*certificate_importer, ImportCertificates(_, current_source, _)) 325 .WillRepeatedly(SetCertificateList(cert_list)); 326 // Trigger a new policy load, and spin the IO message loop to pass the 327 // certificates to the |trust_provider| on the IO thread. 328 updater.SetUserPolicyService(true, "hash", policy_service_.get()); 329 base::RunLoop loop; 330 loop.RunUntilIdle(); 331 Mock::VerifyAndClearExpectations(&network_library_); 332 Mock::VerifyAndClearExpectations(&certificate_importer); 333 334 // Certificates are only provided as trust anchors if they come from user 335 // policy. 336 size_t expected_certs = 0u; 337 if (GetParam() == key::kOpenNetworkConfiguration) 338 expected_certs = 1u; 339 EXPECT_EQ(expected_certs, 340 trust_provider->GetAdditionalTrustAnchors().size()); 341 342 EXPECT_CALL(network_library_, RemoveNetworkProfileObserver(_)); 343 updater.UnsetUserPolicyService(); 344 } 345 346 TEST_P(NetworkConfigurationUpdaterTestWithParam, PolicyChange) { 347 EXPECT_CALL(network_library_, AddNetworkProfileObserver(_)); 348 349 // Ignore the initial updates. 350 EXPECT_CALL(network_library_, LoadOncNetworks(_, _)) 351 .Times(AnyNumber()); 352 StrictMock<chromeos::onc::MockCertificateImporter>* certificate_importer = 353 new StrictMock<chromeos::onc::MockCertificateImporter>(); 354 EXPECT_CALL(*certificate_importer, ImportCertificates(_, _, _)) 355 .Times(AnyNumber()); 356 NetworkConfigurationUpdaterImplCros updater( 357 policy_service_.get(), 358 &network_library_, 359 make_scoped_ptr<chromeos::onc::CertificateImporter>( 360 certificate_importer)); 361 updater.SetUserPolicyService(false, "hash", policy_service_.get()); 362 Mock::VerifyAndClearExpectations(&network_library_); 363 Mock::VerifyAndClearExpectations(&certificate_importer); 364 365 // We should update if policy changes. 366 EXPECT_CALL(network_library_, LoadOncNetworks( 367 IsEqualTo(fake_network_configs_.get()), NameToONCSource(GetParam()))); 368 EXPECT_CALL(*certificate_importer, ImportCertificates( 369 IsEqualTo(fake_certificates_.get()), NameToONCSource(GetParam()), _)); 370 371 // In the current implementation, we always apply both policies. 372 EXPECT_CALL(network_library_, LoadOncNetworks( 373 IsEqualTo(empty_network_configs_.get()), 374 Ne(NameToONCSource(GetParam())))); 375 EXPECT_CALL(*certificate_importer, ImportCertificates( 376 IsEqualTo(empty_certificates_.get()), 377 Ne(NameToONCSource(GetParam())), 378 _)); 379 380 PolicyMap policy; 381 policy.Set(GetParam(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, 382 Value::CreateStringValue(kFakeONC), NULL); 383 UpdateProviderPolicy(policy); 384 Mock::VerifyAndClearExpectations(&network_library_); 385 Mock::VerifyAndClearExpectations(&certificate_importer); 386 387 // Another update is expected if the policy goes away. In the current 388 // implementation, we always apply both policies. 389 EXPECT_CALL(network_library_, LoadOncNetworks( 390 IsEqualTo(empty_network_configs_.get()), 391 onc::ONC_SOURCE_DEVICE_POLICY)); 392 EXPECT_CALL(*certificate_importer, ImportCertificates( 393 IsEqualTo(empty_certificates_.get()), 394 onc::ONC_SOURCE_DEVICE_POLICY, 395 _)); 396 397 EXPECT_CALL(network_library_, LoadOncNetworks( 398 IsEqualTo(empty_network_configs_.get()), 399 onc::ONC_SOURCE_USER_POLICY)); 400 EXPECT_CALL(*certificate_importer, ImportCertificates( 401 IsEqualTo(empty_certificates_.get()), 402 onc::ONC_SOURCE_USER_POLICY, 403 _)); 404 405 EXPECT_CALL(network_library_, RemoveNetworkProfileObserver(_)); 406 407 policy.Erase(GetParam()); 408 UpdateProviderPolicy(policy); 409 updater.UnsetUserPolicyService(); 410 } 411 412 INSTANTIATE_TEST_CASE_P( 413 NetworkConfigurationUpdaterTestWithParamInstance, 414 NetworkConfigurationUpdaterTestWithParam, 415 testing::Values(key::kDeviceOpenNetworkConfiguration, 416 key::kOpenNetworkConfiguration)); 417 418 } // namespace policy 419