Home | History | Annotate | Download | only in network
      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/network_connection_handler.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/callback.h"
      9 #include "base/file_util.h"
     10 #include "base/json/json_reader.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "base/run_loop.h"
     14 #include "base/strings/stringprintf.h"
     15 #include "chromeos/cert_loader.h"
     16 #include "chromeos/dbus/fake_dbus_thread_manager.h"
     17 #include "chromeos/dbus/shill_device_client.h"
     18 #include "chromeos/dbus/shill_manager_client.h"
     19 #include "chromeos/dbus/shill_profile_client.h"
     20 #include "chromeos/dbus/shill_service_client.h"
     21 #include "chromeos/network/managed_network_configuration_handler_impl.h"
     22 #include "chromeos/network/network_configuration_handler.h"
     23 #include "chromeos/network/network_profile_handler.h"
     24 #include "chromeos/network/network_state_handler.h"
     25 #include "chromeos/network/onc/onc_utils.h"
     26 #include "chromeos/tpm_token_loader.h"
     27 #include "components/onc/onc_constants.h"
     28 #include "crypto/nss_util.h"
     29 #include "crypto/nss_util_internal.h"
     30 #include "net/base/net_errors.h"
     31 #include "net/base/test_data_directory.h"
     32 #include "net/cert/nss_cert_database_chromeos.h"
     33 #include "net/cert/x509_certificate.h"
     34 #include "net/test/cert_test_util.h"
     35 #include "testing/gtest/include/gtest/gtest.h"
     36 #include "third_party/cros_system_api/dbus/service_constants.h"
     37 
     38 namespace {
     39 
     40 const char* kSuccessResult = "success";
     41 
     42 void ConfigureCallback(const dbus::ObjectPath& result) {
     43 }
     44 
     45 void ConfigureErrorCallback(const std::string& error_name,
     46                             const std::string& error_message) {
     47 }
     48 
     49 }  // namespace
     50 
     51 namespace chromeos {
     52 
     53 class NetworkConnectionHandlerTest : public testing::Test {
     54  public:
     55   NetworkConnectionHandlerTest()
     56       : user_("userhash"),
     57         test_manager_client_(NULL),
     58         test_service_client_(NULL) {}
     59 
     60   virtual ~NetworkConnectionHandlerTest() {
     61   }
     62 
     63   virtual void SetUp() OVERRIDE {
     64     ASSERT_TRUE(user_.constructed_successfully());
     65     user_.FinishInit();
     66 
     67     test_nssdb_.reset(new net::NSSCertDatabaseChromeOS(
     68         crypto::GetPublicSlotForChromeOSUser(user_.username_hash()),
     69         crypto::GetPrivateSlotForChromeOSUser(
     70             user_.username_hash(),
     71             base::Callback<void(crypto::ScopedPK11Slot)>())));
     72     test_nssdb_->SetSlowTaskRunnerForTest(message_loop_.message_loop_proxy());
     73 
     74     TPMTokenLoader::InitializeForTest();
     75 
     76     CertLoader::Initialize();
     77     CertLoader* cert_loader = CertLoader::Get();
     78     cert_loader->force_hardware_backed_for_test();
     79 
     80     FakeDBusThreadManager* dbus_manager = new FakeDBusThreadManager;
     81     dbus_manager->SetFakeClients();
     82     DBusThreadManager::InitializeForTesting(dbus_manager);
     83     test_manager_client_ =
     84         dbus_manager->GetShillManagerClient()->GetTestInterface();
     85     test_service_client_ =
     86         dbus_manager->GetShillServiceClient()->GetTestInterface();
     87 
     88     test_manager_client_->AddTechnology(shill::kTypeWifi, true /* enabled */);
     89     dbus_manager->GetShillDeviceClient()->GetTestInterface()->AddDevice(
     90         "/device/wifi1", shill::kTypeWifi, "wifi_device1");
     91     test_manager_client_->AddTechnology(shill::kTypeCellular,
     92                                         true /* enabled */);
     93     dbus_manager->GetShillProfileClient()->GetTestInterface()->AddProfile(
     94         "profile_path", std::string() /* shared profile */);
     95 
     96     base::RunLoop().RunUntilIdle();
     97     LoginState::Initialize();
     98     network_state_handler_.reset(NetworkStateHandler::InitializeForTest());
     99     network_config_handler_.reset(
    100         NetworkConfigurationHandler::InitializeForTest(
    101             network_state_handler_.get()));
    102 
    103     network_profile_handler_.reset(new NetworkProfileHandler());
    104     network_profile_handler_->Init();
    105 
    106     managed_config_handler_.reset(new ManagedNetworkConfigurationHandlerImpl());
    107     managed_config_handler_->Init(network_state_handler_.get(),
    108                                   network_profile_handler_.get(),
    109                                   network_config_handler_.get(),
    110                                   NULL /* network_device_handler */);
    111 
    112     network_connection_handler_.reset(new NetworkConnectionHandler);
    113     network_connection_handler_->Init(network_state_handler_.get(),
    114                                       network_config_handler_.get(),
    115                                       managed_config_handler_.get());
    116 
    117     base::RunLoop().RunUntilIdle();
    118   }
    119 
    120   virtual void TearDown() OVERRIDE {
    121     managed_config_handler_.reset();
    122     network_profile_handler_.reset();
    123     network_connection_handler_.reset();
    124     network_config_handler_.reset();
    125     network_state_handler_.reset();
    126     CertLoader::Shutdown();
    127     TPMTokenLoader::Shutdown();
    128     LoginState::Shutdown();
    129     DBusThreadManager::Shutdown();
    130   }
    131 
    132  protected:
    133   bool Configure(const std::string& json_string) {
    134     scoped_ptr<base::DictionaryValue> json_dict =
    135         onc::ReadDictionaryFromJson(json_string);
    136     if (!json_dict) {
    137       LOG(ERROR) << "Error parsing json: " << json_string;
    138       return false;
    139     }
    140     DBusThreadManager::Get()->GetShillManagerClient()->ConfigureService(
    141         *json_dict,
    142         base::Bind(&ConfigureCallback),
    143         base::Bind(&ConfigureErrorCallback));
    144     base::RunLoop().RunUntilIdle();
    145     return true;
    146   }
    147 
    148   void Connect(const std::string& service_path) {
    149     const bool check_error_state = true;
    150     network_connection_handler_->ConnectToNetwork(
    151         service_path,
    152         base::Bind(&NetworkConnectionHandlerTest::SuccessCallback,
    153                    base::Unretained(this)),
    154         base::Bind(&NetworkConnectionHandlerTest::ErrorCallback,
    155                    base::Unretained(this)),
    156         check_error_state);
    157     base::RunLoop().RunUntilIdle();
    158   }
    159 
    160   void Disconnect(const std::string& service_path) {
    161     network_connection_handler_->DisconnectNetwork(
    162         service_path,
    163         base::Bind(&NetworkConnectionHandlerTest::SuccessCallback,
    164                    base::Unretained(this)),
    165         base::Bind(&NetworkConnectionHandlerTest::ErrorCallback,
    166                    base::Unretained(this)));
    167     base::RunLoop().RunUntilIdle();
    168   }
    169 
    170   void SuccessCallback() {
    171     result_ = kSuccessResult;
    172   }
    173 
    174   void ErrorCallback(const std::string& error_name,
    175                      scoped_ptr<base::DictionaryValue> error_data) {
    176     result_ = error_name;
    177   }
    178 
    179   std::string GetResultAndReset() {
    180     std::string result;
    181     result.swap(result_);
    182     return result;
    183   }
    184 
    185   std::string GetServiceStringProperty(const std::string& service_path,
    186                                        const std::string& key) {
    187     std::string result;
    188     const base::DictionaryValue* properties =
    189         test_service_client_->GetServiceProperties(service_path);
    190     if (properties)
    191       properties->GetStringWithoutPathExpansion(key, &result);
    192     return result;
    193   }
    194 
    195   void StartCertLoader() {
    196     CertLoader::Get()->StartWithNSSDB(test_nssdb_.get());
    197     base::RunLoop().RunUntilIdle();
    198   }
    199 
    200   void LoginToRegularUser() {
    201     LoginState::Get()->SetLoggedInState(LoginState::LOGGED_IN_ACTIVE,
    202                                         LoginState::LOGGED_IN_USER_REGULAR);
    203     base::RunLoop().RunUntilIdle();
    204   }
    205 
    206   void ImportClientCertAndKey(const std::string& pkcs12_file,
    207                               net::NSSCertDatabase* nssdb,
    208                               net::CertificateList* loaded_certs) {
    209     std::string pkcs12_data;
    210     base::FilePath pkcs12_path =
    211         net::GetTestCertsDirectory().Append(pkcs12_file);
    212     ASSERT_TRUE(base::ReadFileToString(pkcs12_path, &pkcs12_data));
    213 
    214     scoped_refptr<net::CryptoModule> module(
    215         net::CryptoModule::CreateFromHandle(nssdb->GetPrivateSlot().get()));
    216     ASSERT_EQ(
    217         net::OK,
    218         nssdb->ImportFromPKCS12(module, pkcs12_data, base::string16(), false,
    219                                 loaded_certs));
    220     ASSERT_EQ(1U, loaded_certs->size());
    221   }
    222 
    223   void SetupPolicy() {
    224     const char* kNetworkConfigs =
    225         "[ { \"GUID\": \"wifi1\","
    226         "    \"Name\": \"wifi1\","
    227         "    \"Type\": \"WiFi\","
    228         "    \"WiFi\": {"
    229         "      \"Security\": \"WPA-PSK\","
    230         "      \"SSID\": \"wifi1\","
    231         "      \"Passphrase\": \"passphrase\""
    232         "    }"
    233         "} ]";
    234 
    235     std::string error;
    236     scoped_ptr<base::Value> network_configs_value(
    237         base::JSONReader::ReadAndReturnError(
    238             kNetworkConfigs, base::JSON_ALLOW_TRAILING_COMMAS, NULL, &error));
    239     ASSERT_TRUE(network_configs_value) << error;
    240 
    241     base::ListValue* network_configs = NULL;
    242     ASSERT_TRUE(network_configs_value->GetAsList(&network_configs));
    243 
    244     base::DictionaryValue global_config;
    245     global_config.SetBooleanWithoutPathExpansion(
    246         ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect,
    247         true);
    248 
    249     managed_config_handler_->SetPolicy(::onc::ONC_SOURCE_USER_POLICY,
    250                                        "", // userhash
    251                                        *network_configs,
    252                                        global_config);
    253     base::RunLoop().RunUntilIdle();
    254   }
    255 
    256   scoped_ptr<NetworkStateHandler> network_state_handler_;
    257   scoped_ptr<NetworkConfigurationHandler> network_config_handler_;
    258   scoped_ptr<NetworkConnectionHandler> network_connection_handler_;
    259   scoped_ptr<ManagedNetworkConfigurationHandlerImpl> managed_config_handler_;
    260   scoped_ptr<NetworkProfileHandler> network_profile_handler_;
    261   crypto::ScopedTestNSSChromeOSUser user_;
    262   ShillManagerClient::TestInterface* test_manager_client_;
    263   ShillServiceClient::TestInterface* test_service_client_;
    264   scoped_ptr<net::NSSCertDatabaseChromeOS> test_nssdb_;
    265   base::MessageLoopForUI message_loop_;
    266   std::string result_;
    267 
    268  private:
    269   DISALLOW_COPY_AND_ASSIGN(NetworkConnectionHandlerTest);
    270 };
    271 
    272 namespace {
    273 
    274 const char* kConfigConnectable =
    275     "{ \"GUID\": \"wifi0\", \"Type\": \"wifi\", \"State\": \"idle\", "
    276     "  \"Connectable\": true }";
    277 const char* kConfigConnected =
    278     "{ \"GUID\": \"wifi1\", \"Type\": \"wifi\", \"State\": \"online\" }";
    279 const char* kConfigConnecting =
    280     "{ \"GUID\": \"wifi2\", \"Type\": \"wifi\", \"State\": \"association\" }";
    281 const char* kConfigRequiresPassphrase =
    282     "{ \"GUID\": \"wifi3\", \"Type\": \"wifi\", "
    283     "  \"PassphraseRequired\": true }";
    284 const char* kConfigRequiresActivation =
    285     "{ \"GUID\": \"cellular1\", \"Type\": \"cellular\","
    286     "  \"Cellular.ActivationState\": \"not-activated\" }";
    287 
    288 }  // namespace
    289 
    290 TEST_F(NetworkConnectionHandlerTest, NetworkConnectionHandlerConnectSuccess) {
    291   EXPECT_TRUE(Configure(kConfigConnectable));
    292   Connect("wifi0");
    293   EXPECT_EQ(kSuccessResult, GetResultAndReset());
    294   EXPECT_EQ(shill::kStateOnline,
    295             GetServiceStringProperty("wifi0", shill::kStateProperty));
    296 }
    297 
    298 // Handles basic failure cases.
    299 TEST_F(NetworkConnectionHandlerTest, NetworkConnectionHandlerConnectFailure) {
    300   Connect("no-network");
    301   EXPECT_EQ(NetworkConnectionHandler::kErrorConfigureFailed,
    302             GetResultAndReset());
    303 
    304   EXPECT_TRUE(Configure(kConfigConnected));
    305   Connect("wifi1");
    306   EXPECT_EQ(NetworkConnectionHandler::kErrorConnected, GetResultAndReset());
    307 
    308   EXPECT_TRUE(Configure(kConfigConnecting));
    309   Connect("wifi2");
    310   EXPECT_EQ(NetworkConnectionHandler::kErrorConnecting, GetResultAndReset());
    311 
    312   EXPECT_TRUE(Configure(kConfigRequiresPassphrase));
    313   Connect("wifi3");
    314   EXPECT_EQ(NetworkConnectionHandler::kErrorPassphraseRequired,
    315             GetResultAndReset());
    316 
    317   EXPECT_TRUE(Configure(kConfigRequiresActivation));
    318   Connect("cellular1");
    319   EXPECT_EQ(NetworkConnectionHandler::kErrorActivationRequired,
    320             GetResultAndReset());
    321 }
    322 
    323 namespace {
    324 
    325 const char* kConfigRequiresCertificateTemplate =
    326     "{ \"GUID\": \"wifi4\", \"Type\": \"wifi\", \"Connectable\": false,"
    327     "  \"Security\": \"802_1x\","
    328     "  \"UIData\": \"{"
    329     "    \\\"certificate_type\\\": \\\"pattern\\\","
    330     "    \\\"certificate_pattern\\\": {"
    331     "      \\\"Subject\\\": {\\\"CommonName\\\": \\\"%s\\\" }"
    332     "   } }\" }";
    333 
    334 }  // namespace
    335 
    336 // Handle certificates.
    337 TEST_F(NetworkConnectionHandlerTest, ConnectCertificateMissing) {
    338   StartCertLoader();
    339 
    340   EXPECT_TRUE(Configure(
    341       base::StringPrintf(kConfigRequiresCertificateTemplate, "unknown")));
    342   Connect("wifi4");
    343   EXPECT_EQ(NetworkConnectionHandler::kErrorCertificateRequired,
    344             GetResultAndReset());
    345 }
    346 
    347 TEST_F(NetworkConnectionHandlerTest, ConnectWithCertificateSuccess) {
    348   StartCertLoader();
    349 
    350   net::CertificateList certs;
    351   ImportClientCertAndKey("websocket_client_cert.p12",
    352                          test_nssdb_.get(),
    353                          &certs);
    354 
    355   EXPECT_TRUE(Configure(
    356       base::StringPrintf(kConfigRequiresCertificateTemplate,
    357                          certs[0]->subject().common_name.c_str())));
    358 
    359   Connect("wifi4");
    360   EXPECT_EQ(kSuccessResult, GetResultAndReset());
    361 }
    362 
    363 TEST_F(NetworkConnectionHandlerTest,
    364        ConnectWithCertificateRequestedBeforeCertsAreLoaded) {
    365   net::CertificateList certs;
    366   ImportClientCertAndKey("websocket_client_cert.p12",
    367                          test_nssdb_.get(),
    368                          &certs);
    369 
    370   EXPECT_TRUE(Configure(
    371       base::StringPrintf(kConfigRequiresCertificateTemplate,
    372                          certs[0]->subject().common_name.c_str())));
    373 
    374   Connect("wifi4");
    375 
    376   // Connect request came before the cert loader loaded certificates, so the
    377   // connect request should have been throttled until the certificates are
    378   // loaded.
    379   EXPECT_EQ("", GetResultAndReset());
    380 
    381   StartCertLoader();
    382 
    383   // |StartCertLoader| should have triggered certificate loading.
    384   // When the certificates got loaded, the connection request should have
    385   // proceeded and eventually succeeded.
    386   EXPECT_EQ(kSuccessResult, GetResultAndReset());
    387 }
    388 
    389 TEST_F(NetworkConnectionHandlerTest,
    390        NetworkConnectionHandlerDisconnectSuccess) {
    391   EXPECT_TRUE(Configure(kConfigConnected));
    392   Disconnect("wifi1");
    393   EXPECT_EQ(kSuccessResult, GetResultAndReset());
    394 }
    395 
    396 TEST_F(NetworkConnectionHandlerTest,
    397        NetworkConnectionHandlerDisconnectFailure) {
    398   Connect("no-network");
    399   EXPECT_EQ(NetworkConnectionHandler::kErrorConfigureFailed,
    400             GetResultAndReset());
    401 
    402   EXPECT_TRUE(Configure(kConfigConnectable));
    403   Disconnect("wifi0");
    404   EXPECT_EQ(NetworkConnectionHandler::kErrorNotConnected, GetResultAndReset());
    405 }
    406 
    407 namespace {
    408 
    409 const char* kConfigUnmanagedSharedConnected =
    410     "{ \"GUID\": \"wifi0\", \"Type\": \"wifi\", \"State\": \"online\" }";
    411 const char* kConfigManagedSharedConnectable =
    412     "{ \"GUID\": \"wifi1\", \"Type\": \"wifi\", \"State\": \"idle\", "
    413     "  \"Connectable\": true }";
    414 
    415 }  // namespace
    416 
    417 TEST_F(NetworkConnectionHandlerTest, ReconnectOnLoginEarlyPolicyLoading) {
    418   EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected));
    419   EXPECT_TRUE(Configure(kConfigManagedSharedConnectable));
    420   test_manager_client_->SetBestServiceToConnect("wifi1");
    421 
    422   // User login shouldn't trigger any change because policy is not loaded yet.
    423   LoginToRegularUser();
    424   EXPECT_EQ(shill::kStateOnline,
    425             GetServiceStringProperty("wifi0", shill::kStateProperty));
    426   EXPECT_EQ(shill::kStateIdle,
    427             GetServiceStringProperty("wifi1", shill::kStateProperty));
    428 
    429   // Policy application should disconnect from the shared and unmanaged network.
    430   SetupPolicy();
    431   EXPECT_EQ(shill::kStateIdle,
    432             GetServiceStringProperty("wifi0", shill::kStateProperty));
    433   EXPECT_EQ(shill::kStateIdle,
    434             GetServiceStringProperty("wifi1", shill::kStateProperty));
    435 
    436   // Certificate loading should trigger connecting to the 'best' network.
    437   StartCertLoader();
    438   EXPECT_EQ(shill::kStateIdle,
    439             GetServiceStringProperty("wifi0", shill::kStateProperty));
    440   EXPECT_EQ(shill::kStateOnline,
    441             GetServiceStringProperty("wifi1", shill::kStateProperty));
    442 }
    443 
    444 TEST_F(NetworkConnectionHandlerTest, ReconnectOnLoginLatePolicyLoading) {
    445   EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected));
    446   EXPECT_TRUE(Configure(kConfigManagedSharedConnectable));
    447   test_manager_client_->SetBestServiceToConnect("wifi1");
    448 
    449   // User login and certificate loading shouldn't trigger any change until the
    450   // policy is loaded.
    451   LoginToRegularUser();
    452   StartCertLoader();
    453   EXPECT_EQ(shill::kStateOnline,
    454             GetServiceStringProperty("wifi0", shill::kStateProperty));
    455   EXPECT_EQ(shill::kStateIdle,
    456             GetServiceStringProperty("wifi1", shill::kStateProperty));
    457 
    458   SetupPolicy();
    459   EXPECT_EQ(shill::kStateIdle,
    460             GetServiceStringProperty("wifi0", shill::kStateProperty));
    461   EXPECT_EQ(shill::kStateOnline,
    462             GetServiceStringProperty("wifi1", shill::kStateProperty));
    463 }
    464 
    465 }  // namespace chromeos
    466