Roll src/third_party/WebKit a452221:9ff6d11 (svn 202117:202119)
[chromium-blink-merge.git] / chromeos / network / auto_connect_handler_unittest.cc
blob11431084a03cd00336083fa5de859701e13fea8f
1 // Copyright 2014 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/auto_connect_handler.h"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/files/file_util.h"
12 #include "base/json/json_reader.h"
13 #include "base/macros.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/client_cert_resolver.h"
25 #include "chromeos/network/managed_network_configuration_handler_impl.h"
26 #include "chromeos/network/network_configuration_handler.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"
41 namespace chromeos {
43 namespace {
45 const char* kUserHash = "user_hash";
47 void ConfigureCallback(const dbus::ObjectPath& result) {
50 void FailErrorCallback(const std::string& error_name,
51 const std::string& error_message) {
52 // This function is not expected to be called.
53 EXPECT_TRUE(false);
56 class TestCertResolveObserver : public ClientCertResolver::Observer {
57 public:
58 explicit TestCertResolveObserver(ClientCertResolver* cert_resolver)
59 : changed_network_properties_(false), cert_resolver_(cert_resolver) {
60 cert_resolver_->AddObserver(this);
63 void ResolveRequestCompleted(bool changed_network_properties) override {
64 cert_resolver_->RemoveObserver(this);
65 changed_network_properties_ = changed_network_properties;
68 bool DidNetworkPropertiesChange() { return changed_network_properties_; }
70 private:
71 bool changed_network_properties_;
72 ClientCertResolver* cert_resolver_;
75 } // namespace
77 class AutoConnectHandlerTest : public testing::Test {
78 public:
79 AutoConnectHandlerTest()
80 : test_manager_client_(nullptr), test_service_client_(nullptr) {}
82 void SetUp() override {
83 ASSERT_TRUE(test_nssdb_.is_open());
85 // Use the same DB for public and private slot.
86 test_nsscertdb_.reset(new net::NSSCertDatabaseChromeOS(
87 crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_.slot())),
88 crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_.slot()))));
89 test_nsscertdb_->SetSlowTaskRunnerForTest(message_loop_.task_runner());
91 CertLoader::Initialize();
92 CertLoader::ForceHardwareBackedForTesting();
94 DBusThreadManager::Initialize();
95 DBusThreadManager* dbus_manager = DBusThreadManager::Get();
96 test_manager_client_ =
97 dbus_manager->GetShillManagerClient()->GetTestInterface();
98 test_service_client_ =
99 dbus_manager->GetShillServiceClient()->GetTestInterface();
101 test_manager_client_->AddTechnology(shill::kTypeWifi, true /* enabled */);
102 dbus_manager->GetShillDeviceClient()->GetTestInterface()->AddDevice(
103 "/device/wifi1", shill::kTypeWifi, "wifi_device1");
104 test_manager_client_->AddTechnology(shill::kTypeCellular,
105 true /* enabled */);
106 dbus_manager->GetShillProfileClient()->GetTestInterface()->AddProfile(
107 "shared_profile_path", std::string() /* shared profile */);
108 dbus_manager->GetShillProfileClient()->GetTestInterface()->AddProfile(
109 "user_profile_path", kUserHash);
111 base::RunLoop().RunUntilIdle();
112 LoginState::Initialize();
113 network_state_handler_.reset(NetworkStateHandler::InitializeForTest());
114 network_config_handler_.reset(
115 NetworkConfigurationHandler::InitializeForTest(
116 network_state_handler_.get(), NULL /* network_device_handler */));
118 network_profile_handler_.reset(new NetworkProfileHandler());
119 network_profile_handler_->Init();
121 managed_config_handler_.reset(new ManagedNetworkConfigurationHandlerImpl());
122 managed_config_handler_->Init(
123 network_state_handler_.get(), network_profile_handler_.get(),
124 network_config_handler_.get(), nullptr /* network_device_handler */);
126 client_cert_resolver_.reset(new ClientCertResolver());
127 client_cert_resolver_->Init(network_state_handler_.get(),
128 managed_config_handler_.get());
129 client_cert_resolver_->SetSlowTaskRunnerForTest(
130 message_loop_.task_runner());
132 auto_connect_handler_.reset(new AutoConnectHandler());
133 auto_connect_handler_->Init(client_cert_resolver_.get(),
134 nullptr, // no connection handler
135 network_state_handler_.get(),
136 managed_config_handler_.get());
138 base::RunLoop().RunUntilIdle();
141 void TearDown() override {
142 auto_connect_handler_.reset();
143 client_cert_resolver_.reset();
144 managed_config_handler_.reset();
145 network_profile_handler_.reset();
146 network_config_handler_.reset();
147 network_state_handler_.reset();
148 CertLoader::Shutdown();
149 LoginState::Shutdown();
150 DBusThreadManager::Shutdown();
153 protected:
154 bool Configure(const std::string& json_string) {
155 scoped_ptr<base::DictionaryValue> json_dict =
156 onc::ReadDictionaryFromJson(json_string);
157 if (!json_dict) {
158 LOG(ERROR) << "Error parsing json: " << json_string;
159 return false;
161 DBusThreadManager::Get()->GetShillManagerClient()->ConfigureService(
162 *json_dict, base::Bind(&ConfigureCallback),
163 base::Bind(&FailErrorCallback));
164 base::RunLoop().RunUntilIdle();
165 return true;
168 std::string GetServiceState(const std::string& service_path) {
169 const base::DictionaryValue* properties =
170 test_service_client_->GetServiceProperties(service_path);
171 std::string result;
172 if (properties)
173 properties->GetStringWithoutPathExpansion(shill::kStateProperty, &result);
174 return result;
177 void StartCertLoader() {
178 CertLoader::Get()->StartWithNSSDB(test_nsscertdb_.get());
179 base::RunLoop().RunUntilIdle();
182 void LoginToRegularUser() {
183 LoginState::Get()->SetLoggedInState(LoginState::LOGGED_IN_ACTIVE,
184 LoginState::LOGGED_IN_USER_REGULAR);
185 base::RunLoop().RunUntilIdle();
188 scoped_refptr<net::X509Certificate> ImportTestClientCert() {
189 net::CertificateList ca_cert_list = net::CreateCertificateListFromFile(
190 net::GetTestCertsDirectory(), "client_1_ca.pem",
191 net::X509Certificate::FORMAT_AUTO);
192 if (ca_cert_list.empty()) {
193 LOG(ERROR) << "No CA cert loaded.";
194 return nullptr;
196 net::NSSCertDatabase::ImportCertFailureList failures;
197 EXPECT_TRUE(test_nsscertdb_->ImportCACerts(
198 ca_cert_list, net::NSSCertDatabase::TRUST_DEFAULT, &failures));
199 if (!failures.empty()) {
200 LOG(ERROR) << net::ErrorToString(failures[0].net_error);
201 return nullptr;
204 // Import a client cert signed by that CA.
205 scoped_refptr<net::X509Certificate> client_cert(
206 net::ImportClientCertAndKeyFromFile(net::GetTestCertsDirectory(),
207 "client_1.pem", "client_1.pk8",
208 test_nssdb_.slot()));
209 return client_cert;
212 void SetupPolicy(const std::string& network_configs_json,
213 const base::DictionaryValue& global_config,
214 bool user_policy) {
215 scoped_ptr<base::ListValue> network_configs(new base::ListValue);
216 if (!network_configs_json.empty()) {
217 std::string error;
218 scoped_ptr<base::Value> network_configs_value =
219 base::JSONReader::ReadAndReturnError(network_configs_json,
220 base::JSON_ALLOW_TRAILING_COMMAS,
221 nullptr, &error);
222 ASSERT_TRUE(network_configs_value) << error;
223 base::ListValue* network_configs_list = nullptr;
224 ASSERT_TRUE(network_configs_value->GetAsList(&network_configs_list));
225 ignore_result(network_configs_value.release());
226 network_configs.reset(network_configs_list);
229 if (user_policy) {
230 managed_config_handler_->SetPolicy(::onc::ONC_SOURCE_USER_POLICY,
231 kUserHash, *network_configs,
232 global_config);
233 } else {
234 managed_config_handler_->SetPolicy(::onc::ONC_SOURCE_DEVICE_POLICY,
235 std::string(), // no username hash
236 *network_configs, global_config);
238 base::RunLoop().RunUntilIdle();
241 scoped_ptr<AutoConnectHandler> auto_connect_handler_;
242 scoped_ptr<ClientCertResolver> client_cert_resolver_;
243 scoped_ptr<NetworkStateHandler> network_state_handler_;
244 scoped_ptr<NetworkConfigurationHandler> network_config_handler_;
245 scoped_ptr<ManagedNetworkConfigurationHandlerImpl> managed_config_handler_;
246 scoped_ptr<NetworkProfileHandler> network_profile_handler_;
247 ShillManagerClient::TestInterface* test_manager_client_;
248 ShillServiceClient::TestInterface* test_service_client_;
249 crypto::ScopedTestNSSDB test_nssdb_;
250 scoped_ptr<net::NSSCertDatabaseChromeOS> test_nsscertdb_;
251 base::MessageLoopForUI message_loop_;
253 private:
254 DISALLOW_COPY_AND_ASSIGN(AutoConnectHandlerTest);
257 namespace {
259 const char* kConfigUnmanagedSharedConnected =
260 "{ \"GUID\": \"wifi0\", \"Type\": \"wifi\", \"State\": \"online\", "
261 " \"Security\": \"wpa\" }";
262 const char* kConfigManagedSharedConnectable =
263 "{ \"GUID\": \"wifi1\", \"Type\": \"wifi\", \"State\": \"idle\", "
264 " \"Connectable\": true, \"Security\": \"wpa\" }";
266 const char* kPolicy =
267 "[ { \"GUID\": \"wifi1\","
268 " \"Name\": \"wifi1\","
269 " \"Type\": \"WiFi\","
270 " \"WiFi\": {"
271 " \"Security\": \"WPA-PSK\","
272 " \"HexSSID\": \"7769666931\"," // "wifi1"
273 " \"Passphrase\": \"passphrase\""
274 " }"
275 "} ]";
277 const char* kPolicyCertPattern =
278 "[ { \"GUID\": \"wifi1\","
279 " \"Name\": \"wifi1\","
280 " \"Type\": \"WiFi\","
281 " \"WiFi\": {"
282 " \"Security\": \"WPA-EAP\","
283 " \"HexSSID\": \"7769666931\"," // "wifi1"
284 " \"EAP\": {"
285 " \"Outer\": \"EAP-TLS\","
286 " \"ClientCertType\": \"Pattern\","
287 " \"ClientCertPattern\": {"
288 " \"Issuer\": {"
289 " \"CommonName\": \"B CA\""
290 " }"
291 " }"
292 " }"
293 " }"
294 "} ]";
295 } // namespace
297 TEST_F(AutoConnectHandlerTest, ReconnectOnCertLoading) {
298 EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected));
299 EXPECT_TRUE(Configure(kConfigManagedSharedConnectable));
300 test_manager_client_->SetBestServiceToConnect("wifi1");
302 // User login shouldn't trigger any change until the certificates and policy
303 // are loaded.
304 LoginToRegularUser();
305 EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi0"));
306 EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1"));
308 // Applying the policy which restricts autoconnect should disconnect from the
309 // shared, unmanaged network.
310 base::DictionaryValue global_config;
311 global_config.SetBooleanWithoutPathExpansion(
312 ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect,
313 true);
315 SetupPolicy(std::string(), // no network configs
316 base::DictionaryValue(), // no global config
317 true); // load as user policy
318 SetupPolicy(kPolicy, global_config, false /* load as device policy */);
319 EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi0"));
320 EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1"));
322 // Certificate loading should trigger connecting to the 'best' network.
323 StartCertLoader();
324 EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi0"));
325 EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi1"));
328 TEST_F(AutoConnectHandlerTest, ReconnectOnCertPatternResolved) {
329 EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected));
330 EXPECT_TRUE(Configure(kConfigManagedSharedConnectable));
331 test_manager_client_->SetBestServiceToConnect("wifi0");
333 SetupPolicy(std::string(), // no device policy
334 base::DictionaryValue(), // no global config
335 false); // load as device policy
336 LoginToRegularUser();
337 StartCertLoader();
338 SetupPolicy(kPolicyCertPattern,
339 base::DictionaryValue(), // no global config
340 true); // load as user policy
342 EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi0"));
343 EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1"));
345 test_manager_client_->SetBestServiceToConnect("wifi1");
346 TestCertResolveObserver observer(client_cert_resolver_.get());
348 scoped_refptr<net::X509Certificate> cert = ImportTestClientCert();
349 ASSERT_TRUE(cert.get());
351 base::RunLoop().RunUntilIdle();
352 EXPECT_TRUE(observer.DidNetworkPropertiesChange());
354 EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi0"));
355 EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi1"));
358 // Ensure that resolving of certificate patterns only triggers a reconnect if at
359 // least one pattern was resolved.
360 TEST_F(AutoConnectHandlerTest, NoReconnectIfNoCertResolved) {
361 EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected));
362 EXPECT_TRUE(Configure(kConfigManagedSharedConnectable));
363 test_manager_client_->SetBestServiceToConnect("wifi0");
365 SetupPolicy(std::string(), // no device policy
366 base::DictionaryValue(), // no global config
367 false); // load as device policy
368 LoginToRegularUser();
369 StartCertLoader();
370 SetupPolicy(kPolicy,
371 base::DictionaryValue(), // no global config
372 true); // load as user policy
374 EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi0"));
375 EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1"));
377 test_manager_client_->SetBestServiceToConnect("wifi1");
378 TestCertResolveObserver observer(client_cert_resolver_.get());
379 scoped_refptr<net::X509Certificate> cert = ImportTestClientCert();
380 ASSERT_TRUE(cert.get());
382 base::RunLoop().RunUntilIdle();
383 EXPECT_FALSE(observer.DidNetworkPropertiesChange());
385 EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi0"));
386 EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1"));
389 TEST_F(AutoConnectHandlerTest, DisconnectOnPolicyLoading) {
390 EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected));
391 EXPECT_TRUE(Configure(kConfigManagedSharedConnectable));
393 // User login and certificate loading shouldn't trigger any change until the
394 // policy is loaded.
395 LoginToRegularUser();
396 StartCertLoader();
397 EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi0"));
398 EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1"));
400 base::DictionaryValue global_config;
401 global_config.SetBooleanWithoutPathExpansion(
402 ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect,
403 true);
405 // Applying the policy which restricts autoconnect should disconnect from the
406 // shared, unmanaged network.
407 // Because no best service is set, the fake implementation of
408 // ConnectToBestServices will be a no-op.
409 SetupPolicy(kPolicy, global_config, false /* load as device policy */);
410 EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi0"));
411 EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1"));
414 // After login a reconnect is triggered even if there is no managed network.
415 TEST_F(AutoConnectHandlerTest, ReconnectAfterLogin) {
416 EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected));
417 EXPECT_TRUE(Configure(kConfigManagedSharedConnectable));
418 test_manager_client_->SetBestServiceToConnect("wifi1");
420 // User login and certificate loading shouldn't trigger any change until the
421 // policy is loaded.
422 LoginToRegularUser();
423 StartCertLoader();
424 EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi0"));
425 EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1"));
427 // Applying an empty device policy will not trigger anything yet, until also
428 // the user policy is applied.
429 SetupPolicy(std::string(), // no network configs
430 base::DictionaryValue(), // no global config
431 false); // load as device policy
432 EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi0"));
433 EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1"));
435 // Applying also an empty user policy should trigger connecting to the 'best'
436 // network.
437 SetupPolicy(std::string(), // no network configs
438 base::DictionaryValue(), // no global config
439 true); // load as user policy
440 EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi0"));
441 EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi1"));
444 TEST_F(AutoConnectHandlerTest, ManualConnectAbortsReconnectAfterLogin) {
445 EXPECT_TRUE(Configure(kConfigUnmanagedSharedConnected));
446 EXPECT_TRUE(Configure(kConfigManagedSharedConnectable));
447 test_manager_client_->SetBestServiceToConnect("wifi1");
449 // User login and certificate loading shouldn't trigger any change until the
450 // policy is loaded.
451 LoginToRegularUser();
452 StartCertLoader();
453 SetupPolicy(std::string(), // no network configs
454 base::DictionaryValue(), // no global config
455 false); // load as device policy
457 EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi0"));
458 EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1"));
460 // A manual connect request should prevent a reconnect after login.
461 auto_connect_handler_->ConnectToNetworkRequested(
462 std::string() /* service_path */);
464 // Applying the user policy after login would usually trigger connecting to
465 // the 'best' network. But the manual connect prevents this.
466 SetupPolicy(std::string(), // no network configs
467 base::DictionaryValue(), // no global config
468 true); // load as user policy
469 EXPECT_EQ(shill::kStateOnline, GetServiceState("wifi0"));
470 EXPECT_EQ(shill::kStateIdle, GetServiceState("wifi1"));
473 } // namespace chromeos