OLD | NEW |
| (Empty) |
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@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 | |
OLD | NEW |