diff options
7 files changed, 479 insertions, 16 deletions
diff --git a/chrome/browser/automation/automation_provider_observers.h b/chrome/browser/automation/automation_provider_observers.h index 7579496..0a9cd5e 100644 --- a/chrome/browser/automation/automation_provider_observers.h +++ b/chrome/browser/automation/automation_provider_observers.h @@ -813,8 +813,8 @@ class NetworkScanObserver virtual void OnNetworkManagerChanged(chromeos::NetworkLibrary* obj); private: - AutomationProvider* automation_; - IPC::Message* reply_message_; + base::WeakPtr<AutomationProvider> automation_; + scoped_ptr<IPC::Message> reply_message_; DISALLOW_COPY_AND_ASSIGN(NetworkScanObserver); }; @@ -836,8 +836,8 @@ class NetworkConnectObserver virtual void OnNetworkManagerChanged(chromeos::NetworkLibrary* obj); private: - AutomationProvider* automation_; - IPC::Message* reply_message_; + base::WeakPtr<AutomationProvider> automation_; + scoped_ptr<IPC::Message> reply_message_; DISALLOW_COPY_AND_ASSIGN(NetworkConnectObserver); }; @@ -860,6 +860,31 @@ class ServicePathConnectObserver : public NetworkConnectObserver { }; // Waits for a connection success or failure for the specified +// virtual network and returns the status to the automation provider. +class VirtualConnectObserver + : public chromeos::NetworkLibrary::NetworkManagerObserver { + public: + VirtualConnectObserver(AutomationProvider* automation, + IPC::Message* reply_message, + const std::string& service_name); + + virtual ~VirtualConnectObserver(); + + // NetworkLibrary::NetworkManagerObserver implementation. + virtual void OnNetworkManagerChanged(chromeos::NetworkLibrary* cros); + + private: + virtual chromeos::VirtualNetwork* GetVirtualNetwork( + const chromeos::NetworkLibrary* cros); + + base::WeakPtr<AutomationProvider> automation_; + scoped_ptr<IPC::Message> reply_message_; + std::string service_name_; + + DISALLOW_COPY_AND_ASSIGN(VirtualConnectObserver); +}; + +// Waits for a connection success or failure for the specified // network and returns the status to the automation provider. class SSIDConnectObserver : public NetworkConnectObserver { public: diff --git a/chrome/browser/automation/automation_provider_observers_chromeos.cc b/chrome/browser/automation/automation_provider_observers_chromeos.cc index 9e2efbb..0d166da 100644 --- a/chrome/browser/automation/automation_provider_observers_chromeos.cc +++ b/chrome/browser/automation/automation_provider_observers_chromeos.cc @@ -133,7 +133,7 @@ void ScreenUnlockObserver::OnLoginFailure(const chromeos::LoginFailure& error) { NetworkScanObserver::NetworkScanObserver(AutomationProvider* automation, IPC::Message* reply_message) - : automation_(automation), reply_message_(reply_message) { + : automation_(automation->AsWeakPtr()), reply_message_(reply_message) { NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); network_library->AddNetworkManagerObserver(this); } @@ -147,13 +147,16 @@ void NetworkScanObserver::OnNetworkManagerChanged(NetworkLibrary* obj) { if (obj->wifi_scanning()) return; - AutomationJSONReply(automation_, reply_message_).SendSuccess(NULL); + if (automation_) { + AutomationJSONReply(automation_, + reply_message_.release()).SendSuccess(NULL); + } delete this; } NetworkConnectObserver::NetworkConnectObserver(AutomationProvider* automation, IPC::Message* reply_message) - : automation_(automation), reply_message_(reply_message) { + : automation_(automation->AsWeakPtr()), reply_message_(reply_message) { NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); network_library->AddNetworkManagerObserver(this); } @@ -168,22 +171,28 @@ void NetworkConnectObserver::OnNetworkManagerChanged(NetworkLibrary* obj) { if (!wifi) { // The network was not found, and we assume it no longer exists. // This could be because the SSID is invalid, or the network went away. - scoped_ptr<DictionaryValue> return_value(new DictionaryValue); - return_value->SetString("error_string", "Network not found."); - AutomationJSONReply(automation_, reply_message_) - .SendSuccess(return_value.get()); + if (automation_) { + scoped_ptr<DictionaryValue> return_value(new DictionaryValue); + return_value->SetString("error_string", "Network not found."); + AutomationJSONReply(automation_, reply_message_.release()) + .SendSuccess(return_value.get()); + } delete this; return; } if (wifi->failed()) { - scoped_ptr<DictionaryValue> return_value(new DictionaryValue); - return_value->SetString("error_string", wifi->GetErrorString()); - AutomationJSONReply(automation_, reply_message_) - .SendSuccess(return_value.get()); + if (automation_) { + scoped_ptr<DictionaryValue> return_value(new DictionaryValue); + return_value->SetString("error_string", wifi->GetErrorString()); + AutomationJSONReply(automation_, reply_message_.release()) + .SendSuccess(return_value.get()); + } delete this; } else if (wifi->connected()) { - AutomationJSONReply(automation_, reply_message_).SendSuccess(NULL); + if (automation_) + AutomationJSONReply(automation_, + reply_message_.release()).SendSuccess(NULL); delete this; } @@ -202,6 +211,64 @@ const chromeos::WifiNetwork* ServicePathConnectObserver::GetWifiNetwork( return network_library->FindWifiNetworkByPath(service_path_); } +VirtualConnectObserver::VirtualConnectObserver(AutomationProvider* automation, + IPC::Message* reply_message, + const std::string& service_name) + : automation_(automation->AsWeakPtr()), + reply_message_(reply_message), + service_name_(service_name) { + NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); + network_library->AddNetworkManagerObserver(this); +} + +VirtualConnectObserver::~VirtualConnectObserver() { + NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); + network_library->RemoveNetworkManagerObserver(this); +} + +void VirtualConnectObserver::OnNetworkManagerChanged(NetworkLibrary* cros) { + const chromeos::VirtualNetwork* virt = GetVirtualNetwork(cros); + if (!virt) { + // The network hasn't been added to the NetworkLibrary's list yet, + // just continue waiting for more network events. + return; + } + + if (virt->failed()) { + if (automation_) { + scoped_ptr<DictionaryValue> return_value(new DictionaryValue); + return_value->SetString("error_string", virt->GetErrorString()); + AutomationJSONReply(automation_, reply_message_.release()) + .SendSuccess(return_value.get()); + } + delete this; + } else if (virt->connected()) { + if (automation_) + AutomationJSONReply(automation_, + reply_message_.release()).SendSuccess(NULL); + delete this; + } + // The network is in the NetworkLibrary's list, but there's no failure or + // success condition, so just continue waiting for more network events. +} + +chromeos::VirtualNetwork* VirtualConnectObserver::GetVirtualNetwork( + const chromeos::NetworkLibrary* cros) { + chromeos::VirtualNetwork* virt = NULL; + const chromeos::VirtualNetworkVector& virtual_networks = + cros->virtual_networks(); + + for (chromeos::VirtualNetworkVector::const_iterator iter = + virtual_networks.begin(); iter != virtual_networks.end(); ++iter) { + chromeos::VirtualNetwork* v = *iter; + if (v->name() == service_name_) { + virt = v; + break; + } + } + return virt; +} + SSIDConnectObserver::SSIDConnectObserver( AutomationProvider* automation, IPC::Message* reply_message, const std::string& ssid) diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc index b1288c8..29ec1c3 100644 --- a/chrome/browser/automation/testing_automation_provider.cc +++ b/chrome/browser/automation/testing_automation_provider.cc @@ -2158,6 +2158,15 @@ void TestingAutomationProvider::SendJSONRequest(int handle, handler_map["ForgetWifiNetwork"] = &TestingAutomationProvider::ForgetWifiNetwork; + handler_map["AddPrivateNetwork"] = + &TestingAutomationProvider::AddPrivateNetwork; + handler_map["GetPrivateNetworkInfo"] = + &TestingAutomationProvider::GetPrivateNetworkInfo; + handler_map["ConnectToPrivateNetwork"] = + &TestingAutomationProvider::ConnectToPrivateNetwork; + handler_map["DisconnectFromPrivateNetwork"] = + &TestingAutomationProvider::DisconnectFromPrivateNetwork; + handler_map["GetUpdateInfo"] = &TestingAutomationProvider::GetUpdateInfo; handler_map["UpdateCheck"] = &TestingAutomationProvider::UpdateCheck; handler_map["SetReleaseTrack"] = &TestingAutomationProvider::SetReleaseTrack; diff --git a/chrome/browser/automation/testing_automation_provider.h b/chrome/browser/automation/testing_automation_provider.h index 834f066..7738823 100644 --- a/chrome/browser/automation/testing_automation_provider.h +++ b/chrome/browser/automation/testing_automation_provider.h @@ -1154,6 +1154,18 @@ class TestingAutomationProvider : public AutomationProvider, void DisconnectFromWifiNetwork(DictionaryValue* args, IPC::Message* reply_message); + // VPN automation + void AddPrivateNetwork(DictionaryValue* args, IPC::Message* reply_message); + + void GetPrivateNetworkInfo(DictionaryValue* args, + IPC::Message* reply_message); + + void ConnectToPrivateNetwork(DictionaryValue* args, + IPC::Message* reply_message); + + void DisconnectFromPrivateNetwork(DictionaryValue* args, + IPC::Message* reply_message); + void ForgetWifiNetwork(DictionaryValue* args, IPC::Message* reply_message); void GetUpdateInfo(DictionaryValue* args, IPC::Message* reply_message); diff --git a/chrome/browser/automation/testing_automation_provider_chromeos.cc b/chrome/browser/automation/testing_automation_provider_chromeos.cc index 1cc920d..9e22316 100644 --- a/chrome/browser/automation/testing_automation_provider_chromeos.cc +++ b/chrome/browser/automation/testing_automation_provider_chromeos.cc @@ -4,6 +4,7 @@ #include "chrome/browser/automation/testing_automation_provider.h" +#include "base/stringprintf.h" #include "base/values.h" #include "chrome/browser/automation/automation_provider_json.h" #include "chrome/browser/automation/automation_provider_observers.h" @@ -128,6 +129,20 @@ void UpdateCheckCallback(void* user_data, chromeos::UpdateResult result, delete reply; } +const std::string VPNProviderTypeToString(chromeos::VirtualNetwork::ProviderType + provider_type) { + switch (provider_type) { + case chromeos::VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK: + return std::string("L2TP_IPSEC_PSK"); + case chromeos::VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT: + return std::string("L2TP_IPSEC_USER_CERT"); + case chromeos::VirtualNetwork::PROVIDER_TYPE_OPEN_VPN: + return std::string("OPEN_VPN"); + default: + return std::string("UNSUPPORTED_PROVIDER_TYPE"); + } +} + } // namespace void TestingAutomationProvider::GetLoginInfo(DictionaryValue* args, @@ -521,6 +536,151 @@ void TestingAutomationProvider::DisconnectFromWifiNetwork( reply.SendSuccess(NULL); } +void TestingAutomationProvider::AddPrivateNetwork( + DictionaryValue* args, IPC::Message* reply_message) { + if (!EnsureCrosLibraryLoaded(this, reply_message)) + return; + + std::string hostname, service_name, provider_type, key, cert_id, cert_nss, + username, password; + if (!args->GetString("hostname", &hostname) || + !args->GetString("service_name", &service_name) || + !args->GetString("provider_type", &provider_type) || + !args->GetString("username", &username) || + !args->GetString("password", &password)) { + AutomationJSONReply(this, reply_message) + .SendError("Invalid or missing args."); + return; + } + + NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); + + // Attempt to connect to the VPN based on the provider type. + if (provider_type == VPNProviderTypeToString( + chromeos::VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK)) { + if (!args->GetString("key", &key)) { + AutomationJSONReply(this, reply_message) + .SendError("Missing key arg."); + return; + } + new VirtualConnectObserver(this, reply_message, service_name); + // Connect using a pre-shared key. + network_library->ConnectToVirtualNetworkPSK(service_name, + hostname, + key, + username, + password); + } else if (provider_type == VPNProviderTypeToString( + chromeos::VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT)) { + if (!args->GetString("cert_id", &cert_id) || + !args->GetString("cert_nss", &cert_nss)) { + AutomationJSONReply(this, reply_message) + .SendError("Missing a certificate arg."); + return; + } + new VirtualConnectObserver(this, reply_message, service_name); + // Connect using a user certificate. + network_library->ConnectToVirtualNetworkCert(service_name, + hostname, + cert_nss, + cert_id, + username, + password); + } else if (provider_type == VPNProviderTypeToString( + chromeos::VirtualNetwork::PROVIDER_TYPE_OPEN_VPN)) { + // Connect using OPEN_VPN. Not yet supported by the VPN implementation. + AutomationJSONReply(this, reply_message) + .SendError("Provider type OPEN_VPN is not yet supported."); + return; + } else { + AutomationJSONReply(this, reply_message) + .SendError("Unsupported provider type."); + return; + } +} + +void TestingAutomationProvider::ConnectToPrivateNetwork( + DictionaryValue* args, IPC::Message* reply_message) { + if (!EnsureCrosLibraryLoaded(this, reply_message)) + return; + + AutomationJSONReply reply(this, reply_message); + std::string service_path; + if (!args->GetString("service_path", &service_path)) { + reply.SendError("Invalid or missing args."); + return; + } + + // Connect to a remembered VPN by its service_path. Valid service_paths + // can be found in the dictionary returned by GetPrivateNetworkInfo. + NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); + chromeos::VirtualNetwork* network = + network_library->FindVirtualNetworkByPath(service_path); + if (!network) { + reply.SendError(StringPrintf("No virtual network found: %s", + service_path.c_str())); + return; + } + if (network->NeedMoreInfoToConnect()) { + reply.SendError("Virtual network is missing info required to connect."); + return; + }; + + new VirtualConnectObserver(this, reply_message, network->name()); + network_library->ConnectToVirtualNetwork(network); +} + +void TestingAutomationProvider::GetPrivateNetworkInfo( + DictionaryValue* args, IPC::Message* reply_message) { + if (!EnsureCrosLibraryLoaded(this, reply_message)) + return; + + scoped_ptr<DictionaryValue> return_value(new DictionaryValue); + NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); + const chromeos::VirtualNetworkVector& virtual_networks = + network_library->virtual_networks(); + + // Construct a dictionary of fields describing remembered VPNs. Also list + // the currently active VPN, if any. + if (network_library->virtual_network()) + return_value->SetString("connected", + network_library->virtual_network()->service_path()); + for (chromeos::VirtualNetworkVector::const_iterator iter = + virtual_networks.begin(); iter != virtual_networks.end(); ++iter) { + const chromeos::VirtualNetwork* virt = *iter; + DictionaryValue* item = new DictionaryValue; + item->SetString("name", virt->name()); + item->SetString("provider_type", + VPNProviderTypeToString(virt->provider_type())); + item->SetString("hostname", virt->server_hostname()); + item->SetString("key", virt->psk_passphrase()); + item->SetString("cert_nss", virt->ca_cert_nss()); + item->SetString("cert_id", virt->client_cert_id()); + item->SetString("username", virt->username()); + item->SetString("password", virt->user_passphrase()); + return_value->Set(virt->service_path(), item); + } + + AutomationJSONReply(this, reply_message).SendSuccess(return_value.get()); +} + +void TestingAutomationProvider::DisconnectFromPrivateNetwork( + DictionaryValue* args, IPC::Message* reply_message) { + if (!EnsureCrosLibraryLoaded(this, reply_message)) + return; + + AutomationJSONReply reply(this, reply_message); + NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); + const chromeos::VirtualNetwork* virt = network_library->virtual_network(); + if (!virt) { + reply.SendError("Not connected to any virtual network."); + return; + } + + network_library->DisconnectFromNetwork(virt); + reply.SendSuccess(NULL); +} + void TestingAutomationProvider::GetUpdateInfo(DictionaryValue* args, IPC::Message* reply_message) { if (!EnsureCrosLibraryLoaded(this, reply_message)) diff --git a/chrome/test/functional/chromeos_vpn.py b/chrome/test/functional/chromeos_vpn.py new file mode 100644 index 0000000..8ba6ab1 --- /dev/null +++ b/chrome/test/functional/chromeos_vpn.py @@ -0,0 +1,74 @@ +#!/usr/bin/python +# Copyright (c) 2011 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import subprocess + +import pyauto_functional +import pyauto +import chromeos_network + + +class PrivateNetworkTest(chromeos_network.PyNetworkUITest): + """Tests for VPN. + + Expected to be run with access to the lab setup as defined in + vpn_testbed_config. + """ + + def _PingTest(self, hostname, timeout=10): + """Attempt to ping a remote host. + + Returns: + True if the ping succeeds. + False otherwise. + """ + return subprocess.call(['ping', '-c', '1', '-W', + str(timeout), hostname]) == 0 + + def testCanAddNetwork(self): + """Test to add a VPN network, connect and disconnect.""" + # Load VPN config data from file. + vpn_info_file = os.path.join(pyauto.PyUITest.DataDir(), + 'pyauto_private/chromeos/network', + 'vpn_testbed_config') + self.assertTrue(os.path.exists(vpn_info_file)) + vpn = self.EvalDataFrom(vpn_info_file) + + # Connect to wifi. + self.NetworkScan() + self.WaitUntilWifiNetworkAvailable(vpn['wifi']) + wifi_vpn = self.GetServicePath(vpn['wifi']) + self.assertTrue(wifi_vpn) + self.assertTrue(self.ConnectToWifiNetwork(wifi_vpn) is None) + self.assertFalse(self._PingTest(vpn['ping']), + msg='VPN ping succeeded when not connected.') + + # Connect to the VPN. + self.AddPrivateNetwork(hostname=vpn['hostname'], + service_name=vpn['service_name'], + provider_type=vpn['provider_type'], + username=vpn['username'], + password=vpn['password'], + key=vpn['key']) + + # Get private network info. + result = self.GetPrivateNetworkInfo() + self.assertTrue('connected' in result, msg='Could not connect to VPN') + connected = result['connected'] + self.assertTrue(self._PingTest(vpn['ping']), msg='VPN ping failed.') + self.DisconnectFromPrivateNetwork() + self.assertFalse(self._PingTest(vpn['ping']), + msg='VPN ping succeeded when not connected.') + # Connect to the remembered private network. + self.ConnectToPrivateNetwork(connected) + self.assertTrue(self._PingTest(vpn['ping']), msg='VPN ping failed.') + self.DisconnectFromPrivateNetwork() + self.assertFalse(self._PingTest(vpn['ping']), + msg='VPN ping succeeded when not connected.') + + +if __name__ == '__main__': + pyauto_functional.Main() diff --git a/chrome/test/pyautolib/pyauto.py b/chrome/test/pyautolib/pyauto.py index 9b47ff0..761d17d 100644 --- a/chrome/test/pyautolib/pyauto.py +++ b/chrome/test/pyautolib/pyauto.py @@ -3241,6 +3241,122 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase): } self._GetResultFromJSONRequest(cmd_dict, windex=-1) + def AddPrivateNetwork(self, + hostname, + service_name, + provider_type, + username, + password, + cert_nss='', + cert_id='', + key=''): + """Add and connect to a private network. + + Blocks until connection succeeds or fails. This is equivalent to + 'Add Private Network' in the network menu UI. + + Args: + hostname: Server hostname for the private network. + service_name: Service name that defines the private network. Do not + add multiple services with the same name. + provider_type: Types are L2TP_IPSEC_PSK and L2TP_IPSEC_USER_CERT. + Provider type OPEN_VPN is not yet supported. + Type names returned by GetPrivateNetworkInfo will + also work. + username: Username for connecting to the virtual network. + password: Passphrase for connecting to the virtual network. + cert_nss: Certificate nss nickname for a L2TP_IPSEC_USER_CERT network. + cert_id: Certificate id for a L2TP_IPSEC_USER_CERT network. + key: Pre-shared key for a L2TP_IPSEC_PSK network. + + Returns: + An error string if an error occured. + None otherwise. + + Raises: + pyauto_errors.JSONInterfaceError if the automation call returns an error. + """ + cmd_dict = { + 'command': 'AddPrivateNetwork', + 'hostname': hostname, + 'service_name': service_name, + 'provider_type': provider_type, + 'username': username, + 'password': password, + 'cert_nss': cert_nss, + 'cert_id': cert_id, + 'key': key, + } + result = self._GetResultFromJSONRequest(cmd_dict, windex=-1, timeout=50000) + return result.get('error_string') + + def GetPrivateNetworkInfo(self): + """Get details about private networks on chromeos. + + Returns: + A dictionary including information about all remembered virtual networks + as well as the currently connected virtual network, if any. + Sample: + { u'connected': u'/service/vpn_123_45_67_89_test_vpn'} + u'/service/vpn_123_45_67_89_test_vpn': + { u'username': u'vpn_user', + u'name': u'test_vpn', + u'hostname': u'123.45.67.89', + u'key': u'abcde', + u'cert_id': u'', + u'password': u'zyxw123', + u'provider_type': u'L2TP_IPSEC_PSK'}, + u'/service/vpn_111_11_11_11_test_vpn2': + { u'username': u'testerman', + u'name': u'test_vpn2', + u'hostname': u'111.11.11.11', + u'key': u'fghijklm', + u'cert_id': u'', + u'password': u'789mnop', + u'provider_type': u'L2TP_IPSEC_PSK'}, + + Raises: + pyauto_errors.JSONInterfaceError if the automation call returns an error. + """ + cmd_dict = { 'command': 'GetPrivateNetworkInfo' } + return self._GetResultFromJSONRequest(cmd_dict, windex=-1) + + def ConnectToPrivateNetwork(self, service_path): + """Connect to a remembered private network by its service path. + + Blocks until connection succeeds or fails. The network must have been + previously added with all necessary connection details. + + Args: + service_path: Service name that defines the private network. + + Returns: + An error string if an error occured. + None otherwise. + + Raises: + pyauto_errors.JSONInterfaceError if the automation call returns an error. + """ + cmd_dict = { + 'command': 'ConnectToPrivateNetwork', + 'service_path': service_path, + } + result = self._GetResultFromJSONRequest(cmd_dict, windex=-1, timeout=50000) + return result.get('error_string') + + def DisconnectFromPrivateNetwork(self): + """Disconnect from the active private network. + + Expects a private network to be active. + + Raises: + pyauto_errors.JSONInterfaceError if the automation call returns an error. + """ + cmd_dict = { + 'command': 'DisconnectFromPrivateNetwork', + } + return self._GetResultFromJSONRequest(cmd_dict, windex=-1) + def GetUpdateInfo(self): """Gets the status of the ChromeOS updater. |