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/files/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/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_internal.h" 29 #include "crypto/scoped_test_nss_chromeos_user.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 DBusThreadManager::Initialize(); 81 DBusThreadManager* dbus_manager = DBusThreadManager::Get(); 82 test_manager_client_ = 83 dbus_manager->GetShillManagerClient()->GetTestInterface(); 84 test_service_client_ = 85 dbus_manager->GetShillServiceClient()->GetTestInterface(); 86 87 test_manager_client_->AddTechnology(shill::kTypeWifi, true /* enabled */); 88 dbus_manager->GetShillDeviceClient()->GetTestInterface()->AddDevice( 89 "/device/wifi1", shill::kTypeWifi, "wifi_device1"); 90 test_manager_client_->AddTechnology(shill::kTypeCellular, 91 true /* enabled */); 92 dbus_manager->GetShillProfileClient()->GetTestInterface()->AddProfile( 93 "shared_profile_path", std::string() /* shared profile */); 94 dbus_manager->GetShillProfileClient()->GetTestInterface()->AddProfile( 95 "user_profile_path", user_.username_hash()); 96 97 base::RunLoop().RunUntilIdle(); 98 LoginState::Initialize(); 99 network_state_handler_.reset(NetworkStateHandler::InitializeForTest()); 100 network_config_handler_.reset( 101 NetworkConfigurationHandler::InitializeForTest( 102 network_state_handler_.get())); 103 104 network_profile_handler_.reset(new NetworkProfileHandler()); 105 network_profile_handler_->Init(); 106 107 managed_config_handler_.reset(new ManagedNetworkConfigurationHandlerImpl()); 108 managed_config_handler_->Init(network_state_handler_.get(), 109 network_profile_handler_.get(), 110 network_config_handler_.get(), 111 NULL /* network_device_handler */); 112 113 network_connection_handler_.reset(new NetworkConnectionHandler); 114 network_connection_handler_->Init(network_state_handler_.get(), 115 network_config_handler_.get(), 116 managed_config_handler_.get()); 117 118 base::RunLoop().RunUntilIdle(); 119 } 120 121 virtual void TearDown() OVERRIDE { 122 managed_config_handler_.reset(); 123 network_profile_handler_.reset(); 124 network_connection_handler_.reset(); 125 network_config_handler_.reset(); 126 network_state_handler_.reset(); 127 CertLoader::Shutdown(); 128 TPMTokenLoader::Shutdown(); 129 LoginState::Shutdown(); 130 DBusThreadManager::Shutdown(); 131 } 132 133 protected: 134 bool Configure(const std::string& json_string) { 135 scoped_ptr<base::DictionaryValue> json_dict = 136 onc::ReadDictionaryFromJson(json_string); 137 if (!json_dict) { 138 LOG(ERROR) << "Error parsing json: " << json_string; 139 return false; 140 } 141 DBusThreadManager::Get()->GetShillManagerClient()->ConfigureService( 142 *json_dict, 143 base::Bind(&ConfigureCallback), 144 base::Bind(&ConfigureErrorCallback)); 145 base::RunLoop().RunUntilIdle(); 146 return true; 147 } 148 149 void Connect(const std::string& service_path) { 150 const bool check_error_state = true; 151 network_connection_handler_->ConnectToNetwork( 152 service_path, 153 base::Bind(&NetworkConnectionHandlerTest::SuccessCallback, 154 base::Unretained(this)), 155 base::Bind(&NetworkConnectionHandlerTest::ErrorCallback, 156 base::Unretained(this)), 157 check_error_state); 158 base::RunLoop().RunUntilIdle(); 159 } 160 161 void Disconnect(const std::string& service_path) { 162 network_connection_handler_->DisconnectNetwork( 163 service_path, 164 base::Bind(&NetworkConnectionHandlerTest::SuccessCallback, 165 base::Unretained(this)), 166 base::Bind(&NetworkConnectionHandlerTest::ErrorCallback, 167 base::Unretained(this))); 168 base::RunLoop().RunUntilIdle(); 169 } 170 171 void SuccessCallback() { 172 result_ = kSuccessResult; 173 } 174 175 void ErrorCallback(const std::string& error_name, 176 scoped_ptr<base::DictionaryValue> error_data) { 177 result_ = error_name; 178 } 179 180 std::string GetResultAndReset() { 181 std::string result; 182 result.swap(result_); 183 return result; 184 } 185 186 std::string GetServiceStringProperty(const std::string& service_path, 187 const std::string& key) { 188 std::string result; 189 const base::DictionaryValue* properties = 190 test_service_client_->GetServiceProperties(service_path); 191 if (properties) 192 properties->GetStringWithoutPathExpansion(key, &result); 193 return result; 194 } 195 196 void StartCertLoader() { 197 CertLoader::Get()->StartWithNSSDB(test_nssdb_.get()); 198 base::RunLoop().RunUntilIdle(); 199 } 200 201 void LoginToRegularUser() { 202 LoginState::Get()->SetLoggedInState(LoginState::LOGGED_IN_ACTIVE, 203 LoginState::LOGGED_IN_USER_REGULAR); 204 base::RunLoop().RunUntilIdle(); 205 } 206 207 scoped_refptr<net::X509Certificate> ImportTestClientCert() { 208 net::CertificateList ca_cert_list = 209 net::CreateCertificateListFromFile(net::GetTestCertsDirectory(), 210 "websocket_cacert.pem", 211 net::X509Certificate::FORMAT_AUTO); 212 if (ca_cert_list.empty()) { 213 LOG(ERROR) << "No CA cert loaded."; 214 return NULL; 215 } 216 net::NSSCertDatabase::ImportCertFailureList failures; 217 EXPECT_TRUE(test_nssdb_->ImportCACerts( 218 ca_cert_list, net::NSSCertDatabase::TRUST_DEFAULT, &failures)); 219 if (!failures.empty()) { 220 LOG(ERROR) << net::ErrorToString(failures[0].net_error); 221 return NULL; 222 } 223 224 std::string pkcs12_data; 225 base::FilePath pkcs12_path = 226 net::GetTestCertsDirectory().Append("websocket_client_cert.p12"); 227 if (!base::ReadFileToString(pkcs12_path, &pkcs12_data)) 228 return NULL; 229 230 net::CertificateList loaded_certs; 231 scoped_refptr<net::CryptoModule> module(net::CryptoModule::CreateFromHandle( 232 test_nssdb_->GetPrivateSlot().get())); 233 if (test_nssdb_->ImportFromPKCS12(module.get(), 234 pkcs12_data, 235 base::string16(), 236 false, 237 &loaded_certs) != net::OK) { 238 LOG(ERROR) << "Error while importing to NSSDB."; 239 return NULL; 240 } 241 242 // File contains two certs, the client cert first and the CA cert second. 243 if (loaded_certs.size() != 2U) { 244 LOG(ERROR) << "Expected two certs in file, found " << loaded_certs.size(); 245 return NULL; 246 } 247 return loaded_certs[0]; 248 } 249 250 void SetupPolicy(const std::string& network_configs_json, 251 const base::DictionaryValue& global_config, 252 bool user_policy) { 253 std::string error; 254 scoped_ptr<base::Value> network_configs_value( 255 base::JSONReader::ReadAndReturnError(network_configs_json, 256 base::JSON_ALLOW_TRAILING_COMMAS, 257 NULL, 258 &error)); 259 ASSERT_TRUE(network_configs_value) << error; 260 261 base::ListValue* network_configs = NULL; 262 ASSERT_TRUE(network_configs_value->GetAsList(&network_configs)); 263 264 if (user_policy) { 265 managed_config_handler_->SetPolicy( 266 ::onc::ONC_SOURCE_USER_POLICY, 267 user_.username_hash(), 268 *network_configs, 269 global_config); 270 } else { 271 managed_config_handler_->SetPolicy(::onc::ONC_SOURCE_DEVICE_POLICY, 272 std::string(), // no username hash 273 *network_configs, 274 global_config); 275 } 276 base::RunLoop().RunUntilIdle(); 277 } 278 279 scoped_ptr<NetworkStateHandler> network_state_handler_; 280 scoped_ptr<NetworkConfigurationHandler> network_config_handler_; 281 scoped_ptr<NetworkConnectionHandler> network_connection_handler_; 282 scoped_ptr<ManagedNetworkConfigurationHandlerImpl> managed_config_handler_; 283 scoped_ptr<NetworkProfileHandler> network_profile_handler_; 284 crypto::ScopedTestNSSChromeOSUser user_; 285 ShillManagerClient::TestInterface* test_manager_client_; 286 ShillServiceClient::TestInterface* test_service_client_; 287 scoped_ptr<net::NSSCertDatabaseChromeOS> test_nssdb_; 288 base::MessageLoopForUI message_loop_; 289 std::string result_; 290 291 private: 292 DISALLOW_COPY_AND_ASSIGN(NetworkConnectionHandlerTest); 293 }; 294 295 namespace { 296 297 const char* kConfigConnectable = 298 "{ \"GUID\": \"wifi0\", \"Type\": \"wifi\", \"State\": \"idle\", " 299 " \"Connectable\": true }"; 300 const char* kConfigConnected = 301 "{ \"GUID\": \"wifi1\", \"Type\": \"wifi\", \"State\": \"online\" }"; 302 const char* kConfigConnecting = 303 "{ \"GUID\": \"wifi2\", \"Type\": \"wifi\", \"State\": \"association\" }"; 304 const char* kConfigRequiresPassphrase = 305 "{ \"GUID\": \"wifi3\", \"Type\": \"wifi\", " 306 " \"PassphraseRequired\": true }"; 307 308 } // namespace 309 310 TEST_F(NetworkConnectionHandlerTest, NetworkConnectionHandlerConnectSuccess) { 311 EXPECT_TRUE(Configure(kConfigConnectable)); 312 Connect("wifi0"); 313 EXPECT_EQ(kSuccessResult, GetResultAndReset()); 314 EXPECT_EQ(shill::kStateOnline, 315 GetServiceStringProperty("wifi0", shill::kStateProperty)); 316 } 317 318 // Handles basic failure cases. 319 TEST_F(NetworkConnectionHandlerTest, NetworkConnectionHandlerConnectFailure) { 320 Connect("no-network"); 321 EXPECT_EQ(NetworkConnectionHandler::kErrorConfigureFailed, 322 GetResultAndReset()); 323 324 EXPECT_TRUE(Configure(kConfigConnected)); 325 Connect("wifi1"); 326 EXPECT_EQ(NetworkConnectionHandler::kErrorConnected, GetResultAndReset()); 327 328 EXPECT_TRUE(Configure(kConfigConnecting)); 329 Connect("wifi2"); 330 EXPECT_EQ(NetworkConnectionHandler::kErrorConnecting, GetResultAndReset()); 331 332 EXPECT_TRUE(Configure(kConfigRequiresPassphrase)); 333 Connect("wifi3"); 334 EXPECT_EQ(NetworkConnectionHandler::kErrorPassphraseRequired, 335 GetResultAndReset()); 336 } 337 338 namespace { 339 340 const char* kPolicyWithCertPatternTemplate = 341 "[ { \"GUID\": \"wifi4\"," 342 " \"Name\": \"wifi4\"," 343 " \"Type\": \"WiFi\"," 344 " \"WiFi\": {" 345 " \"Security\": \"WPA-EAP\"," 346 " \"SSID\": \"wifi_ssid\"," 347 " \"EAP\": {" 348 " \"Outer\": \"EAP-TLS\"," 349 " \"ClientCertType\": \"Pattern\"," 350 " \"ClientCertPattern\": {" 351 " \"Subject\": {" 352 " \"CommonName\" : \"%s\"" 353 " }" 354 " }" 355 " }" 356 " }" 357 "} ]"; 358 359 } // namespace 360 361 // Handle certificates. 362 TEST_F(NetworkConnectionHandlerTest, ConnectCertificateMissing) { 363 StartCertLoader(); 364 SetupPolicy(base::StringPrintf(kPolicyWithCertPatternTemplate, "unknown"), 365 base::DictionaryValue(), // no global config 366 true); // load as user policy 367 368 Connect("wifi4"); 369 EXPECT_EQ(NetworkConnectionHandler::kErrorCertificateRequired, 370 GetResultAndReset()); 371 } 372 373 TEST_F(NetworkConnectionHandlerTest, ConnectWithCertificateSuccess) { 374 StartCertLoader(); 375 scoped_refptr<net::X509Certificate> cert = ImportTestClientCert(); 376 ASSERT_TRUE(cert.get()); 377 378 SetupPolicy(base::StringPrintf(kPolicyWithCertPatternTemplate, 379 cert->subject().common_name.c_str()), 380 base::DictionaryValue(), // no global config 381 true); // load as user policy 382 383 Connect("wifi4"); 384 EXPECT_EQ(kSuccessResult, GetResultAndReset()); 385 } 386 387 // Disabled, see http://crbug.com/396729. 388 TEST_F(NetworkConnectionHandlerTest, 389 DISABLED_ConnectWithCertificateRequestedBeforeCertsAreLoaded) { 390 scoped_refptr<net::X509Certificate> cert = ImportTestClientCert(); 391 ASSERT_TRUE(cert.get()); 392 393 SetupPolicy(base::StringPrintf(kPolicyWithCertPatternTemplate, 394 cert->subject().common_name.c_str()), 395 base::DictionaryValue(), // no global config 396 true); // load as user policy 397 398 Connect("wifi4"); 399 400 // Connect request came before the cert loader loaded certificates, so the 401 // connect request should have been throttled until the certificates are 402 // loaded. 403 EXPECT_EQ("", GetResultAndReset()); 404 405 StartCertLoader(); 406 407 // |StartCertLoader| should have triggered certificate loading. 408 // When the certificates got loaded, the connection request should have 409 // proceeded and eventually succeeded. 410 EXPECT_EQ(kSuccessResult, GetResultAndReset()); 411 } 412 413 TEST_F(NetworkConnectionHandlerTest, 414 NetworkConnectionHandlerDisconnectSuccess) { 415 EXPECT_TRUE(Configure(kConfigConnected)); 416 Disconnect("wifi1"); 417 EXPECT_EQ(kSuccessResult, GetResultAndReset()); 418 } 419 420 TEST_F(NetworkConnectionHandlerTest, 421 NetworkConnectionHandlerDisconnectFailure) { 422 Connect("no-network"); 423 EXPECT_EQ(NetworkConnectionHandler::kErrorConfigureFailed, 424 GetResultAndReset()); 425 426 EXPECT_TRUE(Configure(kConfigConnectable)); 427 Disconnect("wifi0"); 428 EXPECT_EQ(NetworkConnectionHandler::kErrorNotConnected, GetResultAndReset()); 429 } 430 431 namespace { 432 433 const char* kConfigUnmanagedSharedConnected = 434 "{ \"GUID\": \"wifi0\", \"Type\": \"wifi\", \"State\": \"online\" }"; 435 const char* kConfigManagedSharedConnectable = 436 "{ \"GUID\": \"wifi1\", \"Type\": \"wifi\", \"State\": \"idle\", " 437 " \"Connectable\": true }"; 438 439 const char* kPolicy = 440 "[ { \"GUID\": \"wifi1\"," 441 " \"Name\": \"wifi1\"," 442 " \"Type\": \"WiFi\"," 443 " \"WiFi\": {" 444 " \"Security\": \"WPA-PSK\"," 445 " \"SSID\": \"wifi1\"," 446 " \"Passphrase\": \"passphrase\"" 447 " }" 448 "} ]"; 449 450 } // namespace 451 452 TEST_F(NetworkConnectionHandlerTest, ReconnectOnLoginEarlyPolicyLoading) { 453 EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected)); 454 EXPECT_TRUE(Configure(kConfigManagedSharedConnectable)); 455 test_manager_client_->SetBestServiceToConnect("wifi1"); 456 457 // User login shouldn't trigger any change because policy is not loaded yet. 458 LoginToRegularUser(); 459 EXPECT_EQ(shill::kStateOnline, 460 GetServiceStringProperty("wifi0", shill::kStateProperty)); 461 EXPECT_EQ(shill::kStateIdle, 462 GetServiceStringProperty("wifi1", shill::kStateProperty)); 463 464 // Applying the policy which restricts autoconnect should disconnect from the 465 // shared, unmanaged network. 466 base::DictionaryValue global_config; 467 global_config.SetBooleanWithoutPathExpansion( 468 ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect, 469 true); 470 471 SetupPolicy(kPolicy, global_config, false /* load as device policy */); 472 EXPECT_EQ(shill::kStateIdle, 473 GetServiceStringProperty("wifi0", shill::kStateProperty)); 474 EXPECT_EQ(shill::kStateIdle, 475 GetServiceStringProperty("wifi1", shill::kStateProperty)); 476 477 // Certificate loading should trigger connecting to the 'best' network. 478 StartCertLoader(); 479 EXPECT_EQ(shill::kStateIdle, 480 GetServiceStringProperty("wifi0", shill::kStateProperty)); 481 EXPECT_EQ(shill::kStateOnline, 482 GetServiceStringProperty("wifi1", shill::kStateProperty)); 483 } 484 485 TEST_F(NetworkConnectionHandlerTest, ReconnectOnLoginLatePolicyLoading) { 486 EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected)); 487 EXPECT_TRUE(Configure(kConfigManagedSharedConnectable)); 488 test_manager_client_->SetBestServiceToConnect("wifi1"); 489 490 // User login and certificate loading shouldn't trigger any change until the 491 // policy is loaded. 492 LoginToRegularUser(); 493 StartCertLoader(); 494 EXPECT_EQ(shill::kStateOnline, 495 GetServiceStringProperty("wifi0", shill::kStateProperty)); 496 EXPECT_EQ(shill::kStateIdle, 497 GetServiceStringProperty("wifi1", shill::kStateProperty)); 498 499 // Applying the policy which restricts autoconnect should disconnect from the 500 // shared, unmanaged network. 501 base::DictionaryValue global_config; 502 global_config.SetBooleanWithoutPathExpansion( 503 ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect, 504 true); 505 506 SetupPolicy(kPolicy, global_config, false /* load as device policy */); 507 EXPECT_EQ(shill::kStateIdle, 508 GetServiceStringProperty("wifi0", shill::kStateProperty)); 509 EXPECT_EQ(shill::kStateOnline, 510 GetServiceStringProperty("wifi1", shill::kStateProperty)); 511 } 512 513 } // namespace chromeos 514