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"
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/files/file_util.h"
13 #include "base/json/json_reader.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/run_loop.h"
17 #include "base/strings/stringprintf.h"
18 #include "chromeos/cert_loader.h"
19 #include "chromeos/dbus/dbus_thread_manager.h"
20 #include "chromeos/dbus/shill_device_client.h"
21 #include "chromeos/dbus/shill_manager_client.h"
22 #include "chromeos/dbus/shill_profile_client.h"
23 #include "chromeos/dbus/shill_service_client.h"
24 #include "chromeos/network/managed_network_configuration_handler_impl.h"
25 #include "chromeos/network/network_configuration_handler.h"
26 #include "chromeos/network/network_connection_observer.h"
27 #include "chromeos/network/network_profile_handler.h"
28 #include "chromeos/network/network_state_handler.h"
29 #include "chromeos/network/onc/onc_utils.h"
30 #include "components/onc/onc_constants.h"
31 #include "crypto/scoped_nss_types.h"
32 #include "crypto/scoped_test_nss_db.h"
33 #include "net/base/net_errors.h"
34 #include "net/base/test_data_directory.h"
35 #include "net/cert/nss_cert_database_chromeos.h"
36 #include "net/cert/x509_certificate.h"
37 #include "net/test/cert_test_util.h"
38 #include "testing/gtest/include/gtest/gtest.h"
39 #include "third_party/cros_system_api/dbus/service_constants.h"
45 const char* kSuccessResult
= "success";
46 const char* kUsernameHash
= "userhash";
48 void ConfigureCallback(const dbus::ObjectPath
& result
) {
51 void ConfigureErrorCallback(const std::string
& error_name
,
52 const std::string
& error_message
) {
55 class TestNetworkConnectionObserver
: public NetworkConnectionObserver
{
57 TestNetworkConnectionObserver() {}
58 ~TestNetworkConnectionObserver() override
{}
60 // NetworkConnectionObserver
61 void ConnectToNetworkRequested(const std::string
& service_path
) override
{
62 requests_
.insert(service_path
);
65 void ConnectSucceeded(const std::string
& service_path
) override
{
66 results_
[service_path
] = kSuccessResult
;
69 void ConnectFailed(const std::string
& service_path
,
70 const std::string
& error_name
) override
{
71 results_
[service_path
] = error_name
;
74 void DisconnectRequested(const std::string
& service_path
) override
{
75 requests_
.insert(service_path
);
78 bool GetRequested(const std::string
& service_path
) {
79 return requests_
.count(service_path
) != 0;
82 std::string
GetResult(const std::string
& service_path
) {
83 auto iter
= results_
.find(service_path
);
84 if (iter
== results_
.end())
90 std::set
<std::string
> requests_
;
91 std::map
<std::string
, std::string
> results_
;
93 DISALLOW_COPY_AND_ASSIGN(TestNetworkConnectionObserver
);
98 class NetworkConnectionHandlerTest
: public testing::Test
{
100 NetworkConnectionHandlerTest()
101 : test_manager_client_(nullptr), test_service_client_(nullptr) {}
103 ~NetworkConnectionHandlerTest() override
{}
105 void SetUp() override
{
106 ASSERT_TRUE(test_nssdb_
.is_open());
108 // Use the same DB for public and private slot.
109 test_nsscertdb_
.reset(new net::NSSCertDatabaseChromeOS(
110 crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_
.slot())),
111 crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_
.slot()))));
112 test_nsscertdb_
->SetSlowTaskRunnerForTest(message_loop_
.task_runner());
114 CertLoader::Initialize();
115 CertLoader::ForceHardwareBackedForTesting();
117 DBusThreadManager::Initialize();
118 DBusThreadManager
* dbus_manager
= DBusThreadManager::Get();
119 test_manager_client_
=
120 dbus_manager
->GetShillManagerClient()->GetTestInterface();
121 test_service_client_
=
122 dbus_manager
->GetShillServiceClient()->GetTestInterface();
124 test_manager_client_
->AddTechnology(shill::kTypeWifi
, true /* enabled */);
125 dbus_manager
->GetShillDeviceClient()->GetTestInterface()->AddDevice(
126 "/device/wifi1", shill::kTypeWifi
, "wifi_device1");
127 test_manager_client_
->AddTechnology(shill::kTypeCellular
,
129 dbus_manager
->GetShillProfileClient()->GetTestInterface()->AddProfile(
130 "shared_profile_path", std::string() /* shared profile */);
131 dbus_manager
->GetShillProfileClient()->GetTestInterface()->AddProfile(
132 "user_profile_path", kUsernameHash
);
134 base::RunLoop().RunUntilIdle();
135 LoginState::Initialize();
136 network_state_handler_
.reset(NetworkStateHandler::InitializeForTest());
137 network_config_handler_
.reset(
138 NetworkConfigurationHandler::InitializeForTest(
139 network_state_handler_
.get(),
140 nullptr /* network_device_handler */));
142 network_profile_handler_
.reset(new NetworkProfileHandler());
143 network_profile_handler_
->Init();
145 managed_config_handler_
.reset(new ManagedNetworkConfigurationHandlerImpl());
146 managed_config_handler_
->Init(
147 network_state_handler_
.get(), network_profile_handler_
.get(),
148 network_config_handler_
.get(), nullptr /* network_device_handler */);
150 network_connection_handler_
.reset(new NetworkConnectionHandler
);
151 network_connection_handler_
->Init(network_state_handler_
.get(),
152 network_config_handler_
.get(),
153 managed_config_handler_
.get());
154 network_connection_observer_
.reset(new TestNetworkConnectionObserver
);
155 network_connection_handler_
->AddObserver(
156 network_connection_observer_
.get());
158 base::RunLoop().RunUntilIdle();
161 void TearDown() override
{
162 managed_config_handler_
.reset();
163 network_profile_handler_
.reset();
164 network_connection_handler_
->RemoveObserver(
165 network_connection_observer_
.get());
166 network_connection_observer_
.reset();
167 network_connection_handler_
.reset();
168 network_config_handler_
.reset();
169 network_state_handler_
.reset();
170 CertLoader::Shutdown();
171 LoginState::Shutdown();
172 DBusThreadManager::Shutdown();
176 bool Configure(const std::string
& json_string
) {
177 scoped_ptr
<base::DictionaryValue
> json_dict
=
178 onc::ReadDictionaryFromJson(json_string
);
180 LOG(ERROR
) << "Error parsing json: " << json_string
;
183 DBusThreadManager::Get()->GetShillManagerClient()->ConfigureService(
185 base::Bind(&ConfigureCallback
),
186 base::Bind(&ConfigureErrorCallback
));
187 base::RunLoop().RunUntilIdle();
191 void Connect(const std::string
& service_path
) {
192 const bool check_error_state
= true;
193 network_connection_handler_
->ConnectToNetwork(
195 base::Bind(&NetworkConnectionHandlerTest::SuccessCallback
,
196 base::Unretained(this)),
197 base::Bind(&NetworkConnectionHandlerTest::ErrorCallback
,
198 base::Unretained(this)),
200 base::RunLoop().RunUntilIdle();
203 void Disconnect(const std::string
& service_path
) {
204 network_connection_handler_
->DisconnectNetwork(
206 base::Bind(&NetworkConnectionHandlerTest::SuccessCallback
,
207 base::Unretained(this)),
208 base::Bind(&NetworkConnectionHandlerTest::ErrorCallback
,
209 base::Unretained(this)));
210 base::RunLoop().RunUntilIdle();
213 void SuccessCallback() {
214 result_
= kSuccessResult
;
217 void ErrorCallback(const std::string
& error_name
,
218 scoped_ptr
<base::DictionaryValue
> error_data
) {
219 result_
= error_name
;
222 std::string
GetResultAndReset() {
224 result
.swap(result_
);
228 std::string
GetServiceStringProperty(const std::string
& service_path
,
229 const std::string
& key
) {
231 const base::DictionaryValue
* properties
=
232 test_service_client_
->GetServiceProperties(service_path
);
234 properties
->GetStringWithoutPathExpansion(key
, &result
);
238 void StartCertLoader() {
239 CertLoader::Get()->StartWithNSSDB(test_nsscertdb_
.get());
240 base::RunLoop().RunUntilIdle();
243 void LoginToRegularUser() {
244 LoginState::Get()->SetLoggedInState(LoginState::LOGGED_IN_ACTIVE
,
245 LoginState::LOGGED_IN_USER_REGULAR
);
246 base::RunLoop().RunUntilIdle();
249 scoped_refptr
<net::X509Certificate
> ImportTestClientCert() {
250 net::CertificateList
ca_cert_list(net::CreateCertificateListFromFile(
251 net::GetTestCertsDirectory(), "client_1_ca.pem",
252 net::X509Certificate::FORMAT_AUTO
));
253 if (ca_cert_list
.empty()) {
254 LOG(ERROR
) << "No CA cert loaded.";
257 net::NSSCertDatabase::ImportCertFailureList failures
;
258 EXPECT_TRUE(test_nsscertdb_
->ImportCACerts(
259 ca_cert_list
, net::NSSCertDatabase::TRUST_DEFAULT
, &failures
));
260 if (!failures
.empty()) {
261 LOG(ERROR
) << net::ErrorToString(failures
[0].net_error
);
265 // Import a client cert signed by that CA.
266 scoped_refptr
<net::X509Certificate
> client_cert(
267 net::ImportClientCertAndKeyFromFile(net::GetTestCertsDirectory(),
268 "client_1.pem", "client_1.pk8",
269 test_nssdb_
.slot()));
273 void SetupPolicy(const std::string
& network_configs_json
,
274 const base::DictionaryValue
& global_config
,
277 scoped_ptr
<base::Value
> network_configs_value
=
278 base::JSONReader::ReadAndReturnError(network_configs_json
,
279 base::JSON_ALLOW_TRAILING_COMMAS
,
281 ASSERT_TRUE(network_configs_value
) << error
;
283 base::ListValue
* network_configs
= nullptr;
284 ASSERT_TRUE(network_configs_value
->GetAsList(&network_configs
));
287 managed_config_handler_
->SetPolicy(::onc::ONC_SOURCE_USER_POLICY
,
288 kUsernameHash
, *network_configs
,
291 managed_config_handler_
->SetPolicy(::onc::ONC_SOURCE_DEVICE_POLICY
,
292 std::string(), // no username hash
296 base::RunLoop().RunUntilIdle();
299 scoped_ptr
<NetworkStateHandler
> network_state_handler_
;
300 scoped_ptr
<NetworkConfigurationHandler
> network_config_handler_
;
301 scoped_ptr
<NetworkConnectionHandler
> network_connection_handler_
;
302 scoped_ptr
<TestNetworkConnectionObserver
> network_connection_observer_
;
303 scoped_ptr
<ManagedNetworkConfigurationHandlerImpl
> managed_config_handler_
;
304 scoped_ptr
<NetworkProfileHandler
> network_profile_handler_
;
305 ShillManagerClient::TestInterface
* test_manager_client_
;
306 ShillServiceClient::TestInterface
* test_service_client_
;
307 crypto::ScopedTestNSSDB test_nssdb_
;
308 scoped_ptr
<net::NSSCertDatabaseChromeOS
> test_nsscertdb_
;
309 base::MessageLoopForUI message_loop_
;
313 DISALLOW_COPY_AND_ASSIGN(NetworkConnectionHandlerTest
);
318 const char* kNoNetwork
= "no-network";
319 const char* kWifi0
= "wifi0";
320 const char* kWifi1
= "wifi1";
321 const char* kWifi2
= "wifi2";
322 const char* kWifi3
= "wifi3";
324 const char* kConfigConnectable
=
325 "{ \"GUID\": \"wifi0\", \"Type\": \"wifi\", \"State\": \"idle\", "
326 " \"Connectable\": true }";
327 const char* kConfigConnected
=
328 "{ \"GUID\": \"wifi1\", \"Type\": \"wifi\", \"State\": \"online\" }";
329 const char* kConfigConnecting
=
330 "{ \"GUID\": \"wifi2\", \"Type\": \"wifi\", \"State\": \"association\" }";
331 const char* kConfigRequiresPassphrase
=
332 "{ \"GUID\": \"wifi3\", \"Type\": \"wifi\", "
333 " \"PassphraseRequired\": true }";
337 TEST_F(NetworkConnectionHandlerTest
, NetworkConnectionHandlerConnectSuccess
) {
338 EXPECT_TRUE(Configure(kConfigConnectable
));
340 EXPECT_EQ(kSuccessResult
, GetResultAndReset());
341 EXPECT_EQ(shill::kStateOnline
,
342 GetServiceStringProperty(kWifi0
, shill::kStateProperty
));
343 // Observer expectations
344 EXPECT_TRUE(network_connection_observer_
->GetRequested(kWifi0
));
345 EXPECT_EQ(kSuccessResult
, network_connection_observer_
->GetResult(kWifi0
));
348 // Handles basic failure cases.
349 TEST_F(NetworkConnectionHandlerTest
, NetworkConnectionHandlerConnectFailure
) {
351 EXPECT_EQ(NetworkConnectionHandler::kErrorConfigureFailed
,
352 GetResultAndReset());
353 EXPECT_TRUE(network_connection_observer_
->GetRequested(kNoNetwork
));
354 EXPECT_EQ(NetworkConnectionHandler::kErrorConfigureFailed
,
355 network_connection_observer_
->GetResult(kNoNetwork
));
357 EXPECT_TRUE(Configure(kConfigConnected
));
359 EXPECT_EQ(NetworkConnectionHandler::kErrorConnected
, GetResultAndReset());
360 EXPECT_TRUE(network_connection_observer_
->GetRequested(kWifi1
));
361 EXPECT_EQ(NetworkConnectionHandler::kErrorConnected
,
362 network_connection_observer_
->GetResult(kWifi1
));
364 EXPECT_TRUE(Configure(kConfigConnecting
));
366 EXPECT_EQ(NetworkConnectionHandler::kErrorConnecting
, GetResultAndReset());
367 EXPECT_TRUE(network_connection_observer_
->GetRequested(kWifi2
));
368 EXPECT_EQ(NetworkConnectionHandler::kErrorConnecting
,
369 network_connection_observer_
->GetResult(kWifi2
));
371 EXPECT_TRUE(Configure(kConfigRequiresPassphrase
));
373 EXPECT_EQ(NetworkConnectionHandler::kErrorPassphraseRequired
,
374 GetResultAndReset());
375 EXPECT_TRUE(network_connection_observer_
->GetRequested(kWifi3
));
376 EXPECT_EQ(NetworkConnectionHandler::kErrorPassphraseRequired
,
377 network_connection_observer_
->GetResult(kWifi3
));
382 const char* kPolicyWithCertPatternTemplate
=
383 "[ { \"GUID\": \"wifi4\","
384 " \"Name\": \"wifi4\","
385 " \"Type\": \"WiFi\","
387 " \"Security\": \"WPA-EAP\","
388 " \"SSID\": \"wifi_ssid\","
390 " \"Outer\": \"EAP-TLS\","
391 " \"ClientCertType\": \"Pattern\","
392 " \"ClientCertPattern\": {"
394 " \"CommonName\" : \"%s\""
403 // Handle certificates.
404 TEST_F(NetworkConnectionHandlerTest
, ConnectCertificateMissing
) {
406 SetupPolicy(base::StringPrintf(kPolicyWithCertPatternTemplate
, "unknown"),
407 base::DictionaryValue(), // no global config
408 true); // load as user policy
411 EXPECT_EQ(NetworkConnectionHandler::kErrorCertificateRequired
,
412 GetResultAndReset());
415 TEST_F(NetworkConnectionHandlerTest
, ConnectWithCertificateSuccess
) {
417 scoped_refptr
<net::X509Certificate
> cert
= ImportTestClientCert();
418 ASSERT_TRUE(cert
.get());
420 SetupPolicy(base::StringPrintf(kPolicyWithCertPatternTemplate
,
421 cert
->subject().common_name
.c_str()),
422 base::DictionaryValue(), // no global config
423 true); // load as user policy
426 EXPECT_EQ(kSuccessResult
, GetResultAndReset());
429 // Disabled, see http://crbug.com/396729.
430 TEST_F(NetworkConnectionHandlerTest
,
431 DISABLED_ConnectWithCertificateRequestedBeforeCertsAreLoaded
) {
432 scoped_refptr
<net::X509Certificate
> cert
= ImportTestClientCert();
433 ASSERT_TRUE(cert
.get());
435 SetupPolicy(base::StringPrintf(kPolicyWithCertPatternTemplate
,
436 cert
->subject().common_name
.c_str()),
437 base::DictionaryValue(), // no global config
438 true); // load as user policy
442 // Connect request came before the cert loader loaded certificates, so the
443 // connect request should have been throttled until the certificates are
445 EXPECT_EQ("", GetResultAndReset());
449 // |StartCertLoader| should have triggered certificate loading.
450 // When the certificates got loaded, the connection request should have
451 // proceeded and eventually succeeded.
452 EXPECT_EQ(kSuccessResult
, GetResultAndReset());
455 TEST_F(NetworkConnectionHandlerTest
,
456 NetworkConnectionHandlerDisconnectSuccess
) {
457 EXPECT_TRUE(Configure(kConfigConnected
));
459 EXPECT_TRUE(network_connection_observer_
->GetRequested(kWifi1
));
460 EXPECT_EQ(kSuccessResult
, GetResultAndReset());
463 TEST_F(NetworkConnectionHandlerTest
,
464 NetworkConnectionHandlerDisconnectFailure
) {
466 EXPECT_EQ(NetworkConnectionHandler::kErrorConfigureFailed
,
467 GetResultAndReset());
469 EXPECT_TRUE(Configure(kConfigConnectable
));
471 EXPECT_EQ(NetworkConnectionHandler::kErrorNotConnected
, GetResultAndReset());
474 } // namespace chromeos