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