shill: openvpn: Support no-OTP user/password authentication.

This also fixes a flimflam bug where passwords were sent unescaped, so \ and "
weren't legal password characters in no-OTP authentication mode.

BUG=chromium:137970
TEST=unit tests

Change-Id: I0caad371a5db91739eaf83fc587ad88df1433c77
Reviewed-on: https://gerrit.chromium.org/gerrit/28266
Tested-by: Darin Petkov <petkov@chromium.org>
Reviewed-by: Paul Stewart <pstew@chromium.org>
Commit-Ready: Darin Petkov <petkov@chromium.org>
diff --git a/openvpn_management_server_unittest.cc b/openvpn_management_server_unittest.cc
index edae281..9852cbe 100644
--- a/openvpn_management_server_unittest.cc
+++ b/openvpn_management_server_unittest.cc
@@ -65,6 +65,14 @@
     ExpectSend("password \"Auth\" \"SCRV1:eW95bw==:MTIzNDU2\"\n");
   }
 
+  void ExpectAuthenticationResponse() {
+    driver_.args()->SetString(flimflam::kOpenVPNUserProperty, "jojo");
+    driver_.args()->SetString(flimflam::kOpenVPNPasswordProperty, "yoyo");
+    SetConnectedSocket();
+    ExpectSend("username \"Auth\" jojo\n");
+    ExpectSend("password \"Auth\" \"yoyo\"\n");
+  }
+
   void ExpectPINResponse() {
     driver_.args()->SetString(flimflam::kOpenVPNPinProperty, "987654");
     SetConnectedSocket();
@@ -254,6 +262,13 @@
   EXPECT_FALSE(driver_.args()->ContainsString(flimflam::kOpenVPNOTPProperty));
 }
 
+TEST_F(OpenVPNManagementServerTest, ProcessNeedPasswordMessageAuth) {
+  ExpectAuthenticationResponse();
+  EXPECT_TRUE(
+      server_.ProcessNeedPasswordMessage(
+          ">PASSWORD:Need 'Auth' username/password"));
+}
+
 TEST_F(OpenVPNManagementServerTest, ProcessNeedPasswordMessageTPMToken) {
   ExpectPINResponse();
   EXPECT_TRUE(
@@ -293,6 +308,18 @@
   EXPECT_FALSE(driver_.args()->ContainsString(flimflam::kOpenVPNOTPProperty));
 }
 
+TEST_F(OpenVPNManagementServerTest, PerformAuthenticationNoCreds) {
+  EXPECT_CALL(driver_, Cleanup(Service::kStateFailure)).Times(2);
+  server_.PerformAuthentication("Auth");
+  driver_.args()->SetString(flimflam::kOpenVPNUserProperty, "jojo");
+  server_.PerformAuthentication("Auth");
+}
+
+TEST_F(OpenVPNManagementServerTest, PerformAuthentication) {
+  ExpectAuthenticationResponse();
+  server_.PerformAuthentication("Auth");
+}
+
 TEST_F(OpenVPNManagementServerTest, ProcessHoldMessage) {
   EXPECT_FALSE(server_.hold_release_);
   EXPECT_FALSE(server_.hold_waiting_);
@@ -342,8 +369,8 @@
 
 TEST_F(OpenVPNManagementServerTest, SendPassword) {
   SetConnectedSocket();
-  ExpectSend("password \"Auth\" \"foobar\"\n");
-  server_.SendPassword("Auth", "foobar");
+  ExpectSend("password \"Auth\" \"foo\\\"bar\"\n");
+  server_.SendPassword("Auth", "foo\"bar");
 }
 
 TEST_F(OpenVPNManagementServerTest, ProcessFailedPasswordMessage) {
@@ -377,4 +404,13 @@
   EXPECT_FALSE(server_.hold_waiting_);
 }
 
+TEST_F(OpenVPNManagementServerTest, EscapeToQuote) {
+  EXPECT_EQ("", OpenVPNManagementServer::EscapeToQuote(""));
+  EXPECT_EQ("foo './", OpenVPNManagementServer::EscapeToQuote("foo './"));
+  EXPECT_EQ("\\\\", OpenVPNManagementServer::EscapeToQuote("\\"));
+  EXPECT_EQ("\\\"", OpenVPNManagementServer::EscapeToQuote("\""));
+  EXPECT_EQ("\\\\\\\"foo\\\\bar\\\"",
+            OpenVPNManagementServer::EscapeToQuote("\\\"foo\\bar\""));
+}
+
 }  // namespace shill