Home | History | Annotate | Download | only in cros
      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