shill: OpenVPNDriver: Accept and use Token parameter

The OpenVPN.Token property is similar to the OpenVPN.OTP property
in that it is a one-time-use credential that can be used during
Static Challenge authentication.  The semantics of how this
credential is presented is slightly different, and it does not
require a password parameter.

BUG=chromium:347298
TEST=Unit tests

Change-Id: I9ee8160b40da8b71c1facc2bdfe9453b2a4f3c6e
Reviewed-on: https://chromium-review.googlesource.com/188165
Reviewed-by: Paul Stewart <pstew@chromium.org>
Commit-Queue: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
diff --git a/openvpn_management_server.cc b/openvpn_management_server.cc
index 07e1246..5349b8f 100644
--- a/openvpn_management_server.cc
+++ b/openvpn_management_server.cc
@@ -261,27 +261,38 @@
   string user = driver_->args()->LookupString(kOpenVPNUserProperty, "");
   string password = driver_->args()->LookupString(kOpenVPNPasswordProperty, "");
   string otp = driver_->args()->LookupString(kOpenVPNOTPProperty, "");
-  if (user.empty() || password.empty() || otp.empty()) {
+  string token = driver_->args()->LookupString(kOpenVPNTokenProperty, "");
+  if (user.empty() || (token.empty() && (password.empty() || otp.empty()))) {
     NOTIMPLEMENTED() << ": Missing credentials:"
                      << (user.empty() ? " no-user" : "")
+                     << (token.empty() ? " no-token" : "")
                      << (password.empty() ? " no-password" : "")
                      << (otp.empty() ? " no-otp" : "");
     driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
     return;
   }
-  string b64_password;
-  string b64_otp;
-  if (!glib_->B64Encode(password, &b64_password) ||
-      !glib_->B64Encode(otp, &b64_otp)) {
-    LOG(ERROR) << "Unable to base64-encode credentials.";
-    return;
+
+  string password_encoded;
+  if (!token.empty()) {
+    password_encoded = StringPrintf("t:%s", token.c_str());
+    // Don't reuse token.
+    driver_->args()->RemoveString(kOpenVPNTokenProperty);
+  } else {
+    string b64_password;
+    string b64_otp;
+    if (!glib_->B64Encode(password, &b64_password) ||
+        !glib_->B64Encode(otp, &b64_otp)) {
+      LOG(ERROR) << "Unable to base64-encode credentials.";
+      return;
+    }
+    password_encoded = StringPrintf("SCRV1:%s:%s",
+                                    b64_password.c_str(),
+                                    b64_otp.c_str());
+    // Don't reuse OTP.
+    driver_->args()->RemoveString(kOpenVPNOTPProperty);
   }
   SendUsername(tag, user);
-  SendPassword(tag, StringPrintf("SCRV1:%s:%s",
-                                 b64_password.c_str(),
-                                 b64_otp.c_str()));
-  // Don't reuse OTP.
-  driver_->args()->RemoveString(kOpenVPNOTPProperty);
+  SendPassword(tag, password_encoded);
 }
 
 void OpenVPNManagementServer::PerformAuthentication(const string &tag) {