From 3551c9c881056c480085172ff9840cab31610854 Mon Sep 17 00:00:00 2001 From: "Torne (Richard Coles)" Date: Fri, 23 Aug 2013 16:39:15 +0100 Subject: Merge from Chromium at DEPS revision r219274 This commit was generated by merge_to_master.py. Change-Id: Ibb7f41396cadf4071e89153e1913c986d126f65d --- remoting/host/chromoting_host.cc | 4 +- remoting/host/chromoting_host.h | 2 +- remoting/host/chromoting_host_context.cc | 2 +- remoting/host/client_session.cc | 2 +- remoting/host/constants_mac.cc | 4 + remoting/host/constants_mac.h | 3 + remoting/host/host_config.cc | 1 + remoting/host/host_config.h | 2 + remoting/host/host_main.cc | 11 +-- remoting/host/installer/linux/Makefile | 5 +- .../installer/mac/ChromotingHostService.pkgproj | 67 ++++++++++++++++ .../mac/uninstaller/remoting_uninstaller.mm | 1 + remoting/host/keygen_main.cc | 37 --------- remoting/host/local_input_monitor_win.cc | 2 +- remoting/host/pairing_registry_delegate_win.cc | 3 +- remoting/host/plugin/host_script_object.cc | 71 +++++++---------- remoting/host/remoting_me2me_host.cc | 51 +++++++----- remoting/host/setup/daemon_controller_linux.cc | 6 +- remoting/host/setup/host_starter.cc | 60 +++++++++++--- remoting/host/setup/host_starter.h | 8 +- remoting/host/setup/native_messaging_host.cc | 68 +++++++++++++++- remoting/host/setup/native_messaging_host.h | 17 ++++ .../host/setup/native_messaging_host_unittest.cc | 2 + remoting/host/setup/oauth_client.cc | 93 ++++++++++++++++++++++ remoting/host/setup/oauth_client.h | 79 ++++++++++++++++++ remoting/host/setup/service_client.cc | 51 ++++++++---- remoting/host/setup/service_client.h | 3 +- remoting/host/setup/start_host.cc | 4 +- remoting/host/setup/win/host_configurer.cc | 3 +- remoting/host/signaling_connector.cc | 25 ++++-- remoting/host/signaling_connector.h | 6 +- 31 files changed, 535 insertions(+), 158 deletions(-) delete mode 100644 remoting/host/keygen_main.cc create mode 100644 remoting/host/setup/oauth_client.cc create mode 100644 remoting/host/setup/oauth_client.h (limited to 'remoting/host') 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 @@ -162,6 +162,73 @@ UID 0 + + CHILDREN + + + CHILDREN + + + CHILDREN + + + CHILDREN + + GID + 0 + PATH + Config/com.google.chrome.remote_desktop.json + PATH_TYPE + 1 + PERMISSIONS + 420 + TYPE + 3 + UID + 0 + + + GID + 0 + PATH + NativeMessagingHosts + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 2 + UID + 0 + + + GID + 0 + PATH + Chrome + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 2 + UID + 0 + + + GID + 0 + PATH + Google + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 2 + UID + 0 + CHILDREN 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 - -#include - -#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 key(crypto::RSAPrivateKey::Create(2048)); - - std::vector 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 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 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* 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 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_watcher_; bool allow_nat_traversal_; std::string talkgadget_prefix_; @@ -303,6 +303,7 @@ HostProcess::HostProcess(scoped_ptr 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 @@ -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 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 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 dns_blackhole_checker( new DnsBlackholeChecker(context_->url_request_context_getter(), @@ -972,7 +986,8 @@ void HostProcess::StartHost() { if (!oauth_refresh_token_.empty()) { scoped_ptr 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 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 service_client, scoped_ptr daemon_controller); + void StartHostProcess(); + void OnHostStarted(DaemonController::AsyncResult result); scoped_ptr oauth_client_; @@ -83,9 +85,11 @@ class HostStarter : public gaia::GaiaOAuthClient::Delegate, scoped_refptr 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 key_pair_; std::string host_id_; + bool use_service_account_; base::WeakPtrFactory weak_ptr_factory_; base::WeakPtr 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 ConfigDictionaryFromMessage( @@ -55,6 +64,7 @@ namespace remoting { NativeMessagingHost::NativeMessagingHost( scoped_ptr daemon_controller, scoped_refptr pairing_registry, + scoped_ptr oauth_client, base::PlatformFile input, base::PlatformFile output, scoped_refptr 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 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 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 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 response) { if (!caller_task_runner_->BelongsToCurrentThread()) { @@ -415,6 +463,15 @@ void NativeMessagingHost::SendBooleanResult( SendResponse(response.Pass()); } +void NativeMessagingHost::SendCredentialsResponse( + scoped_ptr 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 url_request_context_getter( + new remoting::URLRequestContextGetter(message_loop.message_loop_proxy())); + scoped_ptr oauth_client( + new remoting::OAuthClient(url_request_context_getter)); + + net::URLFetcher::SetIgnoreCertificateRequests(true); + scoped_refptr 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 daemon_controller, scoped_refptr pairing_registry, + scoped_ptr oauth_client, base::PlatformFile input, base::PlatformFile output, scoped_refptr caller_task_runner, @@ -79,6 +85,11 @@ class NativeMessagingHost { scoped_ptr response); bool ProcessGetDaemonState(const base::DictionaryValue& message, scoped_ptr response); + bool ProcessGetHostClientId(const base::DictionaryValue& message, + scoped_ptr response); + bool ProcessGetCredentialsFromAuthCode( + const base::DictionaryValue& message, + scoped_ptr 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 response, bool result); + void SendCredentialsResponse(scoped_ptr 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 pairing_registry_; + // Used to exchange the service account authorization code for credentials. + scoped_ptr oauth_client_; + base::WeakPtrFactory 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(), 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 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 +#include + +#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 CompletionCallback; + + OAuthClient( + scoped_refptr 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 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 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 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 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. -- cgit v1.2.3