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 <pk11pub.h> 6 7 #include <map> 8 #include <string> 9 #include <vector> 10 11 #include "base/at_exit.h" 12 #include "base/callback.h" 13 #include "base/files/scoped_temp_dir.h" 14 #include "base/json/json_reader.h" 15 #include "base/lazy_instance.h" 16 #include "base/path_service.h" 17 #include "chrome/browser/chromeos/cros/network_library.h" 18 #include "chrome/browser/chromeos/cros/network_library_impl_stub.h" 19 #include "chrome/browser/chromeos/enrollment_dialog_view.h" 20 #include "chrome/browser/chromeos/login/mock_user_manager.h" 21 #include "chrome/browser/chromeos/login/user_manager.h" 22 #include "chrome/browser/google_apis/test_util.h" 23 #include "chrome/common/chrome_paths.h" 24 #include "chromeos/network/onc/onc_certificate_importer_impl.h" 25 #include "chromeos/network/onc/onc_constants.h" 26 #include "chromeos/network/onc/onc_test_utils.h" 27 #include "chromeos/network/onc/onc_utils.h" 28 #include "crypto/nss_util.h" 29 #include "net/base/crypto_module.h" 30 #include "testing/gmock/include/gmock/gmock.h" 31 #include "testing/gtest/include/gtest/gtest.h" 32 33 using ::testing::AnyNumber; 34 using ::testing::Return; 35 36 namespace chromeos { 37 38 namespace { 39 40 // Have to do a stub here because MOCK can't handle closure arguments. 41 class StubEnrollmentDelegate : public EnrollmentDelegate { 42 public: 43 explicit StubEnrollmentDelegate() 44 : did_enroll(false), 45 correct_args(false) {} 46 47 virtual bool Enroll(const std::vector<std::string>& uri_list, 48 const base::Closure& closure) OVERRIDE { 49 std::vector<std::string> expected_uri_list; 50 expected_uri_list.push_back("http://youtu.be/dQw4w9WgXcQ"); 51 expected_uri_list.push_back("chrome-extension://abc/keygen-cert.html"); 52 if (uri_list == expected_uri_list) 53 correct_args = true; 54 55 did_enroll = true; 56 closure.Run(); 57 return true; 58 } 59 60 bool did_enroll; 61 bool correct_args; 62 }; 63 64 void WifiNetworkConnectCallback(NetworkLibrary* cros, WifiNetwork* wifi) { 65 cros->ConnectToWifiNetwork(wifi, false); 66 } 67 68 void VirtualNetworkConnectCallback(NetworkLibrary* cros, VirtualNetwork* vpn) { 69 cros->ConnectToVirtualNetwork(vpn); 70 } 71 72 } // namespace 73 74 TEST(NetworkLibraryTest, DecodeNonAsciiSSID) { 75 // Sets network name. 76 { 77 std::string wifi_setname = "SSID TEST"; 78 std::string wifi_setname_result = "SSID TEST"; 79 WifiNetwork* wifi = new WifiNetwork("fw"); 80 wifi->SetName(wifi_setname); 81 EXPECT_EQ(wifi->name(), wifi_setname_result); 82 delete wifi; 83 } 84 85 // Truncates invalid UTF-8 86 { 87 std::string wifi_setname2 = "SSID TEST \x01\xff!"; 88 std::string wifi_setname2_result = "SSID TEST \xEF\xBF\xBD\xEF\xBF\xBD!"; 89 WifiNetwork* wifi = new WifiNetwork("fw"); 90 wifi->SetName(wifi_setname2); 91 EXPECT_EQ(wifi->name(), wifi_setname2_result); 92 delete wifi; 93 } 94 95 // UTF8 SSID 96 { 97 std::string wifi_utf8 = "UTF-8 \u3042\u3044\u3046"; 98 std::string wifi_utf8_result = "UTF-8 \xE3\x81\x82\xE3\x81\x84\xE3\x81\x86"; 99 WifiNetwork* wifi = new WifiNetwork("fw"); 100 WifiNetwork::TestApi test_wifi(wifi); 101 test_wifi.SetSsid(wifi_utf8); 102 EXPECT_EQ(wifi->name(), wifi_utf8_result); 103 delete wifi; 104 } 105 106 // latin1 SSID -> UTF8 SSID 107 { 108 std::string wifi_latin1 = "latin-1 \xc0\xcb\xcc\xd6\xfb"; 109 std::string wifi_latin1_result = "latin-1 \u00c0\u00cb\u00cc\u00d6\u00fb"; 110 WifiNetwork* wifi = new WifiNetwork("fw"); 111 WifiNetwork::TestApi test_wifi(wifi); 112 test_wifi.SetSsid(wifi_latin1); 113 EXPECT_EQ(wifi->name(), wifi_latin1_result); 114 delete wifi; 115 } 116 117 // Hex SSID 118 { 119 std::string wifi_hex = "5468697320697320484558205353494421"; 120 std::string wifi_hex_result = "This is HEX SSID!"; 121 WifiNetwork* wifi = new WifiNetwork("fw"); 122 WifiNetwork::TestApi test_wifi(wifi); 123 test_wifi.SetHexSsid(wifi_hex); 124 EXPECT_EQ(wifi->name(), wifi_hex_result); 125 delete wifi; 126 } 127 } 128 129 // Create a stub libcros for testing NetworkLibrary functionality through 130 // NetworkLibraryStubImpl. 131 // NOTE: It would be of little value to test stub functions that simply return 132 // predefined values, e.g. ethernet_available(). However, many other functions 133 // such as connected_network() return values which are set indirectly and thus 134 // we can test the logic of those setters. 135 136 class NetworkLibraryStubTest : public ::testing::Test { 137 public: 138 NetworkLibraryStubTest() : cros_(NULL) {} 139 140 protected: 141 virtual void SetUp() { 142 cros_ = static_cast<NetworkLibraryImplStub*>(NetworkLibrary::Get()); 143 ASSERT_TRUE(cros_) << "GetNetworkLibrary() Failed!"; 144 } 145 146 virtual void TearDown() { 147 cros_ = NULL; 148 } 149 150 // Load the ONC from |onc_file| using NetworkLibrary::LoadOncNetworks. Check 151 // that return value matches |expect_successful_import| and the configuration 152 // that would be sent to Shill matches |shill_json|. 153 void LoadOncAndVerifyNetworks(std::string onc_file, 154 std::string shill_json, 155 onc::ONCSource source, 156 bool expect_successful_import) { 157 MockUserManager* mock_user_manager = 158 new ::testing::StrictMock<MockUserManager>; 159 // Takes ownership of |mock_user_manager|. 160 ScopedUserManagerEnabler user_manager_enabler(mock_user_manager); 161 mock_user_manager->SetActiveUser("madmax (at) my.domain.com"); 162 EXPECT_CALL(*mock_user_manager, IsUserLoggedIn()) 163 .Times(AnyNumber()) 164 .WillRepeatedly(Return(true)); 165 EXPECT_CALL(*mock_user_manager, Shutdown()); 166 167 scoped_ptr<base::DictionaryValue> onc_blob = 168 onc::test_utils::ReadTestDictionary(onc_file); 169 base::ListValue* onc_network_configs; 170 onc_blob->GetListWithoutPathExpansion( 171 onc::toplevel_config::kNetworkConfigurations, 172 &onc_network_configs); 173 ASSERT_TRUE(onc_network_configs); 174 175 scoped_ptr<base::Value> expected_value = 176 google_apis::test_util::LoadJSONFile(shill_json); 177 base::DictionaryValue* expected_configs; 178 expected_value->GetAsDictionary(&expected_configs); 179 180 cros_->LoadOncNetworks(*onc_network_configs, source); 181 182 const std::map<std::string, base::DictionaryValue*>& configs = 183 cros_->GetConfigurations(); 184 185 EXPECT_EQ(expected_configs->size(), configs.size()); 186 187 for (base::DictionaryValue::Iterator it(*expected_configs); !it.IsAtEnd(); 188 it.Advance()) { 189 const base::DictionaryValue* expected_config; 190 it.value().GetAsDictionary(&expected_config); 191 192 std::map<std::string, base::DictionaryValue*>::const_iterator entry = 193 configs.find(it.key()); 194 EXPECT_NE(entry, configs.end()); 195 base::DictionaryValue* actual_config = entry->second; 196 EXPECT_TRUE(onc::test_utils::Equals(expected_config, actual_config)); 197 } 198 } 199 200 ScopedStubNetworkLibraryEnabler cros_stub_; 201 NetworkLibraryImplStub* cros_; 202 203 protected: 204 scoped_refptr<net::CryptoModule> slot_; 205 crypto::ScopedTestNSSDB test_nssdb_; 206 }; 207 208 // Default stub state: 209 // vpn1: disconnected, L2TP/IPsec + PSK 210 // vpn2: disconnected, L2TP/IPsec + user cert 211 // vpn3: disconnected, OpenVpn 212 // eth1: connected (active network) 213 // wifi1: connected 214 // wifi2: disconnected 215 // wifi3: disconnected, WEP 216 // wifi4: disconnected, 8021x 217 // wifi5: disconnected 218 // wifi6: disconnected 219 // cellular1: connected, activated, not roaming 220 // cellular2: disconnected, activated, roaming 221 222 TEST_F(NetworkLibraryStubTest, NetworkLibraryAccessors) { 223 // Set up state. 224 // Set wifi2->connecting for these tests. 225 WifiNetwork* wifi2 = cros_->FindWifiNetworkByPath("wifi2"); 226 ASSERT_NE(static_cast<const Network*>(NULL), wifi2); 227 Network::TestApi test_wifi2(wifi2); 228 test_wifi2.SetConnecting(); 229 // Set cellular1->connecting for these tests. 230 CellularNetwork* cellular1 = cros_->FindCellularNetworkByPath("cellular1"); 231 ASSERT_NE(static_cast<const Network*>(NULL), cellular1); 232 Network::TestApi test_cellular1(cellular1); 233 test_cellular1.SetConnecting(); 234 235 // Ethernet 236 ASSERT_NE(static_cast<const EthernetNetwork*>(NULL), 237 cros_->ethernet_network()); 238 EXPECT_EQ("eth1", cros_->ethernet_network()->service_path()); 239 EXPECT_NE(static_cast<const Network*>(NULL), 240 cros_->FindNetworkByPath("eth1")); 241 EXPECT_TRUE(cros_->ethernet_connected()); 242 EXPECT_FALSE(cros_->ethernet_connecting()); 243 244 // Wifi 245 ASSERT_NE(static_cast<const WifiNetwork*>(NULL), cros_->wifi_network()); 246 EXPECT_EQ("wifi1", cros_->wifi_network()->service_path()); 247 EXPECT_NE(static_cast<const WifiNetwork*>(NULL), 248 cros_->FindWifiNetworkByPath("wifi1")); 249 EXPECT_TRUE(cros_->wifi_connected()); 250 EXPECT_FALSE(cros_->wifi_connecting()); // Only true for active wifi. 251 EXPECT_GE(cros_->wifi_networks().size(), 1U); 252 253 // Cellular 254 ASSERT_NE(static_cast<const CellularNetwork*>(NULL), 255 cros_->cellular_network()); 256 EXPECT_EQ("cellular1", cros_->cellular_network()->service_path()); 257 EXPECT_NE(static_cast<const CellularNetwork*>(NULL), 258 cros_->FindCellularNetworkByPath("cellular1")); 259 EXPECT_FALSE(cros_->cellular_connected()); 260 EXPECT_TRUE(cros_->cellular_connecting()); 261 EXPECT_GE(cros_->cellular_networks().size(), 1U); 262 263 // VPN 264 ASSERT_EQ(static_cast<const VirtualNetwork*>(NULL), cros_->virtual_network()); 265 EXPECT_GE(cros_->virtual_networks().size(), 1U); 266 267 // Active network and global state 268 EXPECT_TRUE(cros_->Connected()); 269 ASSERT_NE(static_cast<const Network*>(NULL), cros_->active_network()); 270 EXPECT_EQ("eth1", cros_->active_network()->service_path()); 271 ASSERT_NE(static_cast<const Network*>(NULL), cros_->connected_network()); 272 EXPECT_EQ("eth1", cros_->connected_network()->service_path()); 273 // The "wifi1" is connected, so we do not return "wifi2" for the connecting 274 // network. There is no conencted cellular network, so "cellular1" is 275 // returned by connecting_network(). 276 EXPECT_TRUE(cros_->Connecting()); 277 ASSERT_NE(static_cast<const Network*>(NULL), cros_->connecting_network()); 278 EXPECT_EQ("cellular1", cros_->connecting_network()->service_path()); 279 } 280 281 TEST_F(NetworkLibraryStubTest, NetworkConnectWifi) { 282 WifiNetwork* wifi1 = cros_->FindWifiNetworkByPath("wifi1"); 283 ASSERT_NE(static_cast<const WifiNetwork*>(NULL), wifi1); 284 EXPECT_TRUE(wifi1->connected()); 285 cros_->DisconnectFromNetwork(wifi1); 286 EXPECT_FALSE(wifi1->connected()); 287 EXPECT_TRUE(cros_->CanConnectToNetwork(wifi1)); 288 cros_->ConnectToWifiNetwork(wifi1); 289 EXPECT_TRUE(wifi1->connected()); 290 } 291 292 TEST_F(NetworkLibraryStubTest, NetworkConnectWifiWithCertPattern) { 293 scoped_ptr<base::DictionaryValue> onc_root = 294 onc::test_utils::ReadTestDictionary("certificate-client.onc"); 295 base::ListValue* certificates; 296 onc_root->GetListWithoutPathExpansion(onc::toplevel_config::kCertificates, 297 &certificates); 298 299 onc::CertificateImporterImpl importer; 300 ASSERT_TRUE(importer.ImportCertificates( 301 *certificates, onc::ONC_SOURCE_USER_IMPORT, NULL)); 302 303 WifiNetwork* wifi = cros_->FindWifiNetworkByPath("wifi_cert_pattern"); 304 305 StubEnrollmentDelegate* enrollment_delegate = new StubEnrollmentDelegate(); 306 wifi->SetEnrollmentDelegate(enrollment_delegate); 307 EXPECT_FALSE(enrollment_delegate->did_enroll); 308 EXPECT_FALSE(enrollment_delegate->correct_args); 309 310 ASSERT_NE(static_cast<const WifiNetwork*>(NULL), wifi); 311 EXPECT_FALSE(wifi->connected()); 312 EXPECT_TRUE(cros_->CanConnectToNetwork(wifi)); 313 EXPECT_FALSE(wifi->connected()); 314 wifi->AttemptConnection( 315 base::Bind(&WifiNetworkConnectCallback, cros_, wifi)); 316 EXPECT_TRUE(wifi->connected()); 317 EXPECT_TRUE(enrollment_delegate->did_enroll); 318 EXPECT_TRUE(enrollment_delegate->correct_args); 319 } 320 321 TEST_F(NetworkLibraryStubTest, NetworkConnectVPNWithCertPattern) { 322 scoped_ptr<base::DictionaryValue> onc_root = 323 onc::test_utils::ReadTestDictionary("certificate-client.onc"); 324 base::ListValue* certificates; 325 onc_root->GetListWithoutPathExpansion(onc::toplevel_config::kCertificates, 326 &certificates); 327 328 onc::CertificateImporterImpl importer; 329 ASSERT_TRUE(importer.ImportCertificates( 330 *certificates, onc::ONC_SOURCE_USER_IMPORT, NULL)); 331 332 VirtualNetwork* vpn = cros_->FindVirtualNetworkByPath("vpn_cert_pattern"); 333 334 StubEnrollmentDelegate* enrollment_delegate = new StubEnrollmentDelegate(); 335 vpn->SetEnrollmentDelegate(enrollment_delegate); 336 EXPECT_FALSE(enrollment_delegate->did_enroll); 337 EXPECT_FALSE(enrollment_delegate->correct_args); 338 339 ASSERT_NE(static_cast<const VirtualNetwork*>(NULL), vpn); 340 EXPECT_FALSE(vpn->connected()); 341 EXPECT_TRUE(cros_->CanConnectToNetwork(vpn)); 342 EXPECT_FALSE(vpn->connected()); 343 vpn->AttemptConnection( 344 base::Bind(&VirtualNetworkConnectCallback, cros_, vpn)); 345 EXPECT_TRUE(vpn->connected()); 346 EXPECT_TRUE(enrollment_delegate->did_enroll); 347 EXPECT_TRUE(enrollment_delegate->correct_args); 348 } 349 350 TEST_F(NetworkLibraryStubTest, NetworkConnectVPN) { 351 VirtualNetwork* vpn1 = cros_->FindVirtualNetworkByPath("vpn1"); 352 EXPECT_NE(static_cast<const VirtualNetwork*>(NULL), vpn1); 353 EXPECT_FALSE(vpn1->connected()); 354 EXPECT_TRUE(cros_->CanConnectToNetwork(vpn1)); 355 cros_->ConnectToVirtualNetwork(vpn1); 356 EXPECT_TRUE(vpn1->connected()); 357 ASSERT_NE(static_cast<const VirtualNetwork*>(NULL), cros_->virtual_network()); 358 EXPECT_EQ("vpn1", cros_->virtual_network()->service_path()); 359 } 360 361 namespace { 362 363 struct ImportParams { 364 // |onc_file|: Filename of source ONC, relative to 365 // chromeos/test/data/network. 366 // |shill_file|: Filename of expected Shill config, relative to 367 // chrome/test/data). 368 // |onc_source|: The source of the ONC. 369 // |expect_import_result|: The expected return value of LoadOncNetworks. 370 ImportParams(const std::string& onc_file, 371 const std::string& shill_file, 372 onc::ONCSource onc_source, 373 bool expect_import_result = true) 374 : onc_file(onc_file), 375 shill_file(shill_file), 376 onc_source(onc_source), 377 expect_import_result(expect_import_result) { 378 } 379 380 std::string onc_file, shill_file; 381 onc::ONCSource onc_source; 382 bool expect_import_result; 383 }; 384 385 ::std::ostream& operator<<(::std::ostream& os, const ImportParams& params) { 386 return os << "(" << params.onc_file << ", " << params.shill_file << ", " 387 << onc::GetSourceAsString(params.onc_source) << ", " 388 << (params.expect_import_result ? "valid" : "invalid") << ")"; 389 } 390 391 } // namespace 392 393 class LoadOncNetworksTest 394 : public NetworkLibraryStubTest, 395 public ::testing::WithParamInterface<ImportParams> { 396 }; 397 398 TEST_P(LoadOncNetworksTest, VerifyNetworksAndCertificates) { 399 LoadOncAndVerifyNetworks(GetParam().onc_file, 400 GetParam().shill_file, 401 GetParam().onc_source, 402 GetParam().expect_import_result); 403 } 404 405 INSTANTIATE_TEST_CASE_P( 406 LoadOncNetworksTest, 407 LoadOncNetworksTest, 408 ::testing::Values( 409 ImportParams("managed_toplevel1_with_cert_pems.onc", 410 "chromeos/net/shill_for_managed_toplevel1.json", 411 onc::ONC_SOURCE_USER_POLICY), 412 ImportParams("managed_toplevel2_with_cert_pems.onc", 413 "chromeos/net/shill_for_managed_toplevel2.json", 414 onc::ONC_SOURCE_USER_POLICY), 415 ImportParams("managed_toplevel_l2tpipsec.onc", 416 "chromeos/net/shill_for_managed_toplevel_l2tpipsec.json", 417 onc::ONC_SOURCE_USER_POLICY), 418 ImportParams("managed_toplevel_wifi_peap.onc", 419 "chromeos/net/shill_for_managed_toplevel_wifi_peap.json", 420 onc::ONC_SOURCE_DEVICE_POLICY), 421 ImportParams("toplevel_wifi_open.onc", 422 "chromeos/net/shill_for_toplevel_wifi_open.json", 423 onc::ONC_SOURCE_DEVICE_POLICY), 424 ImportParams("toplevel_wifi_wep_proxy.onc", 425 "chromeos/net/shill_for_toplevel_wifi_wep_proxy.json", 426 onc::ONC_SOURCE_USER_POLICY), 427 ImportParams("toplevel_wifi_wpa_psk.onc", 428 "chromeos/net/shill_for_toplevel_wifi_wpa_psk.json", 429 onc::ONC_SOURCE_USER_POLICY), 430 ImportParams("toplevel_wifi_leap.onc", 431 "chromeos/net/shill_for_toplevel_wifi_leap.json", 432 onc::ONC_SOURCE_USER_POLICY), 433 ImportParams( 434 "toplevel_wifi_eap_clientcert_with_cert_pems.onc", 435 "chromeos/net/shill_for_toplevel_wifi_eap_clientcert.json", 436 onc::ONC_SOURCE_USER_POLICY), 437 ImportParams("toplevel_openvpn_clientcert_with_cert_pems.onc", 438 "chromeos/net/shill_for_toplevel_openvpn_clientcert.json", 439 onc::ONC_SOURCE_USER_POLICY), 440 ImportParams("toplevel_wifi_remove.onc", 441 "chromeos/net/shill_for_toplevel_wifi_remove.json", 442 onc::ONC_SOURCE_USER_POLICY))); 443 444 // TODO(stevenjb): Test remembered networks. 445 446 // TODO(stevenjb): Test network profiles. 447 448 // TODO(stevenjb): Test network devices. 449 450 // TODO(stevenjb): Test data plans. 451 452 // TODO(stevenjb): Test monitor network / device. 453 454 } // namespace chromeos 455