summaryrefslogtreecommitdiff
path: root/remoting/host
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2013-08-23 16:39:15 +0100
committerTorne (Richard Coles) <torne@google.com>2013-08-23 16:39:15 +0100
commit3551c9c881056c480085172ff9840cab31610854 (patch)
tree23660320f5f4c279966609cf9da7491b96d10ca8 /remoting/host
parent4e9d9adbbb6cf287125ca44a0823791a570472f5 (diff)
downloadchromium_org-3551c9c881056c480085172ff9840cab31610854.tar.gz
Merge from Chromium at DEPS revision r219274
This commit was generated by merge_to_master.py. Change-Id: Ibb7f41396cadf4071e89153e1913c986d126f65d
Diffstat (limited to 'remoting/host')
-rw-r--r--remoting/host/chromoting_host.cc4
-rw-r--r--remoting/host/chromoting_host.h2
-rw-r--r--remoting/host/chromoting_host_context.cc2
-rw-r--r--remoting/host/client_session.cc2
-rw-r--r--remoting/host/constants_mac.cc4
-rw-r--r--remoting/host/constants_mac.h3
-rw-r--r--remoting/host/host_config.cc1
-rw-r--r--remoting/host/host_config.h2
-rw-r--r--remoting/host/host_main.cc11
-rw-r--r--remoting/host/installer/linux/Makefile5
-rw-r--r--remoting/host/installer/mac/ChromotingHostService.pkgproj67
-rw-r--r--remoting/host/installer/mac/uninstaller/remoting_uninstaller.mm1
-rw-r--r--remoting/host/keygen_main.cc37
-rw-r--r--remoting/host/local_input_monitor_win.cc2
-rw-r--r--remoting/host/pairing_registry_delegate_win.cc3
-rw-r--r--remoting/host/plugin/host_script_object.cc71
-rw-r--r--remoting/host/remoting_me2me_host.cc51
-rw-r--r--remoting/host/setup/daemon_controller_linux.cc6
-rw-r--r--remoting/host/setup/host_starter.cc60
-rw-r--r--remoting/host/setup/host_starter.h8
-rw-r--r--remoting/host/setup/native_messaging_host.cc68
-rw-r--r--remoting/host/setup/native_messaging_host.h17
-rw-r--r--remoting/host/setup/native_messaging_host_unittest.cc2
-rw-r--r--remoting/host/setup/oauth_client.cc93
-rw-r--r--remoting/host/setup/oauth_client.h79
-rw-r--r--remoting/host/setup/service_client.cc51
-rw-r--r--remoting/host/setup/service_client.h3
-rw-r--r--remoting/host/setup/start_host.cc4
-rw-r--r--remoting/host/setup/win/host_configurer.cc3
-rw-r--r--remoting/host/signaling_connector.cc25
-rw-r--r--remoting/host/signaling_connector.h6
31 files changed, 535 insertions, 158 deletions
diff --git a/remoting/host/chromoting_host.cc b/remoting/host/chromoting_host.cc
index 82f0d6e4b0..d7780f1d2d 100644
--- a/remoting/host/chromoting_host.cc
+++ b/remoting/host/chromoting_host.cc
@@ -109,13 +109,13 @@ ChromotingHost::~ChromotingHost() {
FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnShutdown());
}
-void ChromotingHost::Start(const std::string& xmpp_login) {
+void ChromotingHost::Start(const std::string& host_owner) {
DCHECK(CalledOnValidThread());
DCHECK(!started_);
LOG(INFO) << "Starting host";
started_ = true;
- FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnStart(xmpp_login));
+ FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnStart(host_owner));
// Start the SessionManager, supplying this ChromotingHost as the listener.
session_manager_->Init(signal_strategy_, this);
diff --git a/remoting/host/chromoting_host.h b/remoting/host/chromoting_host.h
index 614b46678a..ee4c5874f4 100644
--- a/remoting/host/chromoting_host.h
+++ b/remoting/host/chromoting_host.h
@@ -86,7 +86,7 @@ class ChromotingHost : public base::NonThreadSafe,
// network and start listening for incoming connections.
//
// This method can only be called once during the lifetime of this object.
- void Start(const std::string& xmpp_login);
+ void Start(const std::string& host_owner);
// HostStatusMonitor interface.
virtual void AddStatusObserver(HostStatusObserver* observer) OVERRIDE;
diff --git a/remoting/host/chromoting_host_context.cc b/remoting/host/chromoting_host_context.cc
index aa3146cb81..350404b24c 100644
--- a/remoting/host/chromoting_host_context.cc
+++ b/remoting/host/chromoting_host_context.cc
@@ -40,7 +40,7 @@ ChromotingHostContext::ChromotingHostContext(
"ChromotingEncodeThread", ui_task_runner_);
url_request_context_getter_ = new URLRequestContextGetter(
- ui_task_runner_, network_task_runner_);
+ network_task_runner_);
}
ChromotingHostContext::~ChromotingHostContext() {
diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc
index 933ded3e47..b001a392db 100644
--- a/remoting/host/client_session.cc
+++ b/remoting/host/client_session.cc
@@ -177,7 +177,7 @@ void ClientSession::SetCapabilities(
void ClientSession::RequestPairing(
const protocol::PairingRequest& pairing_request) {
- if (pairing_request.has_client_name()) {
+ if (pairing_registry_ && pairing_request.has_client_name()) {
protocol::PairingRegistry::Pairing pairing =
pairing_registry_->CreatePairing(pairing_request.client_name());
protocol::PairingResponse pairing_response;
diff --git a/remoting/host/constants_mac.cc b/remoting/host/constants_mac.cc
index 9b7938456f..3b48ca0f93 100644
--- a/remoting/host/constants_mac.cc
+++ b/remoting/host/constants_mac.cc
@@ -36,6 +36,10 @@ const char kServicePlistPath[] = LAUNCH_AGENTS_DIR SERVICE_NAME ".plist";
const char kLogFilePath[] = LOG_DIR SERVICE_NAME ".log";
const char kLogFileConfigPath[] = LOG_CONFIG_DIR SERVICE_NAME ".conf";
+const char kNativeMessagingManifestPath[] =
+ "/Library/Google/Chrome/NativeMessagingHosts/"
+ "com.google.chrome.remote_desktop.json";
+
const char kBrandedUninstallerPath[] = APPLICATIONS_DIR
"Chrome Remote Desktop Host Uninstaller.app";
const char kUnbrandedUninstallerPath[] = APPLICATIONS_DIR
diff --git a/remoting/host/constants_mac.h b/remoting/host/constants_mac.h
index ac288e5ccf..5d131d2875 100644
--- a/remoting/host/constants_mac.h
+++ b/remoting/host/constants_mac.h
@@ -52,6 +52,9 @@ extern const char kLogFilePath[];
// Path to the log config file
extern const char kLogFileConfigPath[];
+// Path to the native messaging host manifest
+extern const char kNativeMessagingManifestPath[];
+
// The branded and unbranded names for the uninstaller.
// This is the only file that changes names based on branding. We define both
// because we want local dev builds to be able to clean up both files.
diff --git a/remoting/host/host_config.cc b/remoting/host/host_config.cc
index 94b5d49bd2..e81284312a 100644
--- a/remoting/host/host_config.cc
+++ b/remoting/host/host_config.cc
@@ -7,6 +7,7 @@
namespace remoting {
const char kHostEnabledConfigPath[] = "enabled";
+const char kHostOwnerConfigPath[] = "host_owner";
const char kXmppLoginConfigPath[] = "xmpp_login";
const char kXmppAuthTokenConfigPath[] = "xmpp_auth_token";
const char kOAuthRefreshTokenConfigPath[] = "oauth_refresh_token";
diff --git a/remoting/host/host_config.h b/remoting/host/host_config.h
index a8233b5d67..5bd5c5cb49 100644
--- a/remoting/host/host_config.h
+++ b/remoting/host/host_config.h
@@ -19,6 +19,8 @@ namespace remoting {
// Status of the host, whether it is enabled or disabled.
extern const char kHostEnabledConfigPath[];
+// Google account of the owner of this host.
+extern const char kHostOwnerConfigPath[];
// Login used to authenticate in XMPP network.
extern const char kXmppLoginConfigPath[];
// Auth token used to authenticate to XMPP network.
diff --git a/remoting/host/host_main.cc b/remoting/host/host_main.cc
index 25e01e64fb..bf3dc17022 100644
--- a/remoting/host/host_main.cc
+++ b/remoting/host/host_main.cc
@@ -234,14 +234,15 @@ int HostMain(int argc, char** argv) {
// missing and the first argument looks like an origin that represents
// an extension.
CommandLine::StringVector args = command_line->GetArgs();
+ if (!args.empty()) {
#if defined(OS_WIN)
- std::string origin = UTF16ToUTF8(args[0]);
+ std::string origin = UTF16ToUTF8(args[0]);
#else
- std::string origin = args[0];
+ std::string origin = args[0];
#endif
- if (!args.empty() &&
- StartsWithASCII(origin, kExtensionOriginPrefix, true)) {
- process_type = kProcessTypeNativeMessagingHost;
+ if (StartsWithASCII(origin, kExtensionOriginPrefix, true)) {
+ process_type = kProcessTypeNativeMessagingHost;
+ }
}
}
diff --git a/remoting/host/installer/linux/Makefile b/remoting/host/installer/linux/Makefile
index 9fc36bebfb..dd45d26b19 100644
--- a/remoting/host/installer/linux/Makefile
+++ b/remoting/host/installer/linux/Makefile
@@ -11,7 +11,6 @@ RELEASE = $(SRC)/out/Release
INSTALL_DIR = $(DESTDIR)/opt/google/chrome-remote-desktop
CHROME_MANIFEST_DIR = $(DESTDIR)/etc/opt/chrome/native-messaging-hosts
-MANIFEST = $(CHROME_MANIFEST_DIR)/com.google.chrome.remote_desktop.json
ME2ME_PROGNAME = $(RELEASE)/remoting_me2me_host
ME2ME_DEBUGFILE = $(ME2ME_PROGNAME).debug
@@ -30,8 +29,8 @@ install:
"$(INSTALL_DIR)/chrome-remote-desktop"
install "$(TOOLS)/is-remoting-session" "$(INSTALL_DIR)"
- install -T "$(RELEASE)/remoting/native_messaging_manifest.json" \
- -m 0644 "$(MANIFEST)"
+ install "$(RELEASE)/remoting/com.google.chrome.remote_desktop.json" \
+ -m 0644 "$(CHROME_MANIFEST_DIR)"
eu-strip -f "$(ME2ME_DEBUGFILE)" "$(ME2ME_PROGNAME)"
install "$(ME2ME_PROGNAME)" \
diff --git a/remoting/host/installer/mac/ChromotingHostService.pkgproj b/remoting/host/installer/mac/ChromotingHostService.pkgproj
index bc036f8c88..72ced50565 100644
--- a/remoting/host/installer/mac/ChromotingHostService.pkgproj
+++ b/remoting/host/installer/mac/ChromotingHostService.pkgproj
@@ -164,6 +164,73 @@
</dict>
<dict>
<key>CHILDREN</key>
+ <array>
+ <dict>
+ <key>CHILDREN</key>
+ <array>
+ <dict>
+ <key>CHILDREN</key>
+ <array>
+ <dict>
+ <key>CHILDREN</key>
+ <array/>
+ <key>GID</key>
+ <integer>0</integer>
+ <key>PATH</key>
+ <string>Config/com.google.chrome.remote_desktop.json</string>
+ <key>PATH_TYPE</key>
+ <integer>1</integer>
+ <key>PERMISSIONS</key>
+ <integer>420</integer>
+ <key>TYPE</key>
+ <integer>3</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ </array>
+ <key>GID</key>
+ <integer>0</integer>
+ <key>PATH</key>
+ <string>NativeMessagingHosts</string>
+ <key>PATH_TYPE</key>
+ <integer>0</integer>
+ <key>PERMISSIONS</key>
+ <integer>493</integer>
+ <key>TYPE</key>
+ <integer>2</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ </array>
+ <key>GID</key>
+ <integer>0</integer>
+ <key>PATH</key>
+ <string>Chrome</string>
+ <key>PATH_TYPE</key>
+ <integer>0</integer>
+ <key>PERMISSIONS</key>
+ <integer>493</integer>
+ <key>TYPE</key>
+ <integer>2</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ </array>
+ <key>GID</key>
+ <integer>0</integer>
+ <key>PATH</key>
+ <string>Google</string>
+ <key>PATH_TYPE</key>
+ <integer>0</integer>
+ <key>PERMISSIONS</key>
+ <integer>493</integer>
+ <key>TYPE</key>
+ <integer>2</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>0</integer>
diff --git a/remoting/host/installer/mac/uninstaller/remoting_uninstaller.mm b/remoting/host/installer/mac/uninstaller/remoting_uninstaller.mm
index eb984d1956..eec5e5856b 100644
--- a/remoting/host/installer/mac/uninstaller/remoting_uninstaller.mm
+++ b/remoting/host/installer/mac/uninstaller/remoting_uninstaller.mm
@@ -143,6 +143,7 @@ const char kKeystonePID[] = "com.google.chrome_remote_desktop";
[self sudoDelete:remoting::kPrefPaneFilePath usingAuth:authRef];
[self sudoDelete:remoting::kLogFilePath usingAuth:authRef];
[self sudoDelete:remoting::kLogFileConfigPath usingAuth:authRef];
+ [self sudoDelete:remoting::kNativeMessagingManifestPath usingAuth:authRef];
[self sudoDelete:remoting::kBrandedUninstallerPath usingAuth:authRef];
[self sudoDelete:remoting::kUnbrandedUninstallerPath usingAuth:authRef];
diff --git a/remoting/host/keygen_main.cc b/remoting/host/keygen_main.cc
deleted file mode 100644
index 9102756100..0000000000
--- a/remoting/host/keygen_main.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.
-//
-// This is a tool used by register_host.py to generate RSA keypair. It just
-// generates new keys and prints them on stdout.
-//
-// This code will need to be integrated with the host registration UI.
-
-#include <stdio.h>
-
-#include <vector>
-
-#include "base/at_exit.h"
-#include "base/base64.h"
-#include "crypto/rsa_private_key.h"
-#include "base/memory/scoped_ptr.h"
-
-int main(int argc, char** argv) {
- base::AtExitManager exit_manager;
-
- scoped_ptr<crypto::RSAPrivateKey> key(crypto::RSAPrivateKey::Create(2048));
-
- std::vector<uint8> private_key_buf;
- key->ExportPrivateKey(&private_key_buf);
- std::string private_key_str(private_key_buf.begin(), private_key_buf.end());
- std::string private_key_base64;
- base::Base64Encode(private_key_str, &private_key_base64);
- printf("%s\n", private_key_base64.c_str());
-
- std::vector<uint8> public_key_buf;
- key->ExportPublicKey(&public_key_buf);
- std::string public_key_str(public_key_buf.begin(), public_key_buf.end());
- std::string public_key_base64;
- base::Base64Encode(public_key_str, &public_key_base64);
- printf("%s\n", public_key_base64.c_str());
-}
diff --git a/remoting/host/local_input_monitor_win.cc b/remoting/host/local_input_monitor_win.cc
index 2796bf0b0b..2459c0fe22 100644
--- a/remoting/host/local_input_monitor_win.cc
+++ b/remoting/host/local_input_monitor_win.cc
@@ -148,7 +148,7 @@ void LocalInputMonitorWin::Core::StopOnUiThread() {
device.dwFlags = RIDEV_REMOVE;
device.usUsagePage = kGenericDesktopPage;
device.usUsage = kMouseUsage;
- device.hwndTarget = window_->hwnd();
+ device.hwndTarget = NULL;
// The error is harmless, ignore it.
RegisterRawInputDevices(&device, 1, sizeof(device));
diff --git a/remoting/host/pairing_registry_delegate_win.cc b/remoting/host/pairing_registry_delegate_win.cc
index c7f11d9288..20230d0d50 100644
--- a/remoting/host/pairing_registry_delegate_win.cc
+++ b/remoting/host/pairing_registry_delegate_win.cc
@@ -83,8 +83,7 @@ bool WriteValue(base::win::RegKey& key,
// presubmit: allow wstring
std::wstring value_json = UTF8ToWide(value_json_utf8);
- LONG result = key.WriteValue(value_name,
- UTF8ToWide(value_json_utf8).c_str());
+ LONG result = key.WriteValue(value_name, value_json.c_str());
if (result != ERROR_SUCCESS) {
SetLastError(result);
PLOG(ERROR) << "Cannot write value '" << value_name << "'";
diff --git a/remoting/host/plugin/host_script_object.cc b/remoting/host/plugin/host_script_object.cc
index 1c8771dd74..b766cad5f4 100644
--- a/remoting/host/plugin/host_script_object.cc
+++ b/remoting/host/plugin/host_script_object.cc
@@ -16,6 +16,7 @@
#include "base/threading/platform_thread.h"
#include "base/values.h"
#include "net/base/net_util.h"
+#include "net/socket/client_socket_factory.h"
#include "remoting/base/auth_token_util.h"
#include "remoting/base/auto_thread.h"
#include "remoting/base/resources.h"
@@ -107,9 +108,7 @@ class HostNPScriptObject::It2MeImpl
// Methods called by the script object, from the plugin thread.
// Creates It2Me host structures and starts the host.
- void Connect(const std::string& uid,
- const std::string& auth_token,
- const std::string& auth_service);
+ void Connect();
// Disconnects the host, ready for tear-down.
// Also called internally, from the network thread.
@@ -135,14 +134,10 @@ class HostNPScriptObject::It2MeImpl
bool IsConnected() const;
// Called by Connect() to check for policies and start connection process.
- void ReadPolicyAndConnect(const std::string& uid,
- const std::string& auth_token,
- const std::string& auth_service);
+ void ReadPolicyAndConnect();
// Called by ReadPolicyAndConnect once policies have been read.
- void FinishConnect(const std::string& uid,
- const std::string& auth_token,
- const std::string& auth_service);
+ void FinishConnect();
// Called when the support host registration completes.
void OnReceivedSupportID(bool success,
@@ -223,15 +218,11 @@ HostNPScriptObject::It2MeImpl::It2MeImpl(
DCHECK(plugin_task_runner_->BelongsToCurrentThread());
}
-void HostNPScriptObject::It2MeImpl::Connect(
- const std::string& uid,
- const std::string& auth_token,
- const std::string& auth_service) {
+void HostNPScriptObject::It2MeImpl::Connect() {
if (!host_context_->ui_task_runner()->BelongsToCurrentThread()) {
DCHECK(plugin_task_runner_->BelongsToCurrentThread());
host_context_->ui_task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&It2MeImpl::Connect, this, uid, auth_token, auth_service));
+ FROM_HERE, base::Bind(&It2MeImpl::Connect, this));
return;
}
@@ -248,9 +239,7 @@ void HostNPScriptObject::It2MeImpl::Connect(
// Switch to the network thread to start the actual connection.
host_context_->network_task_runner()->PostTask(
- FROM_HERE, base::Bind(
- &It2MeImpl::ReadPolicyAndConnect, this,
- uid, auth_token, auth_service));
+ FROM_HERE, base::Bind(&It2MeImpl::ReadPolicyAndConnect, this));
}
void HostNPScriptObject::It2MeImpl::Disconnect() {
@@ -305,10 +294,7 @@ void HostNPScriptObject::It2MeImpl::RequestNatPolicy() {
UpdateNatPolicy(nat_traversal_enabled_);
}
-void HostNPScriptObject::It2MeImpl::ReadPolicyAndConnect(
- const std::string& uid,
- const std::string& auth_token,
- const std::string& auth_service) {
+void HostNPScriptObject::It2MeImpl::ReadPolicyAndConnect() {
DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
SetState(kStarting);
@@ -316,19 +302,15 @@ void HostNPScriptObject::It2MeImpl::ReadPolicyAndConnect(
// Only proceed to FinishConnect() if at least one policy update has been
// received.
if (policy_received_) {
- FinishConnect(uid, auth_token, auth_service);
+ FinishConnect();
} else {
// Otherwise, create the policy watcher, and thunk the connect.
pending_connect_ =
- base::Bind(&It2MeImpl::FinishConnect, this,
- uid, auth_token, auth_service);
+ base::Bind(&It2MeImpl::FinishConnect, this);
}
}
-void HostNPScriptObject::It2MeImpl::FinishConnect(
- const std::string& uid,
- const std::string& auth_token,
- const std::string& auth_service) {
+void HostNPScriptObject::It2MeImpl::FinishConnect() {
DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
if (state_ != kStarting) {
@@ -338,7 +320,8 @@ void HostNPScriptObject::It2MeImpl::FinishConnect(
// Check the host domain policy.
if (!required_host_domain_.empty() &&
- !EndsWith(uid, std::string("@") + required_host_domain_, false)) {
+ !EndsWith(xmpp_server_config_.username,
+ std::string("@") + required_host_domain_, false)) {
SetState(kInvalidDomainError);
return;
}
@@ -349,8 +332,8 @@ void HostNPScriptObject::It2MeImpl::FinishConnect(
// Create XMPP connection.
scoped_ptr<SignalStrategy> signal_strategy(
- new XmppSignalStrategy(host_context_->url_request_context_getter(),
- uid, auth_token, auth_service,
+ new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(),
+ host_context_->url_request_context_getter(),
xmpp_server_config_));
// Request registration of the host for support.
@@ -405,7 +388,7 @@ void HostNPScriptObject::It2MeImpl::FinishConnect(
// Connect signaling and start the host.
signal_strategy_->Connect();
- host_->Start(uid);
+ host_->Start(xmpp_server_config_.username);
SetState(kRequestedAccessCode);
return;
@@ -1015,7 +998,7 @@ bool HostNPScriptObject::Enumerate(std::vector<std::string>* values) {
return true;
}
-// string uid, string auth_token
+// string username, string auth_token
bool HostNPScriptObject::Connect(const NPVariant* args,
uint32_t arg_count,
NPVariant* result) {
@@ -1033,18 +1016,18 @@ bool HostNPScriptObject::Connect(const NPVariant* args,
return false;
}
- std::string uid = StringFromNPVariant(args[0]);
- if (uid.empty()) {
- SetException("connect: bad uid argument");
+ XmppSignalStrategy::XmppServerConfig xmpp_config = xmpp_server_config_;
+
+ xmpp_config.username = StringFromNPVariant(args[0]);
+ if (xmpp_config.username.empty()) {
+ SetException("connect: bad username argument");
return false;
}
std::string auth_service_with_token = StringFromNPVariant(args[1]);
- std::string auth_token;
- std::string auth_service;
- ParseAuthTokenWithService(auth_service_with_token, &auth_token,
- &auth_service);
- if (auth_token.empty()) {
+ ParseAuthTokenWithService(auth_service_with_token, &xmpp_config.auth_token,
+ &xmpp_config.auth_service);
+ if (xmpp_config.auth_token.empty()) {
SetException("connect: auth_service_with_token argument has empty token");
return false;
}
@@ -1060,8 +1043,8 @@ bool HostNPScriptObject::Connect(const NPVariant* args,
// Create the It2Me host implementation and start connecting.
it2me_impl_ = new It2MeImpl(
host_context.Pass(), plugin_task_runner_, weak_ptr_,
- xmpp_server_config_, directory_bot_jid_);
- it2me_impl_->Connect(uid, auth_token, auth_service);
+ xmpp_config, directory_bot_jid_);
+ it2me_impl_->Connect();
return true;
}
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc
index 52b0fd37da..9ed3383974 100644
--- a/remoting/host/remoting_me2me_host.cc
+++ b/remoting/host/remoting_me2me_host.cc
@@ -29,6 +29,7 @@
#include "ipc/ipc_listener.h"
#include "media/base/media.h"
#include "net/base/network_change_notifier.h"
+#include "net/socket/client_socket_factory.h"
#include "net/socket/ssl_server_socket.h"
#include "net/url_request/url_fetcher.h"
#include "remoting/base/auto_thread_task_runner.h"
@@ -266,9 +267,8 @@ class HostProcess
scoped_refptr<RsaKeyPair> key_pair_;
std::string oauth_refresh_token_;
std::string serialized_config_;
- std::string xmpp_login_;
- std::string xmpp_auth_token_;
- std::string xmpp_auth_service_;
+ std::string host_owner_;
+ bool use_service_account_;
scoped_ptr<policy_hack::PolicyWatcher> policy_watcher_;
bool allow_nat_traversal_;
std::string talkgadget_prefix_;
@@ -303,6 +303,7 @@ HostProcess::HostProcess(scoped_ptr<ChromotingHostContext> context,
int* exit_code_out)
: context_(context.Pass()),
state_(HOST_INITIALIZING),
+ use_service_account_(false),
allow_nat_traversal_(true),
allow_pairing_(true),
curtain_required_(false),
@@ -520,7 +521,8 @@ void HostProcess::CreateAuthenticatorFactory() {
if (token_url_.is_empty() && token_validation_url_.is_empty()) {
factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithSharedSecret(
- local_certificate, key_pair_, host_secret_hash_, pairing_registry);
+ host_owner_, local_certificate, key_pair_, host_secret_hash_,
+ pairing_registry);
} else if (token_url_.is_valid() && token_validation_url_.is_valid()) {
scoped_ptr<protocol::ThirdPartyHostAuthenticator::TokenValidatorFactory>
@@ -528,7 +530,8 @@ void HostProcess::CreateAuthenticatorFactory() {
token_url_, token_validation_url_, key_pair_,
context_->url_request_context_getter()));
factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth(
- local_certificate, key_pair_, token_validator_factory.Pass());
+ host_owner_, local_certificate, key_pair_,
+ token_validator_factory.Pass());
} else {
// TODO(rmsousa): If the policy is bad the host should not go online. It
@@ -709,8 +712,9 @@ bool HostProcess::ApplyConfig(scoped_ptr<JsonHostConfig> config) {
}
// Use an XMPP connection to the Talk network for session signalling.
- if (!config->GetString(kXmppLoginConfigPath, &xmpp_login_) ||
- !(config->GetString(kXmppAuthTokenConfigPath, &xmpp_auth_token_) ||
+ if (!config->GetString(kXmppLoginConfigPath, &xmpp_server_config_.username) ||
+ !(config->GetString(kXmppAuthTokenConfigPath,
+ &xmpp_server_config_.auth_token) ||
config->GetString(kOAuthRefreshTokenConfigPath,
&oauth_refresh_token_))) {
LOG(ERROR) << "XMPP credentials are not defined in the config.";
@@ -718,14 +722,24 @@ bool HostProcess::ApplyConfig(scoped_ptr<JsonHostConfig> config) {
}
if (!oauth_refresh_token_.empty()) {
- xmpp_auth_token_ = ""; // This will be set to the access token later.
- xmpp_auth_service_ = "oauth2";
+ // SignalingConnector is responsible for getting OAuth token.
+ xmpp_server_config_.auth_token = "";
+ xmpp_server_config_.auth_service = "oauth2";
} else if (!config->GetString(kXmppAuthServiceConfigPath,
- &xmpp_auth_service_)) {
+ &xmpp_server_config_.auth_service)) {
// For the me2me host, we default to ClientLogin token for chromiumsync
// because earlier versions of the host had no HTTP stack with which to
// request an OAuth2 access token.
- xmpp_auth_service_ = kChromotingTokenDefaultServiceName;
+ xmpp_server_config_.auth_service = kChromotingTokenDefaultServiceName;
+ }
+
+ if (config->GetString(kHostOwnerConfigPath, &host_owner_)) {
+ // Service account configs have a host_owner, different from the xmpp_login.
+ use_service_account_ = true;
+ } else {
+ // User credential configs only have an xmpp_login, which is also the owner.
+ host_owner_ = xmpp_server_config_.username;
+ use_service_account_ = false;
}
return true;
}
@@ -799,7 +813,7 @@ bool HostProcess::OnHostDomainPolicyUpdate(const std::string& host_domain) {
LOG(INFO) << "Policy sets host domain: " << host_domain;
if (!host_domain.empty() &&
- !EndsWith(xmpp_login_, std::string("@") + host_domain, false)) {
+ !EndsWith(host_owner_, std::string("@") + host_domain, false)) {
ShutdownHost(kInvalidHostDomainExitCode);
}
return false;
@@ -814,7 +828,7 @@ bool HostProcess::OnUsernamePolicyUpdate(bool curtain_required,
LOG(INFO) << "Policy requires host username match.";
std::string username = GetUsername();
bool shutdown = username.empty() ||
- !StartsWithASCII(xmpp_login_, username + std::string("@"),
+ !StartsWithASCII(host_owner_, username + std::string("@"),
false);
#if defined(OS_MACOSX)
@@ -952,9 +966,9 @@ void HostProcess::StartHost() {
state_ = HOST_STARTED;
signal_strategy_.reset(
- new XmppSignalStrategy(context_->url_request_context_getter(),
- xmpp_login_, xmpp_auth_token_,
- xmpp_auth_service_, xmpp_server_config_));
+ new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(),
+ context_->url_request_context_getter(),
+ xmpp_server_config_));
scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker(
new DnsBlackholeChecker(context_->url_request_context_getter(),
@@ -972,7 +986,8 @@ void HostProcess::StartHost() {
if (!oauth_refresh_token_.empty()) {
scoped_ptr<SignalingConnector::OAuthCredentials> oauth_credentials(
new SignalingConnector::OAuthCredentials(
- xmpp_login_, oauth_refresh_token_));
+ xmpp_server_config_.username, oauth_refresh_token_,
+ use_service_account_));
signaling_connector_->EnableOAuth(oauth_credentials.Pass());
}
@@ -1026,7 +1041,7 @@ void HostProcess::StartHost() {
#endif // !defined(REMOTING_MULTI_PROCESS)
host_->SetEnableCurtaining(curtain_required_);
- host_->Start(xmpp_login_);
+ host_->Start(host_owner_);
CreateAuthenticatorFactory();
}
diff --git a/remoting/host/setup/daemon_controller_linux.cc b/remoting/host/setup/daemon_controller_linux.cc
index 1fb259812b..e2d6566da3 100644
--- a/remoting/host/setup/daemon_controller_linux.cc
+++ b/remoting/host/setup/daemon_controller_linux.cc
@@ -36,8 +36,10 @@ namespace {
const char kDaemonScript[] =
"/opt/google/chrome-remote-desktop/chrome-remote-desktop";
-// Timeout for running daemon script.
-const int64 kDaemonTimeoutMs = 5000;
+// Timeout for running daemon script. The script itself sets a timeout when
+// waiting for the host to come online, so the setting here should be at least
+// as long.
+const int64 kDaemonTimeoutMs = 60000;
// Timeout for commands that require password prompt - 5 minutes.
const int64 kSudoTimeoutSeconds = 5 * 60;
diff --git a/remoting/host/setup/host_starter.cc b/remoting/host/setup/host_starter.cc
index d16137bed6..3a0646bb8a 100644
--- a/remoting/host/setup/host_starter.cc
+++ b/remoting/host/setup/host_starter.cc
@@ -95,30 +95,72 @@ void HostStarter::OnRefreshTokenResponse(
NOTREACHED();
}
+// This function is called twice: once with the host owner credentials, and once
+// with the service account credentials.
void HostStarter::OnGetUserEmailResponse(const std::string& user_email) {
if (!main_task_runner_->BelongsToCurrentThread()) {
main_task_runner_->PostTask(FROM_HERE, base::Bind(
&HostStarter::OnGetUserEmailResponse, weak_ptr_, user_email));
return;
}
- user_email_ = user_email;
- // Register the host.
- host_id_ = base::GenerateGUID();
- key_pair_ = RsaKeyPair::Generate();
- service_client_->RegisterHost(
- host_id_, host_name_, key_pair_->GetPublicKey(), access_token_, this);
+
+ if (host_owner_.empty()) {
+ // This is the first callback, with the host owner credentials. Store the
+ // owner's email, and register the host.
+ host_owner_ = user_email;
+ host_id_ = base::GenerateGUID();
+ key_pair_ = RsaKeyPair::Generate();
+
+ std::string host_client_id;
+ host_client_id = google_apis::GetOAuth2ClientID(
+ google_apis::CLIENT_REMOTING_HOST);
+
+ service_client_->RegisterHost(
+ host_id_, host_name_, key_pair_->GetPublicKey(), host_client_id,
+ access_token_, this);
+ } else {
+ // This is the second callback, with the service account credentials.
+ // This email is the service account's email, used to login to XMPP.
+ xmpp_login_ = user_email;
+ StartHostProcess();
+ }
}
-void HostStarter::OnHostRegistered() {
+void HostStarter::OnHostRegistered(const std::string& authorization_code) {
if (!main_task_runner_->BelongsToCurrentThread()) {
main_task_runner_->PostTask(FROM_HERE, base::Bind(
- &HostStarter::OnHostRegistered, weak_ptr_));
+ &HostStarter::OnHostRegistered, weak_ptr_, authorization_code));
+ return;
+ }
+
+ if (authorization_code.empty()) {
+ // No service account code, start the host with the owner's credentials.
+ xmpp_login_ = host_owner_;
+ StartHostProcess();
return;
}
+
+ // Received a service account authorization code, update oauth_client_info_
+ // to use the service account client keys, and get service account tokens.
+ oauth_client_info_.client_id =
+ google_apis::GetOAuth2ClientID(
+ google_apis::CLIENT_REMOTING_HOST);
+ oauth_client_info_.client_secret =
+ google_apis::GetOAuth2ClientSecret(
+ google_apis::CLIENT_REMOTING_HOST);
+ oauth_client_info_.redirect_uri = "oob";
+ oauth_client_->GetTokensFromAuthCode(
+ oauth_client_info_, authorization_code, kMaxGetTokensRetries, this);
+}
+
+void HostStarter::StartHostProcess() {
// Start the host.
std::string host_secret_hash = remoting::MakeHostPinHash(host_id_, host_pin_);
scoped_ptr<base::DictionaryValue> config(new base::DictionaryValue());
- config->SetString("xmpp_login", user_email_);
+ if (host_owner_ != xmpp_login_) {
+ config->SetString("host_owner", host_owner_);
+ }
+ config->SetString("xmpp_login", xmpp_login_);
config->SetString("oauth_refresh_token", refresh_token_);
config->SetString("host_id", host_id_);
config->SetString("host_name", host_name_);
diff --git a/remoting/host/setup/host_starter.h b/remoting/host/setup/host_starter.h
index a51f299f13..3bb2e3e050 100644
--- a/remoting/host/setup/host_starter.h
+++ b/remoting/host/setup/host_starter.h
@@ -55,7 +55,7 @@ class HostStarter : public gaia::GaiaOAuthClient::Delegate,
virtual void OnGetUserEmailResponse(const std::string& user_email) OVERRIDE;
// remoting::ServiceClient::Delegate
- virtual void OnHostRegistered() OVERRIDE;
+ virtual void OnHostRegistered(const std::string& authorization_code) OVERRIDE;
virtual void OnHostUnregistered() OVERRIDE;
// TODO(sergeyu): Following methods are members of all three delegate
@@ -70,6 +70,8 @@ class HostStarter : public gaia::GaiaOAuthClient::Delegate,
scoped_ptr<remoting::ServiceClient> service_client,
scoped_ptr<remoting::DaemonController> daemon_controller);
+ void StartHostProcess();
+
void OnHostStarted(DaemonController::AsyncResult result);
scoped_ptr<gaia::GaiaOAuthClient> oauth_client_;
@@ -83,9 +85,11 @@ class HostStarter : public gaia::GaiaOAuthClient::Delegate,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
std::string refresh_token_;
std::string access_token_;
- std::string user_email_;
+ std::string host_owner_;
+ std::string xmpp_login_;
scoped_refptr<remoting::RsaKeyPair> key_pair_;
std::string host_id_;
+ bool use_service_account_;
base::WeakPtrFactory<HostStarter> weak_ptr_factory_;
base::WeakPtr<HostStarter> weak_ptr_;
diff --git a/remoting/host/setup/native_messaging_host.cc b/remoting/host/setup/native_messaging_host.cc
index 7bf6b7c150..0492736c61 100644
--- a/remoting/host/setup/native_messaging_host.cc
+++ b/remoting/host/setup/native_messaging_host.cc
@@ -15,12 +15,16 @@
#include "base/run_loop.h"
#include "base/strings/stringize_macros.h"
#include "base/values.h"
+#include "google_apis/gaia/gaia_oauth_client.h"
+#include "google_apis/google_api_keys.h"
#include "net/base/net_util.h"
+#include "net/url_request/url_fetcher.h"
#include "remoting/base/rsa_key_pair.h"
+#include "remoting/base/url_request_context.h"
#include "remoting/host/host_exit_codes.h"
#include "remoting/host/pairing_registry_delegate.h"
-#include "remoting/host/pairing_registry_delegate.h"
#include "remoting/host/pin_hash.h"
+#include "remoting/host/setup/oauth_client.h"
#include "remoting/protocol/pairing_registry.h"
#if defined(OS_POSIX)
@@ -32,8 +36,13 @@ namespace {
// Features supported in addition to the base protocol.
const char* kSupportedFeatures[] = {
"pairingRegistry",
+ "oauthClient"
};
+// redirect_uri to use when authenticating service accounts (service account
+// codes are obtained "out-of-band", i.e., not through an OAuth redirect).
+const char* kServiceAccountRedirectUri = "oob";
+
// Helper to extract the "config" part of a message as a DictionaryValue.
// Returns NULL on failure, and logs an error message.
scoped_ptr<base::DictionaryValue> ConfigDictionaryFromMessage(
@@ -55,6 +64,7 @@ namespace remoting {
NativeMessagingHost::NativeMessagingHost(
scoped_ptr<DaemonController> daemon_controller,
scoped_refptr<protocol::PairingRegistry> pairing_registry,
+ scoped_ptr<OAuthClient> oauth_client,
base::PlatformFile input,
base::PlatformFile output,
scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
@@ -65,6 +75,7 @@ NativeMessagingHost::NativeMessagingHost(
native_messaging_writer_(output),
daemon_controller_(daemon_controller.Pass()),
pairing_registry_(pairing_registry),
+ oauth_client_(oauth_client.Pass()),
weak_factory_(this) {
weak_ptr_ = weak_factory_.GetWeakPtr();
}
@@ -145,6 +156,11 @@ void NativeMessagingHost::ProcessMessage(scoped_ptr<base::Value> message) {
success = ProcessStopDaemon(*message_dict, response_dict.Pass());
} else if (type == "getDaemonState") {
success = ProcessGetDaemonState(*message_dict, response_dict.Pass());
+ } else if (type == "getHostClientId") {
+ success = ProcessGetHostClientId(*message_dict, response_dict.Pass());
+ } else if (type == "getCredentialsFromAuthCode") {
+ success = ProcessGetCredentialsFromAuthCode(
+ *message_dict, response_dict.Pass());
} else {
LOG(ERROR) << "Unsupported request type: " << type;
}
@@ -347,6 +363,38 @@ bool NativeMessagingHost::ProcessGetDaemonState(
return true;
}
+bool NativeMessagingHost::ProcessGetHostClientId(
+ const base::DictionaryValue& message,
+ scoped_ptr<base::DictionaryValue> response) {
+ response->SetString("clientId", google_apis::GetOAuth2ClientID(
+ google_apis::CLIENT_REMOTING_HOST));
+ SendResponse(response.Pass());
+ return true;
+}
+
+bool NativeMessagingHost::ProcessGetCredentialsFromAuthCode(
+ const base::DictionaryValue& message,
+ scoped_ptr<base::DictionaryValue> response) {
+ std::string auth_code;
+ if (!message.GetString("authorizationCode", &auth_code)) {
+ LOG(ERROR) << "'authorizationCode' string not found.";
+ return false;
+ }
+
+ gaia::OAuthClientInfo oauth_client_info = {
+ google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING_HOST),
+ google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_REMOTING_HOST),
+ kServiceAccountRedirectUri
+ };
+
+ oauth_client_->GetCredentialsFromAuthCode(
+ oauth_client_info, auth_code, base::Bind(
+ &NativeMessagingHost::SendCredentialsResponse, weak_ptr_,
+ base::Passed(&response)));
+
+ return true;
+}
+
void NativeMessagingHost::SendResponse(
scoped_ptr<base::DictionaryValue> response) {
if (!caller_task_runner_->BelongsToCurrentThread()) {
@@ -415,6 +463,15 @@ void NativeMessagingHost::SendBooleanResult(
SendResponse(response.Pass());
}
+void NativeMessagingHost::SendCredentialsResponse(
+ scoped_ptr<base::DictionaryValue> response,
+ const std::string& user_email,
+ const std::string& refresh_token) {
+ response->SetString("userEmail", user_email);
+ response->SetString("refreshToken", refresh_token);
+ SendResponse(response.Pass());
+}
+
int NativeMessagingHostMain() {
#if defined(OS_WIN)
base::PlatformFile read_file = GetStdHandle(STD_INPUT_HANDLE);
@@ -428,10 +485,19 @@ int NativeMessagingHostMain() {
base::MessageLoop message_loop(base::MessageLoop::TYPE_IO);
base::RunLoop run_loop;
+ // OAuth client (for credential requests).
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter(
+ new remoting::URLRequestContextGetter(message_loop.message_loop_proxy()));
+ scoped_ptr<remoting::OAuthClient> oauth_client(
+ new remoting::OAuthClient(url_request_context_getter));
+
+ net::URLFetcher::SetIgnoreCertificateRequests(true);
+
scoped_refptr<protocol::PairingRegistry> pairing_registry =
CreatePairingRegistry(message_loop.message_loop_proxy());
remoting::NativeMessagingHost host(remoting::DaemonController::Create(),
pairing_registry,
+ oauth_client.Pass(),
read_file, write_file,
message_loop.message_loop_proxy(),
run_loop.QuitClosure());
diff --git a/remoting/host/setup/native_messaging_host.h b/remoting/host/setup/native_messaging_host.h
index 309d63cad6..6a00080a84 100644
--- a/remoting/host/setup/native_messaging_host.h
+++ b/remoting/host/setup/native_messaging_host.h
@@ -13,6 +13,7 @@
#include "remoting/host/setup/daemon_controller.h"
#include "remoting/host/setup/native_messaging_reader.h"
#include "remoting/host/setup/native_messaging_writer.h"
+#include "remoting/host/setup/oauth_client.h"
namespace base {
class DictionaryValue;
@@ -21,6 +22,10 @@ class SingleThreadTaskRunner;
class Value;
} // namespace base
+namespace gaia {
+class GaiaOAuthClient;
+} // namespace gaia
+
namespace remoting {
namespace protocol {
@@ -33,6 +38,7 @@ class NativeMessagingHost {
NativeMessagingHost(
scoped_ptr<DaemonController> daemon_controller,
scoped_refptr<protocol::PairingRegistry> pairing_registry,
+ scoped_ptr<OAuthClient> oauth_client,
base::PlatformFile input,
base::PlatformFile output,
scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
@@ -79,6 +85,11 @@ class NativeMessagingHost {
scoped_ptr<base::DictionaryValue> response);
bool ProcessGetDaemonState(const base::DictionaryValue& message,
scoped_ptr<base::DictionaryValue> response);
+ bool ProcessGetHostClientId(const base::DictionaryValue& message,
+ scoped_ptr<base::DictionaryValue> response);
+ bool ProcessGetCredentialsFromAuthCode(
+ const base::DictionaryValue& message,
+ scoped_ptr<base::DictionaryValue> response);
// Sends a response back to the client app. This can be called on either the
// main message loop or the DaemonController's internal thread, so it
@@ -101,6 +112,9 @@ class NativeMessagingHost {
DaemonController::AsyncResult result);
void SendBooleanResult(scoped_ptr<base::DictionaryValue> response,
bool result);
+ void SendCredentialsResponse(scoped_ptr<base::DictionaryValue> response,
+ const std::string& user_email,
+ const std::string& refresh_token);
// Callbacks may be invoked by e.g. DaemonController during destruction,
// which use |weak_ptr_|, so it's important that it be the last member to be
@@ -121,6 +135,9 @@ class NativeMessagingHost {
// Used to load and update the paired clients for this host.
scoped_refptr<protocol::PairingRegistry> pairing_registry_;
+ // Used to exchange the service account authorization code for credentials.
+ scoped_ptr<OAuthClient> oauth_client_;
+
base::WeakPtrFactory<NativeMessagingHost> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(NativeMessagingHost);
diff --git a/remoting/host/setup/native_messaging_host_unittest.cc b/remoting/host/setup/native_messaging_host_unittest.cc
index 09cf26ed63..209604a4f9 100644
--- a/remoting/host/setup/native_messaging_host_unittest.cc
+++ b/remoting/host/setup/native_messaging_host_unittest.cc
@@ -12,6 +12,7 @@
#include "base/stl_util.h"
#include "base/strings/stringize_macros.h"
#include "base/values.h"
+#include "google_apis/gaia/gaia_oauth_client.h"
#include "net/base/file_stream.h"
#include "net/base/net_util.h"
#include "remoting/host/pin_hash.h"
@@ -273,6 +274,7 @@ void NativeMessagingHostTest::SetUp() {
host_.reset(new NativeMessagingHost(daemon_controller.Pass(),
pairing_registry,
+ scoped_ptr<remoting::OAuthClient>(),
input_read_handle_, output_write_handle_,
message_loop_.message_loop_proxy(),
run_loop_.QuitClosure()));
diff --git a/remoting/host/setup/oauth_client.cc b/remoting/host/setup/oauth_client.cc
new file mode 100644
index 0000000000..9de07238c5
--- /dev/null
+++ b/remoting/host/setup/oauth_client.cc
@@ -0,0 +1,93 @@
+// Copyright 2013 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.
+
+#include "remoting/host/setup/oauth_client.h"
+
+namespace {
+const int kMaxGaiaRetries = 3;
+} // namespace
+
+namespace remoting {
+
+OAuthClient::OAuthClient(
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter)
+ : gaia_oauth_client_(url_request_context_getter) {
+}
+
+OAuthClient::~OAuthClient() {
+}
+
+void OAuthClient::GetCredentialsFromAuthCode(
+ const gaia::OAuthClientInfo& oauth_client_info,
+ const std::string& auth_code,
+ CompletionCallback on_done) {
+
+ if (!on_done_.is_null()) {
+ pending_requests_.push(Request(oauth_client_info, auth_code, on_done));
+ return;
+ }
+
+ on_done_ = on_done;
+ // Map the authorization code to refresh and access tokens.
+ gaia_oauth_client_.GetTokensFromAuthCode(oauth_client_info, auth_code,
+ kMaxGaiaRetries, this);
+}
+
+void OAuthClient::OnGetTokensResponse(
+ const std::string& refresh_token,
+ const std::string& access_token,
+ int expires_in_seconds) {
+ refresh_token_ = refresh_token;
+ // Get the email corresponding to the access token.
+ gaia_oauth_client_.GetUserEmail(access_token, kMaxGaiaRetries, this);
+}
+
+void OAuthClient::OnRefreshTokenResponse(
+ const std::string& access_token,
+ int expires_in_seconds) {
+ // We never request a refresh token, so this call is not expected.
+ NOTREACHED();
+}
+
+void OAuthClient::SendResponse(const std::string& user_email,
+ const std::string& refresh_token) {
+ CompletionCallback on_done = on_done_;
+ on_done_.Reset();
+ on_done.Run(user_email, refresh_token);
+
+ // Process the next request in the queue.
+ if (pending_requests_.size()) {
+ Request request = pending_requests_.front();
+ pending_requests_.pop();
+ // GetCredentialsFromAuthCode is asynchronous, so it's safe to call it here.
+ GetCredentialsFromAuthCode(
+ request.oauth_client_info, request.auth_code, request.on_done);
+ }
+}
+
+void OAuthClient::OnGetUserEmailResponse(const std::string& user_email) {
+ SendResponse(user_email, refresh_token_);
+}
+
+void OAuthClient::OnOAuthError() {
+ SendResponse("", "");
+}
+
+void OAuthClient::OnNetworkError(int response_code) {
+ SendResponse("", "");
+}
+
+OAuthClient::Request::Request(
+ const gaia::OAuthClientInfo& oauth_client_info,
+ const std::string& auth_code,
+ CompletionCallback on_done) {
+ this->oauth_client_info = oauth_client_info;
+ this->auth_code = auth_code;
+ this->on_done = on_done;
+}
+
+OAuthClient::Request::~Request() {
+}
+
+} // namespace remoting
diff --git a/remoting/host/setup/oauth_client.h b/remoting/host/setup/oauth_client.h
new file mode 100644
index 0000000000..2fdcbfe426
--- /dev/null
+++ b/remoting/host/setup/oauth_client.h
@@ -0,0 +1,79 @@
+// Copyright 2013 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.
+
+#ifndef REMOTING_HOST_SETUP_OAUTH_CLIENT
+#define REMOTING_HOST_SETUP_OAUTH_CLIENT
+
+#include <queue>
+#include <string>
+
+#include "base/callback.h"
+#include "google_apis/gaia/gaia_oauth_client.h"
+#include "remoting/base/url_request_context.h"
+
+namespace remoting {
+
+// A wrapper around GaiaOAuthClient that provides a more convenient interface,
+// with queueing of requests and a callback rather than a delegate.
+class OAuthClient : public gaia::GaiaOAuthClient::Delegate {
+ public:
+ // Called when GetCredentialsFromAuthCode is completed, with the |user_email|
+ // and |refresh_token| that correspond to the given |auth_code|, or with empty
+ // strings on error.
+ typedef base::Callback<void(
+ const std::string& user_email,
+ const std::string& refresh_token)> CompletionCallback;
+
+ OAuthClient(
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter);
+
+ virtual ~OAuthClient();
+
+ // Redeems |auth_code| using |oauth_client_info| to obtain |refresh_token| and
+ // |access_token|, then uses the userinfo endpoint to obtain |user_email|.
+ // Calls CompletionCallback with |user_email| and |refresh_token| when done,
+ // or with empty strings on error.
+ // If a request is received while another one is being processed, it is
+ // enqueued and processed after the first one is finished.
+ void GetCredentialsFromAuthCode(
+ const gaia::OAuthClientInfo& oauth_client_info,
+ const std::string& auth_code,
+ CompletionCallback on_done);
+
+ // gaia::GaiaOAuthClient::Delegate
+ virtual void OnGetTokensResponse(const std::string& refresh_token,
+ const std::string& access_token,
+ int expires_in_seconds) OVERRIDE;
+ virtual void OnRefreshTokenResponse(const std::string& access_token,
+ int expires_in_seconds) OVERRIDE;
+ virtual void OnGetUserEmailResponse(const std::string& user_email) OVERRIDE;
+
+ virtual void OnOAuthError() OVERRIDE;
+ virtual void OnNetworkError(int response_code) OVERRIDE;
+
+ private:
+ struct Request {
+ Request(const gaia::OAuthClientInfo& oauth_client_info,
+ const std::string& auth_code,
+ CompletionCallback on_done);
+ virtual ~Request();
+ gaia::OAuthClientInfo oauth_client_info;
+ std::string auth_code;
+ CompletionCallback on_done;
+ };
+
+ void SendResponse(const std::string& user_email,
+ const std::string& refresh_token);
+
+ std::queue<Request> pending_requests_;
+ gaia::GaiaOAuthClient gaia_oauth_client_;
+ std::string refresh_token_;
+ CompletionCallback on_done_;
+
+ DISALLOW_COPY_AND_ASSIGN(OAuthClient);
+};
+
+} // namespace remoting
+
+#endif // REMOTING_HOST_SETUP_OAUTH_CLIENT
diff --git a/remoting/host/setup/service_client.cc b/remoting/host/setup/service_client.cc
index c7bc22eb9f..215b04e4f2 100644
--- a/remoting/host/setup/service_client.cc
+++ b/remoting/host/setup/service_client.cc
@@ -4,6 +4,7 @@
#include "remoting/host/setup/service_client.h"
+#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
@@ -30,6 +31,7 @@ class ServiceClient::Core
void RegisterHost(const std::string& host_id,
const std::string& host_name,
const std::string& public_key,
+ const std::string& host_client_id,
const std::string& oauth_access_token,
ServiceClient::Delegate* delegate);
@@ -50,7 +52,7 @@ class ServiceClient::Core
PENDING_REQUEST_UNREGISTER_HOST
};
- void MakeGaiaRequest(net::URLFetcher::RequestType request_type,
+ void MakeChromotingRequest(net::URLFetcher::RequestType request_type,
const std::string& post_body,
const std::string& url_suffix,
const std::string& oauth_access_token,
@@ -68,6 +70,7 @@ void ServiceClient::Core::RegisterHost(
const std::string& host_id,
const std::string& host_name,
const std::string& public_key,
+ const std::string& host_client_id,
const std::string& oauth_access_token,
Delegate* delegate) {
DCHECK(pending_request_type_ == PENDING_REQUEST_NONE);
@@ -76,13 +79,16 @@ void ServiceClient::Core::RegisterHost(
post_body.SetString("data.hostId", host_id);
post_body.SetString("data.hostName", host_name);
post_body.SetString("data.publicKey", public_key);
+ std::string url_suffix;
+ if (!host_client_id.empty())
+ url_suffix = "?hostClientId=" + host_client_id;
std::string post_body_str;
base::JSONWriter::Write(&post_body, &post_body_str);
- MakeGaiaRequest(net::URLFetcher::POST,
- std::string(),
- post_body_str,
- oauth_access_token,
- delegate);
+ MakeChromotingRequest(net::URLFetcher::POST,
+ url_suffix,
+ post_body_str,
+ oauth_access_token,
+ delegate);
}
void ServiceClient::Core::UnregisterHost(
@@ -91,14 +97,14 @@ void ServiceClient::Core::UnregisterHost(
Delegate* delegate) {
DCHECK(pending_request_type_ == PENDING_REQUEST_NONE);
pending_request_type_ = PENDING_REQUEST_UNREGISTER_HOST;
- MakeGaiaRequest(net::URLFetcher::DELETE_REQUEST,
- host_id,
- std::string(),
- oauth_access_token,
- delegate);
+ MakeChromotingRequest(net::URLFetcher::DELETE_REQUEST,
+ host_id,
+ std::string(),
+ oauth_access_token,
+ delegate);
}
-void ServiceClient::Core::MakeGaiaRequest(
+void ServiceClient::Core::MakeChromotingRequest(
net::URLFetcher::RequestType request_type,
const std::string& url_suffix,
const std::string& request_body,
@@ -133,7 +139,21 @@ void ServiceClient::Core::HandleResponse(const net::URLFetcher* source) {
case PENDING_REQUEST_NONE:
break;
case PENDING_REQUEST_REGISTER_HOST:
- delegate_->OnHostRegistered();
+ {
+ std::string data;
+ source->GetResponseAsString(&data);
+ scoped_ptr<Value> message_value(base::JSONReader::Read(data));
+ DictionaryValue *dict;
+ std::string code;
+ if (message_value.get() &&
+ message_value->IsType(Value::TYPE_DICTIONARY) &&
+ message_value->GetAsDictionary(&dict) &&
+ dict->GetString("data.authorizationCode", &code)) {
+ delegate_->OnHostRegistered(code);
+ } else {
+ delegate_->OnHostRegistered(std::string());
+ }
+ }
break;
case PENDING_REQUEST_UNREGISTER_HOST:
delegate_->OnHostUnregistered();
@@ -156,10 +176,11 @@ void ServiceClient::RegisterHost(
const std::string& host_id,
const std::string& host_name,
const std::string& public_key,
+ const std::string& host_client_id,
const std::string& oauth_access_token,
Delegate* delegate) {
- return core_->RegisterHost(host_id, host_name, public_key, oauth_access_token,
- delegate);
+ return core_->RegisterHost(host_id, host_name, public_key, host_client_id,
+ oauth_access_token, delegate);
}
void ServiceClient::UnregisterHost(
diff --git a/remoting/host/setup/service_client.h b/remoting/host/setup/service_client.h
index 5ae2144507..eaa26abdc3 100644
--- a/remoting/host/setup/service_client.h
+++ b/remoting/host/setup/service_client.h
@@ -22,7 +22,7 @@ class ServiceClient {
class Delegate {
public:
// Invoked when a host has been registered.
- virtual void OnHostRegistered() = 0;
+ virtual void OnHostRegistered(const std::string& authorization_code) = 0;
// Invoked when a host has been unregistered.
virtual void OnHostUnregistered() = 0;
// Invoked when there is an OAuth error.
@@ -42,6 +42,7 @@ class ServiceClient {
void RegisterHost(const std::string& host_id,
const std::string& host_name,
const std::string& public_key,
+ const std::string& host_client_id,
const std::string& oauth_access_token,
Delegate* delegate);
// Unregister a host.
diff --git a/remoting/host/setup/start_host.cc b/remoting/host/setup/start_host.cc
index 024e9a3aca..ab5688dbce 100644
--- a/remoting/host/setup/start_host.cc
+++ b/remoting/host/setup/start_host.cc
@@ -149,9 +149,7 @@ int main(int argc, char** argv) {
io_thread.StartWithOptions(io_thread_options);
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter(
- new remoting::URLRequestContextGetter(
- g_message_loop->message_loop_proxy(),
- io_thread.message_loop_proxy()));
+ new remoting::URLRequestContextGetter(io_thread.message_loop_proxy()));
net::URLFetcher::SetIgnoreCertificateRequests(true);
diff --git a/remoting/host/setup/win/host_configurer.cc b/remoting/host/setup/win/host_configurer.cc
index bf5b8a6da6..604c9e4caa 100644
--- a/remoting/host/setup/win/host_configurer.cc
+++ b/remoting/host/setup/win/host_configurer.cc
@@ -45,8 +45,7 @@ int WINAPI WinMain(HINSTANCE instance_handle, HINSTANCE prev_instance_handle,
io_thread.StartWithOptions(io_thread_options);
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_(
- new remoting::URLRequestContextGetter(
- message_loop.message_loop_proxy(), io_thread.message_loop_proxy()));
+ new remoting::URLRequestContextGetter(io_thread.message_loop_proxy()));
OleInitialize(NULL);
diff --git a/remoting/host/signaling_connector.cc b/remoting/host/signaling_connector.cc
index 67c142fb30..ad9fbe5dc1 100644
--- a/remoting/host/signaling_connector.cc
+++ b/remoting/host/signaling_connector.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/strings/string_util.h"
#include "google_apis/google_api_keys.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_request_context_getter.h"
@@ -26,9 +27,11 @@ const int kTokenUpdateTimeBeforeExpirySeconds = 60;
SignalingConnector::OAuthCredentials::OAuthCredentials(
const std::string& login_value,
- const std::string& refresh_token_value)
+ const std::string& refresh_token_value,
+ bool is_service_account)
: login(login_value),
- refresh_token(refresh_token_value) {
+ refresh_token(refresh_token_value),
+ is_service_account(is_service_account) {
}
SignalingConnector::SignalingConnector(
@@ -228,12 +231,20 @@ void SignalingConnector::RefreshOAuthToken() {
LOG(INFO) << "Refreshing OAuth token.";
DCHECK(!refreshing_oauth_token_);
+ // Service accounts use different API keys, as they use the client app flow.
+ google_apis::OAuth2Client oauth2_client;
+ if (oauth_credentials_->is_service_account) {
+ oauth2_client = google_apis::CLIENT_REMOTING_HOST;
+ } else {
+ oauth2_client = google_apis::CLIENT_REMOTING;
+ }
+
gaia::OAuthClientInfo client_info = {
- google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING),
- google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_REMOTING),
- // Redirect URL is only used when getting tokens from auth code. It
- // is not required when getting access tokens.
- ""
+ google_apis::GetOAuth2ClientID(oauth2_client),
+ google_apis::GetOAuth2ClientSecret(oauth2_client),
+ // Redirect URL is only used when getting tokens from auth code. It
+ // is not required when getting access tokens.
+ ""
};
refreshing_oauth_token_ = true;
diff --git a/remoting/host/signaling_connector.h b/remoting/host/signaling_connector.h
index 06265e75d4..77474cd34e 100644
--- a/remoting/host/signaling_connector.h
+++ b/remoting/host/signaling_connector.h
@@ -40,13 +40,17 @@ class SignalingConnector
// authentication to OAuth2.
struct OAuthCredentials {
OAuthCredentials(const std::string& login_value,
- const std::string& refresh_token_value);
+ const std::string& refresh_token_value,
+ bool is_service_account);
// The user's account name (i.e. their email address).
std::string login;
// Token delegating authority to us to act as the user.
std::string refresh_token;
+
+ // Whether these credentials belong to a service account.
+ bool is_service_account;
};
// The |auth_failed_callback| is called when authentication fails.