blob: cba8517abc2e716efffb657d6bfc8856cd33f13f [file] [log] [blame]
[email protected]d0f68472012-10-05 03:27:351// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "remoting/host/setup/host_starter.h"
6
Jinho Bang138fde32018-01-18 23:13:427#include <memory>
sergeyu1417e0132015-12-23 19:01:228#include <utility>
9
[email protected]305ed872014-07-08 02:33:5310#include "base/bind.h"
[email protected]76d632082012-10-19 00:45:1111#include "base/guid.h"
[email protected]305ed872014-07-08 02:33:5312#include "base/location.h"
dcheng0765c492016-04-06 22:41:5313#include "base/memory/ptr_util.h"
gabbac02f52016-05-11 17:55:5114#include "base/threading/thread_task_runner_handle.h"
[email protected]d0f68472012-10-05 03:27:3515#include "base/values.h"
[email protected]d0f68472012-10-05 03:27:3516#include "google_apis/google_api_keys.h"
17#include "remoting/host/pin_hash.h"
Maks Orlovich8db7d0d62018-08-16 19:22:2718#include "services/network/public/cpp/shared_url_loader_factory.h"
[email protected]d0f68472012-10-05 03:27:3519
20namespace {
[email protected]d0f68472012-10-05 03:27:3521const int kMaxGetTokensRetries = 3;
[email protected]d0f68472012-10-05 03:27:3522} // namespace
23
24namespace remoting {
25
26HostStarter::HostStarter(
dcheng0765c492016-04-06 22:41:5327 std::unique_ptr<gaia::GaiaOAuthClient> oauth_client,
28 std::unique_ptr<remoting::ServiceClient> service_client,
[email protected]8c5d6c02013-09-10 00:54:0529 scoped_refptr<remoting::DaemonController> daemon_controller)
sergeyu1417e0132015-12-23 19:01:2230 : oauth_client_(std::move(oauth_client)),
31 service_client_(std::move(service_client)),
[email protected]8c5d6c02013-09-10 00:54:0532 daemon_controller_(daemon_controller),
[email protected]3acb80472012-10-18 01:41:0833 consent_to_data_collection_(false),
Jeremy Roman7c5cfabd2019-08-12 15:45:2734 unregistering_host_(false) {
[email protected]70dbb9d2013-10-10 09:58:5435 weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
[email protected]3acb80472012-10-18 01:41:0836 main_task_runner_ = base::ThreadTaskRunnerHandle::Get();
[email protected]d0f68472012-10-05 03:27:3537}
38
Chris Watkins6fe52aa2017-11-28 03:24:0539HostStarter::~HostStarter() = default;
[email protected]d0f68472012-10-05 03:27:3540
dcheng0765c492016-04-06 22:41:5341std::unique_ptr<HostStarter> HostStarter::Create(
Lambros Lambrou88f556372019-05-30 04:07:4742 const std::string& remoting_server_endpoint,
Antonio Gomesf8c54702018-08-31 20:15:5243 scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
dcheng0765c492016-04-06 22:41:5344 return base::WrapUnique(new HostStarter(
Maks Orlovich8db7d0d62018-08-16 19:22:2745 std::make_unique<gaia::GaiaOAuthClient>(url_loader_factory),
Lambros Lambrou88f556372019-05-30 04:07:4746 std::make_unique<remoting::ServiceClient>(remoting_server_endpoint),
sergeyu1417e0132015-12-23 19:01:2247 remoting::DaemonController::Create()));
[email protected]d0f68472012-10-05 03:27:3548}
49
[email protected]3acb80472012-10-18 01:41:0850void HostStarter::StartHost(
51 const std::string& host_name,
52 const std::string& host_pin,
53 bool consent_to_data_collection,
54 const std::string& auth_code,
[email protected]33c431a2012-10-18 19:00:0455 const std::string& redirect_url,
[email protected]3acb80472012-10-18 01:41:0856 CompletionCallback on_done) {
57 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]2c1d91f2012-10-24 20:34:4758 DCHECK(on_done_.is_null());
59
[email protected]d0f68472012-10-05 03:27:3560 host_name_ = host_name;
61 host_pin_ = host_pin;
62 consent_to_data_collection_ = consent_to_data_collection;
63 on_done_ = on_done;
[email protected]33c431a2012-10-18 19:00:0464 oauth_client_info_.client_id =
65 google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING);
66 oauth_client_info_.client_secret =
67 google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_REMOTING);
68 oauth_client_info_.redirect_uri = redirect_url;
[email protected]d0f68472012-10-05 03:27:3569 // Map the authorization code to refresh and access tokens.
Lambros Lambrou6fb4a122019-06-06 22:16:3870 DCHECK_EQ(pending_get_tokens_, GET_TOKENS_NONE);
71 pending_get_tokens_ = GET_TOKENS_DIRECTORY;
[email protected]d0f68472012-10-05 03:27:3572 oauth_client_->GetTokensFromAuthCode(oauth_client_info_, auth_code,
73 kMaxGetTokensRetries, this);
74}
75
76void HostStarter::OnGetTokensResponse(
77 const std::string& refresh_token,
78 const std::string& access_token,
79 int expires_in_seconds) {
[email protected]3acb80472012-10-18 01:41:0880 if (!main_task_runner_->BelongsToCurrentThread()) {
kylechar2caf4d62019-02-15 20:03:4281 main_task_runner_->PostTask(
82 FROM_HERE,
83 base::BindOnce(&HostStarter::OnGetTokensResponse, weak_ptr_,
84 refresh_token, access_token, expires_in_seconds));
[email protected]3acb80472012-10-18 01:41:0885 return;
86 }
Lambros Lambrou6fb4a122019-06-06 22:16:3887
88 if (pending_get_tokens_ == GET_TOKENS_DIRECTORY) {
89 directory_access_token_ = access_token;
90 } else if (pending_get_tokens_ == GET_TOKENS_HOST) {
91 host_refresh_token_ = refresh_token;
92 host_access_token_ = access_token;
93 } else {
94 NOTREACHED();
95 }
96
97 pending_get_tokens_ = GET_TOKENS_NONE;
98
[email protected]d0f68472012-10-05 03:27:3599 // Get the email corresponding to the access token.
Lambros Lambrou6fb4a122019-06-06 22:16:38100 oauth_client_->GetUserEmail(access_token, 1, this);
[email protected]d0f68472012-10-05 03:27:35101}
102
[email protected]2c1d91f2012-10-24 20:34:47103void HostStarter::OnRefreshTokenResponse(
104 const std::string& access_token,
105 int expires_in_seconds) {
106 // We never request a refresh token, so this call is not expected.
107 NOTREACHED();
108}
109
[email protected]1aec3452013-08-16 22:29:52110// This function is called twice: once with the host owner credentials, and once
111// with the service account credentials.
[email protected]5d82f982013-06-26 04:11:34112void HostStarter::OnGetUserEmailResponse(const std::string& user_email) {
[email protected]3acb80472012-10-18 01:41:08113 if (!main_task_runner_->BelongsToCurrentThread()) {
kylechar2caf4d62019-02-15 20:03:42114 main_task_runner_->PostTask(
115 FROM_HERE, base::BindOnce(&HostStarter::OnGetUserEmailResponse,
116 weak_ptr_, user_email));
[email protected]3acb80472012-10-18 01:41:08117 return;
118 }
[email protected]1aec3452013-08-16 22:29:52119
120 if (host_owner_.empty()) {
121 // This is the first callback, with the host owner credentials. Store the
122 // owner's email, and register the host.
123 host_owner_ = user_email;
124 host_id_ = base::GenerateGUID();
125 key_pair_ = RsaKeyPair::Generate();
126
127 std::string host_client_id;
128 host_client_id = google_apis::GetOAuth2ClientID(
129 google_apis::CLIENT_REMOTING_HOST);
130
Lambros Lambrou6fb4a122019-06-06 22:16:38131 service_client_->RegisterHost(host_id_, host_name_,
132 key_pair_->GetPublicKey(), host_client_id,
133 directory_access_token_, this);
[email protected]1aec3452013-08-16 22:29:52134 } else {
135 // This is the second callback, with the service account credentials.
136 // This email is the service account's email, used to login to XMPP.
137 xmpp_login_ = user_email;
138 StartHostProcess();
139 }
[email protected]d0f68472012-10-05 03:27:35140}
141
[email protected]1aec3452013-08-16 22:29:52142void HostStarter::OnHostRegistered(const std::string& authorization_code) {
[email protected]3acb80472012-10-18 01:41:08143 if (!main_task_runner_->BelongsToCurrentThread()) {
kylechar2caf4d62019-02-15 20:03:42144 main_task_runner_->PostTask(
145 FROM_HERE, base::BindOnce(&HostStarter::OnHostRegistered, weak_ptr_,
146 authorization_code));
[email protected]3acb80472012-10-18 01:41:08147 return;
148 }
[email protected]1aec3452013-08-16 22:29:52149
150 if (authorization_code.empty()) {
151 // No service account code, start the host with the owner's credentials.
152 xmpp_login_ = host_owner_;
153 StartHostProcess();
154 return;
155 }
156
157 // Received a service account authorization code, update oauth_client_info_
158 // to use the service account client keys, and get service account tokens.
Lambros Lambrou6fb4a122019-06-06 22:16:38159 DCHECK_EQ(pending_get_tokens_, GET_TOKENS_NONE);
160 pending_get_tokens_ = GET_TOKENS_HOST;
161
[email protected]1aec3452013-08-16 22:29:52162 oauth_client_info_.client_id =
163 google_apis::GetOAuth2ClientID(
164 google_apis::CLIENT_REMOTING_HOST);
165 oauth_client_info_.client_secret =
166 google_apis::GetOAuth2ClientSecret(
167 google_apis::CLIENT_REMOTING_HOST);
168 oauth_client_info_.redirect_uri = "oob";
169 oauth_client_->GetTokensFromAuthCode(
170 oauth_client_info_, authorization_code, kMaxGetTokensRetries, this);
171}
172
173void HostStarter::StartHostProcess() {
[email protected]d0f68472012-10-05 03:27:35174 // Start the host.
175 std::string host_secret_hash = remoting::MakeHostPinHash(host_id_, host_pin_);
dcheng0765c492016-04-06 22:41:53176 std::unique_ptr<base::DictionaryValue> config(new base::DictionaryValue());
[email protected]1aec3452013-08-16 22:29:52177 if (host_owner_ != xmpp_login_) {
178 config->SetString("host_owner", host_owner_);
179 }
180 config->SetString("xmpp_login", xmpp_login_);
Lambros Lambrou6fb4a122019-06-06 22:16:38181 config->SetString("oauth_refresh_token", host_refresh_token_);
[email protected]d0f68472012-10-05 03:27:35182 config->SetString("host_id", host_id_);
183 config->SetString("host_name", host_name_);
[email protected]8f1504b2013-03-07 13:43:10184 config->SetString("private_key", key_pair_->ToString());
[email protected]d0f68472012-10-05 03:27:35185 config->SetString("host_secret_hash", host_secret_hash);
186 daemon_controller_->SetConfigAndStart(
sergeyu1417e0132015-12-23 19:01:22187 std::move(config), consent_to_data_collection_,
[email protected]3acb80472012-10-18 01:41:08188 base::Bind(&HostStarter::OnHostStarted, base::Unretained(this)));
[email protected]d0f68472012-10-05 03:27:35189}
190
191void HostStarter::OnHostStarted(DaemonController::AsyncResult result) {
[email protected]3acb80472012-10-18 01:41:08192 if (!main_task_runner_->BelongsToCurrentThread()) {
kylechar2caf4d62019-02-15 20:03:42193 main_task_runner_->PostTask(
194 FROM_HERE,
195 base::BindOnce(&HostStarter::OnHostStarted, weak_ptr_, result));
[email protected]3acb80472012-10-18 01:41:08196 return;
197 }
[email protected]d215b652012-10-27 00:50:10198 if (result != DaemonController::RESULT_OK) {
[email protected]761cc1ae2013-08-28 00:24:58199 unregistering_host_ = true;
Lambros Lambrou6fb4a122019-06-06 22:16:38200 service_client_->UnregisterHost(host_id_, directory_access_token_, this);
[email protected]d215b652012-10-27 00:50:10201 return;
202 }
Daniel Chengce48c3c42019-04-26 15:06:08203 std::move(on_done_).Run(START_COMPLETE);
[email protected]d0f68472012-10-05 03:27:35204}
205
206void HostStarter::OnOAuthError() {
[email protected]3acb80472012-10-18 01:41:08207 if (!main_task_runner_->BelongsToCurrentThread()) {
kylechar2caf4d62019-02-15 20:03:42208 main_task_runner_->PostTask(
209 FROM_HERE, base::BindOnce(&HostStarter::OnOAuthError, weak_ptr_));
[email protected]3acb80472012-10-18 01:41:08210 return;
211 }
Lambros Lambrou6fb4a122019-06-06 22:16:38212
213 pending_get_tokens_ = GET_TOKENS_NONE;
[email protected]761cc1ae2013-08-28 00:24:58214 if (unregistering_host_) {
215 LOG(ERROR) << "OAuth error occurred when unregistering host.";
[email protected]761cc1ae2013-08-28 00:24:58216 }
sergeyud9bdcb62015-04-25 00:18:08217
Daniel Chengce48c3c42019-04-26 15:06:08218 std::move(on_done_).Run(unregistering_host_ ? START_ERROR : OAUTH_ERROR);
[email protected]d0f68472012-10-05 03:27:35219}
220
221void HostStarter::OnNetworkError(int response_code) {
[email protected]3acb80472012-10-18 01:41:08222 if (!main_task_runner_->BelongsToCurrentThread()) {
kylechar2caf4d62019-02-15 20:03:42223 main_task_runner_->PostTask(
224 FROM_HERE,
225 base::BindOnce(&HostStarter::OnNetworkError, weak_ptr_, response_code));
[email protected]3acb80472012-10-18 01:41:08226 return;
227 }
Lambros Lambrou6fb4a122019-06-06 22:16:38228
229 pending_get_tokens_ = GET_TOKENS_NONE;
[email protected]761cc1ae2013-08-28 00:24:58230 if (unregistering_host_) {
231 LOG(ERROR) << "Network error occurred when unregistering host.";
[email protected]761cc1ae2013-08-28 00:24:58232 }
sergeyud9bdcb62015-04-25 00:18:08233
Daniel Chengce48c3c42019-04-26 15:06:08234 std::move(on_done_).Run(unregistering_host_ ? START_ERROR : NETWORK_ERROR);
[email protected]d0f68472012-10-05 03:27:35235}
236
[email protected]d215b652012-10-27 00:50:10237void HostStarter::OnHostUnregistered() {
238 if (!main_task_runner_->BelongsToCurrentThread()) {
kylechar2caf4d62019-02-15 20:03:42239 main_task_runner_->PostTask(
240 FROM_HERE, base::BindOnce(&HostStarter::OnHostUnregistered, weak_ptr_));
[email protected]d215b652012-10-27 00:50:10241 return;
242 }
Daniel Chengce48c3c42019-04-26 15:06:08243 std::move(on_done_).Run(START_ERROR);
[email protected]d215b652012-10-27 00:50:10244}
245
[email protected]d0f68472012-10-05 03:27:35246} // namespace remoting