shill: vpn: Load and save OpenVPN service properties.
BUG=chromium-os:27650
TEST=unit tests
Change-Id: If620f34ecbf82be018b546c290e3fa1baa6fc001
Reviewed-on: https://gerrit.chromium.org/gerrit/18650
Tested-by: Darin Petkov <petkov@chromium.org>
Reviewed-by: Paul Stewart <pstew@chromium.org>
Commit-Ready: Darin Petkov <petkov@chromium.org>
diff --git a/mock_vpn_driver.h b/mock_vpn_driver.h
index 08492a9..58b398e 100644
--- a/mock_vpn_driver.h
+++ b/mock_vpn_driver.h
@@ -20,6 +20,10 @@
int interface_index));
MOCK_METHOD2(Connect, void(const VPNServiceRefPtr &service, Error *error));
MOCK_METHOD0(Disconnect, void());
+ MOCK_METHOD2(Load, bool(StoreInterface *storage,
+ const std::string &storage_id));
+ MOCK_METHOD2(Save, bool(StoreInterface *storage,
+ const std::string &storage_id));
private:
DISALLOW_COPY_AND_ASSIGN(MockVPNDriver);
diff --git a/openvpn_driver.cc b/openvpn_driver.cc
index af9ace2..4e31029 100644
--- a/openvpn_driver.cc
+++ b/openvpn_driver.cc
@@ -17,6 +17,7 @@
#include "shill/error.h"
#include "shill/manager.h"
#include "shill/rpc_task.h"
+#include "shill/store_interface.h"
#include "shill/vpn.h"
#include "shill/vpn_service.h"
@@ -36,6 +37,61 @@
const char kOpenVPNRouteVPNGateway[] = "route_vpn_gateway";
const char kOpenVPNTrustedIP[] = "trusted_ip";
const char kOpenVPNTunMTU[] = "tun_mtu";
+
+// TODO(petkov): Move to chromeos/dbus/service_constants.h.
+const char kOpenVPNCertProperty[] = "OpenVPN.Cert";
+const char kOpenVPNKeyProperty[] = "OpenVPN.Key";
+const char kOpenVPNPingProperty[] = "OpenVPN.Ping";
+const char kOpenVPNPingExitProperty[] = "OpenVPN.PingExit";
+const char kOpenVPNPingRestartProperty[] = "OpenVPN.PingRestart";
+const char kOpenVPNTLSAuthProperty[] = "OpenVPN.TLSAuth";
+const char kOpenVPNVerbProperty[] = "OpenVPN.Verb";
+const char kVPNMTUProperty[] = "VPN.MTU";
+
+const struct {
+ const char *property;
+ bool crypted;
+} kProperties[] = {
+ { flimflam::kOpenVPNAuthNoCacheProperty, false },
+ { flimflam::kOpenVPNAuthProperty, false },
+ { flimflam::kOpenVPNAuthRetryProperty, false },
+ { flimflam::kOpenVPNAuthUserPassProperty, false },
+ { flimflam::kOpenVPNCaCertNSSProperty, false },
+ { flimflam::kOpenVPNCaCertProperty, false },
+ { flimflam::kOpenVPNCipherProperty, false },
+ { flimflam::kOpenVPNCompLZOProperty, false },
+ { flimflam::kOpenVPNCompNoAdaptProperty, false },
+ { flimflam::kOpenVPNKeyDirectionProperty, false },
+ { flimflam::kOpenVPNNsCertTypeProperty, false },
+ { flimflam::kOpenVPNPasswordProperty, true },
+ { flimflam::kOpenVPNPinProperty, false },
+ { flimflam::kOpenVPNPortProperty, false },
+ { flimflam::kOpenVPNProtoProperty, false },
+ { flimflam::kOpenVPNProviderProperty, false },
+ { flimflam::kOpenVPNPushPeerInfoProperty, false },
+ { flimflam::kOpenVPNRemoteCertEKUProperty, false },
+ { flimflam::kOpenVPNRemoteCertKUProperty, false },
+ { flimflam::kOpenVPNRemoteCertTLSProperty, false },
+ { flimflam::kOpenVPNRenegSecProperty, false },
+ { flimflam::kOpenVPNServerPollTimeoutProperty, false },
+ { flimflam::kOpenVPNShaperProperty, false },
+ { flimflam::kOpenVPNStaticChallengeProperty, false },
+ { flimflam::kOpenVPNTLSAuthContentsProperty, false },
+ { flimflam::kOpenVPNTLSRemoteProperty, false },
+ { flimflam::kOpenVPNUserProperty, false },
+ { flimflam::kProviderHostProperty, false },
+ { flimflam::kProviderNameProperty, false },
+ { flimflam::kProviderTypeProperty, false },
+ { kOpenVPNCertProperty, false },
+ { kOpenVPNKeyProperty, false },
+ { kOpenVPNPingExitProperty, false },
+ { kOpenVPNPingProperty, false },
+ { kOpenVPNPingRestartProperty, false },
+ { kOpenVPNTLSAuthProperty, false },
+ { kOpenVPNVerbProperty, false },
+ { kVPNMTUProperty, false },
+ { NULL, false },
+};
} // namespace
// static
@@ -335,12 +391,12 @@
options->push_back("--syslog");
// TODO(petkov): Enable verbosity based on shill logging options too.
- AppendValueOption("OpenVPN.Verb", "--verb", options);
+ AppendValueOption(kOpenVPNVerbProperty, "--verb", options);
- AppendValueOption("VPN.MTU", "--mtu", options);
+ AppendValueOption(kVPNMTUProperty, "--mtu", options);
AppendValueOption(flimflam::kOpenVPNProtoProperty, "--proto", options);
AppendValueOption(flimflam::kOpenVPNPortProperty, "--port", options);
- AppendValueOption("OpenVPN.TLSAuth", "--tls-auth", options);
+ AppendValueOption(kOpenVPNTLSAuthProperty, "--tls-auth", options);
// TODO(petkov): Implement this.
LOG_IF(ERROR, args_.ContainsString(flimflam::kOpenVPNTLSAuthContentsProperty))
@@ -367,15 +423,15 @@
<< "Support for NSS CA not implemented yet.";
// Client-side ping support.
- AppendValueOption("OpenVPN.Ping", "--ping", options);
- AppendValueOption("OpenVPN.PingExit", "--ping-exit", options);
- AppendValueOption("OpenVPN.PingRestart", "--ping-restart", options);
+ AppendValueOption(kOpenVPNPingProperty, "--ping", options);
+ AppendValueOption(kOpenVPNPingExitProperty, "--ping-exit", options);
+ AppendValueOption(kOpenVPNPingRestartProperty, "--ping-restart", options);
AppendValueOption(flimflam::kOpenVPNCaCertProperty, "--ca", options);
- AppendValueOption("OpenVPN.Cert", "--cert", options);
+ AppendValueOption(kOpenVPNCertProperty, "--cert", options);
AppendValueOption(
flimflam::kOpenVPNNsCertTypeProperty, "--ns-cert-type", options);
- AppendValueOption("OpenVPN.Key", "--key", options);
+ AppendValueOption(kOpenVPNKeyProperty, "--key", options);
// TODO(petkov): Implement this.
LOG_IF(ERROR, args_.ContainsString(flimflam::kOpenVPNClientCertIdProperty))
@@ -477,4 +533,33 @@
Cleanup(Service::kStateIdle);
}
+bool OpenVPNDriver::Load(StoreInterface *storage, const string &storage_id) {
+ for (int i = 0; kProperties[i].property; i++) {
+ const string property = kProperties[i].property;
+ string value;
+ bool loaded = kProperties[i].crypted ?
+ storage->GetCryptedString(storage_id, property, &value) :
+ storage->GetString(storage_id, property, &value);
+ if (loaded) {
+ args_.SetString(property, value);
+ }
+ }
+ return true;
+}
+
+bool OpenVPNDriver::Save(StoreInterface *storage, const string &storage_id) {
+ for (int i = 0; kProperties[i].property; i++) {
+ const string property = kProperties[i].property;
+ const string value = args_.LookupString(property, "");
+ if (value.empty()) {
+ storage->DeleteKey(storage_id, property);
+ } else if (kProperties[i].crypted) {
+ storage->SetCryptedString(storage_id, property, value);
+ } else {
+ storage->SetString(storage_id, property, value);
+ }
+ }
+ return true;
+}
+
} // namespace shill
diff --git a/openvpn_driver.h b/openvpn_driver.h
index 86b1899..374258b 100644
--- a/openvpn_driver.h
+++ b/openvpn_driver.h
@@ -52,6 +52,9 @@
int interface_index);
virtual void Disconnect();
+ virtual bool Load(StoreInterface *storage, const std::string &storage_id);
+ virtual bool Save(StoreInterface *storage, const std::string &storage_id);
+
private:
friend class OpenVPNDriverTest;
FRIEND_TEST(OpenVPNDriverTest, AppendFlag);
diff --git a/openvpn_driver_unittest.cc b/openvpn_driver_unittest.cc
index 77ebeaf..e4ede64 100644
--- a/openvpn_driver_unittest.cc
+++ b/openvpn_driver_unittest.cc
@@ -21,6 +21,7 @@
#include "shill/mock_manager.h"
#include "shill/mock_metrics.h"
#include "shill/mock_service.h"
+#include "shill/mock_store.h"
#include "shill/mock_vpn.h"
#include "shill/mock_vpn_service.h"
#include "shill/nice_mock_control.h"
@@ -32,7 +33,9 @@
using std::string;
using std::vector;
using testing::_;
+using testing::AnyNumber;
using testing::DoAll;
+using testing::Ne;
using testing::NiceMock;
using testing::Return;
using testing::SetArgumentPointee;
@@ -82,6 +85,10 @@
driver_->args_ = args_;
}
+ KeyValueStore *GetArgs() {
+ return &driver_->args_;
+ }
+
// Used to assert that a flag appears in the options.
void ExpectInFlags(const vector<string> &options, const string &flag,
const string &value);
@@ -518,4 +525,47 @@
EXPECT_TRUE(file_util::PathExists(FilePath(SYSROOT).Append(vpn_script)));
}
+TEST_F(OpenVPNDriverTest, Load) {
+ MockStore storage;
+ static const char kStorageID[] = "vpn_service_id";
+ const string port = "1234";
+ const string password = "random-password";
+ EXPECT_CALL(storage, GetString(kStorageID, _, _))
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(storage, GetString(kStorageID, flimflam::kOpenVPNPortProperty, _))
+ .WillOnce(DoAll(SetArgumentPointee<2>(port), Return(true)));
+ EXPECT_CALL(storage, GetCryptedString(kStorageID,
+ flimflam::kOpenVPNPasswordProperty,
+ _))
+ .WillOnce(DoAll(SetArgumentPointee<2>(password), Return(true)));
+ EXPECT_TRUE(driver_->Load(&storage, kStorageID));
+ EXPECT_EQ(port,
+ GetArgs()->LookupString(flimflam::kOpenVPNPortProperty, ""));
+ EXPECT_EQ(password,
+ GetArgs()->LookupString(flimflam::kOpenVPNPasswordProperty, ""));
+}
+
+TEST_F(OpenVPNDriverTest, Store) {
+ const string key_direction = "1";
+ const string password = "foobar";
+ args_.SetString(flimflam::kOpenVPNKeyDirectionProperty, key_direction);
+ args_.SetString(flimflam::kOpenVPNPasswordProperty, password);
+ SetArgs();
+ MockStore storage;
+ static const char kStorageID[] = "vpn_service_id";
+ EXPECT_CALL(storage,
+ SetString(kStorageID,
+ flimflam::kOpenVPNKeyDirectionProperty,
+ key_direction))
+ .WillOnce(Return(true));
+ EXPECT_CALL(storage, SetCryptedString(kStorageID,
+ flimflam::kOpenVPNPasswordProperty,
+ password))
+ .WillOnce(Return(true));
+ EXPECT_CALL(storage, DeleteKey(kStorageID, _)).Times(AnyNumber());
+ EXPECT_CALL(storage, DeleteKey(kStorageID, flimflam::kOpenVPNAuthProperty))
+ .Times(1);
+ EXPECT_TRUE(driver_->Save(&storage, kStorageID));
+}
+
} // namespace shill
diff --git a/vpn_driver.h b/vpn_driver.h
index b829951..1f26fe6 100644
--- a/vpn_driver.h
+++ b/vpn_driver.h
@@ -14,6 +14,7 @@
namespace shill {
class Error;
+class StoreInterface;
class VPNDriver {
public:
@@ -23,6 +24,8 @@
int interface_index) = 0;
virtual void Connect(const VPNServiceRefPtr &service, Error *error) = 0;
virtual void Disconnect() = 0;
+ virtual bool Load(StoreInterface *storage, const std::string &storage_id) = 0;
+ virtual bool Save(StoreInterface *storage, const std::string &storage_id) = 0;
};
} // namespace shill
diff --git a/vpn_service.cc b/vpn_service.cc
index 6264cb8..e2583fe 100644
--- a/vpn_service.cc
+++ b/vpn_service.cc
@@ -70,4 +70,14 @@
return "/";
}
+bool VPNService::Load(StoreInterface *storage) {
+ return Service::Load(storage) &&
+ driver_->Load(storage, GetStorageIdentifier());
+}
+
+bool VPNService::Save(StoreInterface *storage) {
+ return Service::Save(storage) &&
+ driver_->Save(storage, GetStorageIdentifier());
+}
+
} // namespace shill
diff --git a/vpn_service.h b/vpn_service.h
index a004cc7..203357f 100644
--- a/vpn_service.h
+++ b/vpn_service.h
@@ -28,6 +28,8 @@
virtual void Connect(Error *error);
virtual void Disconnect(Error *error);
virtual std::string GetStorageIdentifier() const;
+ virtual bool Load(StoreInterface *storage);
+ virtual bool Save(StoreInterface *storage);
VPNDriver *driver() const { return driver_.get(); }
diff --git a/vpn_service_unittest.cc b/vpn_service_unittest.cc
index 10a90b4..9e603f1 100644
--- a/vpn_service_unittest.cc
+++ b/vpn_service_unittest.cc
@@ -11,9 +11,12 @@
#include "shill/nice_mock_control.h"
#include "shill/mock_adaptors.h"
#include "shill/mock_metrics.h"
+#include "shill/mock_store.h"
#include "shill/mock_vpn_driver.h"
using testing::_;
+using testing::NiceMock;
+using testing::Return;
namespace shill {
@@ -84,4 +87,21 @@
EXPECT_EQ(Error::kNotSupported, error.type());
}
+TEST_F(VPNServiceTest, Load) {
+ NiceMock<MockStore> storage;
+ static const char kStorageID[] = "storage-id";
+ service_->set_storage_id(kStorageID);
+ EXPECT_CALL(storage, ContainsGroup(kStorageID)).WillOnce(Return(true));
+ EXPECT_CALL(*driver_, Load(&storage, kStorageID)).WillOnce(Return(true));
+ EXPECT_TRUE(service_->Load(&storage));
+}
+
+TEST_F(VPNServiceTest, Save) {
+ NiceMock<MockStore> storage;
+ static const char kStorageID[] = "storage-id";
+ service_->set_storage_id(kStorageID);
+ EXPECT_CALL(*driver_, Save(&storage, kStorageID)).WillOnce(Return(true));
+ EXPECT_TRUE(service_->Save(&storage));
+}
+
} // namespace shill