Fix race condition in gyp/ninja builds.
[chromium-blink-merge.git] / chromeos / network / network_connection_handler_unittest.cc
bloba615694c3de7b7ddf825dd4562f69da6f9e4e2ee
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.
5 #include "chromeos/network/network_connection_handler.h"
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"
38 namespace {
40 const char* kSuccessResult = "success";
42 void ConfigureCallback(const dbus::ObjectPath& result) {
45 void ConfigureErrorCallback(const std::string& error_name,
46 const std::string& error_message) {
49 } // namespace
51 namespace chromeos {
53 class NetworkConnectionHandlerTest : public testing::Test {
54 public:
55 NetworkConnectionHandlerTest()
56 : user_("userhash"),
57 test_manager_client_(NULL),
58 test_service_client_(NULL) {}
60 virtual ~NetworkConnectionHandlerTest() {
63 virtual void SetUp() OVERRIDE {
64 ASSERT_TRUE(user_.constructed_successfully());
65 user_.FinishInit();
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());
74 TPMTokenLoader::InitializeForTest();
76 CertLoader::Initialize();
77 CertLoader* cert_loader = CertLoader::Get();
78 cert_loader->force_hardware_backed_for_test();
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();
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 "shared_profile_path", std::string() /* shared profile */);
95 dbus_manager->GetShillProfileClient()->GetTestInterface()->AddProfile(
96 "user_profile_path", user_.username_hash());
98 base::RunLoop().RunUntilIdle();
99 LoginState::Initialize();
100 network_state_handler_.reset(NetworkStateHandler::InitializeForTest());
101 network_config_handler_.reset(
102 NetworkConfigurationHandler::InitializeForTest(
103 network_state_handler_.get()));
105 network_profile_handler_.reset(new NetworkProfileHandler());
106 network_profile_handler_->Init();
108 managed_config_handler_.reset(new ManagedNetworkConfigurationHandlerImpl());
109 managed_config_handler_->Init(network_state_handler_.get(),
110 network_profile_handler_.get(),
111 network_config_handler_.get(),
112 NULL /* network_device_handler */);
114 network_connection_handler_.reset(new NetworkConnectionHandler);
115 network_connection_handler_->Init(network_state_handler_.get(),
116 network_config_handler_.get(),
117 managed_config_handler_.get());
119 base::RunLoop().RunUntilIdle();
122 virtual void TearDown() OVERRIDE {
123 managed_config_handler_.reset();
124 network_profile_handler_.reset();
125 network_connection_handler_.reset();
126 network_config_handler_.reset();
127 network_state_handler_.reset();
128 CertLoader::Shutdown();
129 TPMTokenLoader::Shutdown();
130 LoginState::Shutdown();
131 DBusThreadManager::Shutdown();
134 protected:
135 bool Configure(const std::string& json_string) {
136 scoped_ptr<base::DictionaryValue> json_dict =
137 onc::ReadDictionaryFromJson(json_string);
138 if (!json_dict) {
139 LOG(ERROR) << "Error parsing json: " << json_string;
140 return false;
142 DBusThreadManager::Get()->GetShillManagerClient()->ConfigureService(
143 *json_dict,
144 base::Bind(&ConfigureCallback),
145 base::Bind(&ConfigureErrorCallback));
146 base::RunLoop().RunUntilIdle();
147 return true;
150 void Connect(const std::string& service_path) {
151 const bool check_error_state = true;
152 network_connection_handler_->ConnectToNetwork(
153 service_path,
154 base::Bind(&NetworkConnectionHandlerTest::SuccessCallback,
155 base::Unretained(this)),
156 base::Bind(&NetworkConnectionHandlerTest::ErrorCallback,
157 base::Unretained(this)),
158 check_error_state);
159 base::RunLoop().RunUntilIdle();
162 void Disconnect(const std::string& service_path) {
163 network_connection_handler_->DisconnectNetwork(
164 service_path,
165 base::Bind(&NetworkConnectionHandlerTest::SuccessCallback,
166 base::Unretained(this)),
167 base::Bind(&NetworkConnectionHandlerTest::ErrorCallback,
168 base::Unretained(this)));
169 base::RunLoop().RunUntilIdle();
172 void SuccessCallback() {
173 result_ = kSuccessResult;
176 void ErrorCallback(const std::string& error_name,
177 scoped_ptr<base::DictionaryValue> error_data) {
178 result_ = error_name;
181 std::string GetResultAndReset() {
182 std::string result;
183 result.swap(result_);
184 return result;
187 std::string GetServiceStringProperty(const std::string& service_path,
188 const std::string& key) {
189 std::string result;
190 const base::DictionaryValue* properties =
191 test_service_client_->GetServiceProperties(service_path);
192 if (properties)
193 properties->GetStringWithoutPathExpansion(key, &result);
194 return result;
197 void StartCertLoader() {
198 CertLoader::Get()->StartWithNSSDB(test_nssdb_.get());
199 base::RunLoop().RunUntilIdle();
202 void LoginToRegularUser() {
203 LoginState::Get()->SetLoggedInState(LoginState::LOGGED_IN_ACTIVE,
204 LoginState::LOGGED_IN_USER_REGULAR);
205 base::RunLoop().RunUntilIdle();
208 void ImportClientCertAndKey(const std::string& pkcs12_file,
209 net::NSSCertDatabase* nssdb,
210 net::CertificateList* loaded_certs) {
211 std::string pkcs12_data;
212 base::FilePath pkcs12_path =
213 net::GetTestCertsDirectory().Append(pkcs12_file);
214 ASSERT_TRUE(base::ReadFileToString(pkcs12_path, &pkcs12_data));
216 scoped_refptr<net::CryptoModule> module(
217 net::CryptoModule::CreateFromHandle(nssdb->GetPrivateSlot().get()));
218 ASSERT_EQ(
219 net::OK,
220 nssdb->ImportFromPKCS12(module, pkcs12_data, base::string16(), false,
221 loaded_certs));
222 ASSERT_EQ(1U, loaded_certs->size());
225 void SetupPolicy(const std::string& network_configs_json,
226 const base::DictionaryValue& global_config,
227 bool user_policy) {
228 std::string error;
229 scoped_ptr<base::Value> network_configs_value(
230 base::JSONReader::ReadAndReturnError(network_configs_json,
231 base::JSON_ALLOW_TRAILING_COMMAS,
232 NULL,
233 &error));
234 ASSERT_TRUE(network_configs_value) << error;
236 base::ListValue* network_configs = NULL;
237 ASSERT_TRUE(network_configs_value->GetAsList(&network_configs));
239 if (user_policy) {
240 managed_config_handler_->SetPolicy(
241 ::onc::ONC_SOURCE_USER_POLICY,
242 user_.username_hash(),
243 *network_configs,
244 global_config);
245 } else {
246 managed_config_handler_->SetPolicy(::onc::ONC_SOURCE_DEVICE_POLICY,
247 std::string(), // no username hash
248 *network_configs,
249 global_config);
251 base::RunLoop().RunUntilIdle();
254 scoped_ptr<NetworkStateHandler> network_state_handler_;
255 scoped_ptr<NetworkConfigurationHandler> network_config_handler_;
256 scoped_ptr<NetworkConnectionHandler> network_connection_handler_;
257 scoped_ptr<ManagedNetworkConfigurationHandlerImpl> managed_config_handler_;
258 scoped_ptr<NetworkProfileHandler> network_profile_handler_;
259 crypto::ScopedTestNSSChromeOSUser user_;
260 ShillManagerClient::TestInterface* test_manager_client_;
261 ShillServiceClient::TestInterface* test_service_client_;
262 scoped_ptr<net::NSSCertDatabaseChromeOS> test_nssdb_;
263 base::MessageLoopForUI message_loop_;
264 std::string result_;
266 private:
267 DISALLOW_COPY_AND_ASSIGN(NetworkConnectionHandlerTest);
270 namespace {
272 const char* kConfigConnectable =
273 "{ \"GUID\": \"wifi0\", \"Type\": \"wifi\", \"State\": \"idle\", "
274 " \"Connectable\": true }";
275 const char* kConfigConnected =
276 "{ \"GUID\": \"wifi1\", \"Type\": \"wifi\", \"State\": \"online\" }";
277 const char* kConfigConnecting =
278 "{ \"GUID\": \"wifi2\", \"Type\": \"wifi\", \"State\": \"association\" }";
279 const char* kConfigRequiresPassphrase =
280 "{ \"GUID\": \"wifi3\", \"Type\": \"wifi\", "
281 " \"PassphraseRequired\": true }";
282 const char* kConfigRequiresActivation =
283 "{ \"GUID\": \"cellular1\", \"Type\": \"cellular\","
284 " \"Cellular.ActivationState\": \"not-activated\" }";
286 } // namespace
288 TEST_F(NetworkConnectionHandlerTest, NetworkConnectionHandlerConnectSuccess) {
289 EXPECT_TRUE(Configure(kConfigConnectable));
290 Connect("wifi0");
291 EXPECT_EQ(kSuccessResult, GetResultAndReset());
292 EXPECT_EQ(shill::kStateOnline,
293 GetServiceStringProperty("wifi0", shill::kStateProperty));
296 // Handles basic failure cases.
297 TEST_F(NetworkConnectionHandlerTest, NetworkConnectionHandlerConnectFailure) {
298 Connect("no-network");
299 EXPECT_EQ(NetworkConnectionHandler::kErrorConfigureFailed,
300 GetResultAndReset());
302 EXPECT_TRUE(Configure(kConfigConnected));
303 Connect("wifi1");
304 EXPECT_EQ(NetworkConnectionHandler::kErrorConnected, GetResultAndReset());
306 EXPECT_TRUE(Configure(kConfigConnecting));
307 Connect("wifi2");
308 EXPECT_EQ(NetworkConnectionHandler::kErrorConnecting, GetResultAndReset());
310 EXPECT_TRUE(Configure(kConfigRequiresPassphrase));
311 Connect("wifi3");
312 EXPECT_EQ(NetworkConnectionHandler::kErrorPassphraseRequired,
313 GetResultAndReset());
315 EXPECT_TRUE(Configure(kConfigRequiresActivation));
316 Connect("cellular1");
317 EXPECT_EQ(NetworkConnectionHandler::kErrorActivationRequired,
318 GetResultAndReset());
321 namespace {
323 const char* kPolicyWithCertPatternTemplate =
324 "[ { \"GUID\": \"wifi4\","
325 " \"Name\": \"wifi4\","
326 " \"Type\": \"WiFi\","
327 " \"WiFi\": {"
328 " \"Security\": \"WPA-EAP\","
329 " \"SSID\": \"wifi_ssid\","
330 " \"EAP\": {"
331 " \"Outer\": \"EAP-TLS\","
332 " \"ClientCertType\": \"Pattern\","
333 " \"ClientCertPattern\": {"
334 " \"Subject\": {"
335 " \"CommonName\" : \"%s\""
336 " }"
337 " }"
338 " }"
339 " }"
340 "} ]";
342 } // namespace
344 // Handle certificates.
345 TEST_F(NetworkConnectionHandlerTest, ConnectCertificateMissing) {
346 StartCertLoader();
347 SetupPolicy(base::StringPrintf(kPolicyWithCertPatternTemplate, "unknown"),
348 base::DictionaryValue(), // no global config
349 true); // load as user policy
351 Connect("wifi4");
352 EXPECT_EQ(NetworkConnectionHandler::kErrorCertificateRequired,
353 GetResultAndReset());
356 TEST_F(NetworkConnectionHandlerTest, ConnectWithCertificateSuccess) {
357 StartCertLoader();
359 net::CertificateList certs;
360 ImportClientCertAndKey("websocket_client_cert.p12",
361 test_nssdb_.get(),
362 &certs);
364 SetupPolicy(base::StringPrintf(kPolicyWithCertPatternTemplate,
365 certs[0]->subject().common_name.c_str()),
366 base::DictionaryValue(), // no global config
367 true); // load as user policy
369 Connect("wifi4");
370 EXPECT_EQ(kSuccessResult, GetResultAndReset());
373 TEST_F(NetworkConnectionHandlerTest,
374 ConnectWithCertificateRequestedBeforeCertsAreLoaded) {
375 net::CertificateList certs;
376 ImportClientCertAndKey("websocket_client_cert.p12",
377 test_nssdb_.get(),
378 &certs);
380 SetupPolicy(base::StringPrintf(kPolicyWithCertPatternTemplate,
381 certs[0]->subject().common_name.c_str()),
382 base::DictionaryValue(), // no global config
383 true); // load as user policy
385 Connect("wifi4");
387 // Connect request came before the cert loader loaded certificates, so the
388 // connect request should have been throttled until the certificates are
389 // loaded.
390 EXPECT_EQ("", GetResultAndReset());
392 StartCertLoader();
394 // |StartCertLoader| should have triggered certificate loading.
395 // When the certificates got loaded, the connection request should have
396 // proceeded and eventually succeeded.
397 EXPECT_EQ(kSuccessResult, GetResultAndReset());
400 TEST_F(NetworkConnectionHandlerTest,
401 NetworkConnectionHandlerDisconnectSuccess) {
402 EXPECT_TRUE(Configure(kConfigConnected));
403 Disconnect("wifi1");
404 EXPECT_EQ(kSuccessResult, GetResultAndReset());
407 TEST_F(NetworkConnectionHandlerTest,
408 NetworkConnectionHandlerDisconnectFailure) {
409 Connect("no-network");
410 EXPECT_EQ(NetworkConnectionHandler::kErrorConfigureFailed,
411 GetResultAndReset());
413 EXPECT_TRUE(Configure(kConfigConnectable));
414 Disconnect("wifi0");
415 EXPECT_EQ(NetworkConnectionHandler::kErrorNotConnected, GetResultAndReset());
418 namespace {
420 const char* kConfigUnmanagedSharedConnected =
421 "{ \"GUID\": \"wifi0\", \"Type\": \"wifi\", \"State\": \"online\" }";
422 const char* kConfigManagedSharedConnectable =
423 "{ \"GUID\": \"wifi1\", \"Type\": \"wifi\", \"State\": \"idle\", "
424 " \"Connectable\": true }";
426 const char* kPolicy =
427 "[ { \"GUID\": \"wifi1\","
428 " \"Name\": \"wifi1\","
429 " \"Type\": \"WiFi\","
430 " \"WiFi\": {"
431 " \"Security\": \"WPA-PSK\","
432 " \"SSID\": \"wifi1\","
433 " \"Passphrase\": \"passphrase\""
434 " }"
435 "} ]";
437 } // namespace
439 TEST_F(NetworkConnectionHandlerTest, ReconnectOnLoginEarlyPolicyLoading) {
440 EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected));
441 EXPECT_TRUE(Configure(kConfigManagedSharedConnectable));
442 test_manager_client_->SetBestServiceToConnect("wifi1");
444 // User login shouldn't trigger any change because policy is not loaded yet.
445 LoginToRegularUser();
446 EXPECT_EQ(shill::kStateOnline,
447 GetServiceStringProperty("wifi0", shill::kStateProperty));
448 EXPECT_EQ(shill::kStateIdle,
449 GetServiceStringProperty("wifi1", shill::kStateProperty));
451 // Applying the policy which restricts autoconnect should disconnect from the
452 // shared, unmanaged network.
453 base::DictionaryValue global_config;
454 global_config.SetBooleanWithoutPathExpansion(
455 ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect,
456 true);
458 SetupPolicy(kPolicy, global_config, false /* load as device policy */);
459 EXPECT_EQ(shill::kStateIdle,
460 GetServiceStringProperty("wifi0", shill::kStateProperty));
461 EXPECT_EQ(shill::kStateIdle,
462 GetServiceStringProperty("wifi1", shill::kStateProperty));
464 // Certificate loading should trigger connecting to the 'best' network.
465 StartCertLoader();
466 EXPECT_EQ(shill::kStateIdle,
467 GetServiceStringProperty("wifi0", shill::kStateProperty));
468 EXPECT_EQ(shill::kStateOnline,
469 GetServiceStringProperty("wifi1", shill::kStateProperty));
472 TEST_F(NetworkConnectionHandlerTest, ReconnectOnLoginLatePolicyLoading) {
473 EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected));
474 EXPECT_TRUE(Configure(kConfigManagedSharedConnectable));
475 test_manager_client_->SetBestServiceToConnect("wifi1");
477 // User login and certificate loading shouldn't trigger any change until the
478 // policy is loaded.
479 LoginToRegularUser();
480 StartCertLoader();
481 EXPECT_EQ(shill::kStateOnline,
482 GetServiceStringProperty("wifi0", shill::kStateProperty));
483 EXPECT_EQ(shill::kStateIdle,
484 GetServiceStringProperty("wifi1", shill::kStateProperty));
486 // Applying the policy which restricts autoconnect should disconnect from the
487 // shared, unmanaged network.
488 base::DictionaryValue global_config;
489 global_config.SetBooleanWithoutPathExpansion(
490 ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect,
491 true);
493 SetupPolicy(kPolicy, global_config, false /* load as device policy */);
494 EXPECT_EQ(shill::kStateIdle,
495 GetServiceStringProperty("wifi0", shill::kStateProperty));
496 EXPECT_EQ(shill::kStateOnline,
497 GetServiceStringProperty("wifi1", shill::kStateProperty));
500 } // namespace chromeos