[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 1 | // 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 Bang | 138fde3 | 2018-01-18 23:13:42 | [diff] [blame] | 7 | #include <memory> |
sergeyu | 1417e013 | 2015-12-23 19:01:22 | [diff] [blame] | 8 | #include <utility> |
| 9 | |
[email protected] | 305ed87 | 2014-07-08 02:33:53 | [diff] [blame] | 10 | #include "base/bind.h" |
[email protected] | 76d63208 | 2012-10-19 00:45:11 | [diff] [blame] | 11 | #include "base/guid.h" |
[email protected] | 305ed87 | 2014-07-08 02:33:53 | [diff] [blame] | 12 | #include "base/location.h" |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 13 | #include "base/memory/ptr_util.h" |
gab | bac02f5 | 2016-05-11 17:55:51 | [diff] [blame] | 14 | #include "base/threading/thread_task_runner_handle.h" |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 15 | #include "base/values.h" |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 16 | #include "google_apis/google_api_keys.h" |
| 17 | #include "remoting/host/pin_hash.h" |
Maks Orlovich | 8db7d0d6 | 2018-08-16 19:22:27 | [diff] [blame] | 18 | #include "services/network/public/cpp/shared_url_loader_factory.h" |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 19 | |
| 20 | namespace { |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 21 | const int kMaxGetTokensRetries = 3; |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 22 | } // namespace |
| 23 | |
| 24 | namespace remoting { |
| 25 | |
| 26 | HostStarter::HostStarter( |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 27 | std::unique_ptr<gaia::GaiaOAuthClient> oauth_client, |
| 28 | std::unique_ptr<remoting::ServiceClient> service_client, |
[email protected] | 8c5d6c0 | 2013-09-10 00:54:05 | [diff] [blame] | 29 | scoped_refptr<remoting::DaemonController> daemon_controller) |
sergeyu | 1417e013 | 2015-12-23 19:01:22 | [diff] [blame] | 30 | : oauth_client_(std::move(oauth_client)), |
| 31 | service_client_(std::move(service_client)), |
[email protected] | 8c5d6c0 | 2013-09-10 00:54:05 | [diff] [blame] | 32 | daemon_controller_(daemon_controller), |
[email protected] | 3acb8047 | 2012-10-18 01:41:08 | [diff] [blame] | 33 | consent_to_data_collection_(false), |
Jeremy Roman | 7c5cfabd | 2019-08-12 15:45:27 | [diff] [blame] | 34 | unregistering_host_(false) { |
[email protected] | 70dbb9d | 2013-10-10 09:58:54 | [diff] [blame] | 35 | weak_ptr_ = weak_ptr_factory_.GetWeakPtr(); |
[email protected] | 3acb8047 | 2012-10-18 01:41:08 | [diff] [blame] | 36 | main_task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 37 | } |
| 38 | |
Chris Watkins | 6fe52aa | 2017-11-28 03:24:05 | [diff] [blame] | 39 | HostStarter::~HostStarter() = default; |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 40 | |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 41 | std::unique_ptr<HostStarter> HostStarter::Create( |
Lambros Lambrou | 88f55637 | 2019-05-30 04:07:47 | [diff] [blame] | 42 | const std::string& remoting_server_endpoint, |
Antonio Gomes | f8c5470 | 2018-08-31 20:15:52 | [diff] [blame] | 43 | scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) { |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 44 | return base::WrapUnique(new HostStarter( |
Maks Orlovich | 8db7d0d6 | 2018-08-16 19:22:27 | [diff] [blame] | 45 | std::make_unique<gaia::GaiaOAuthClient>(url_loader_factory), |
Lambros Lambrou | 88f55637 | 2019-05-30 04:07:47 | [diff] [blame] | 46 | std::make_unique<remoting::ServiceClient>(remoting_server_endpoint), |
sergeyu | 1417e013 | 2015-12-23 19:01:22 | [diff] [blame] | 47 | remoting::DaemonController::Create())); |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 48 | } |
| 49 | |
[email protected] | 3acb8047 | 2012-10-18 01:41:08 | [diff] [blame] | 50 | void 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] | 33c431a | 2012-10-18 19:00:04 | [diff] [blame] | 55 | const std::string& redirect_url, |
[email protected] | 3acb8047 | 2012-10-18 01:41:08 | [diff] [blame] | 56 | CompletionCallback on_done) { |
| 57 | DCHECK(main_task_runner_->BelongsToCurrentThread()); |
[email protected] | 2c1d91f | 2012-10-24 20:34:47 | [diff] [blame] | 58 | DCHECK(on_done_.is_null()); |
| 59 | |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 60 | 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] | 33c431a | 2012-10-18 19:00:04 | [diff] [blame] | 64 | 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] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 69 | // Map the authorization code to refresh and access tokens. |
Lambros Lambrou | 6fb4a12 | 2019-06-06 22:16:38 | [diff] [blame] | 70 | DCHECK_EQ(pending_get_tokens_, GET_TOKENS_NONE); |
| 71 | pending_get_tokens_ = GET_TOKENS_DIRECTORY; |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 72 | oauth_client_->GetTokensFromAuthCode(oauth_client_info_, auth_code, |
| 73 | kMaxGetTokensRetries, this); |
| 74 | } |
| 75 | |
| 76 | void HostStarter::OnGetTokensResponse( |
| 77 | const std::string& refresh_token, |
| 78 | const std::string& access_token, |
| 79 | int expires_in_seconds) { |
[email protected] | 3acb8047 | 2012-10-18 01:41:08 | [diff] [blame] | 80 | if (!main_task_runner_->BelongsToCurrentThread()) { |
kylechar | 2caf4d6 | 2019-02-15 20:03:42 | [diff] [blame] | 81 | main_task_runner_->PostTask( |
| 82 | FROM_HERE, |
| 83 | base::BindOnce(&HostStarter::OnGetTokensResponse, weak_ptr_, |
| 84 | refresh_token, access_token, expires_in_seconds)); |
[email protected] | 3acb8047 | 2012-10-18 01:41:08 | [diff] [blame] | 85 | return; |
| 86 | } |
Lambros Lambrou | 6fb4a12 | 2019-06-06 22:16:38 | [diff] [blame] | 87 | |
| 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] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 99 | // Get the email corresponding to the access token. |
Lambros Lambrou | 6fb4a12 | 2019-06-06 22:16:38 | [diff] [blame] | 100 | oauth_client_->GetUserEmail(access_token, 1, this); |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 101 | } |
| 102 | |
[email protected] | 2c1d91f | 2012-10-24 20:34:47 | [diff] [blame] | 103 | void 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] | 1aec345 | 2013-08-16 22:29:52 | [diff] [blame] | 110 | // This function is called twice: once with the host owner credentials, and once |
| 111 | // with the service account credentials. |
[email protected] | 5d82f98 | 2013-06-26 04:11:34 | [diff] [blame] | 112 | void HostStarter::OnGetUserEmailResponse(const std::string& user_email) { |
[email protected] | 3acb8047 | 2012-10-18 01:41:08 | [diff] [blame] | 113 | if (!main_task_runner_->BelongsToCurrentThread()) { |
kylechar | 2caf4d6 | 2019-02-15 20:03:42 | [diff] [blame] | 114 | main_task_runner_->PostTask( |
| 115 | FROM_HERE, base::BindOnce(&HostStarter::OnGetUserEmailResponse, |
| 116 | weak_ptr_, user_email)); |
[email protected] | 3acb8047 | 2012-10-18 01:41:08 | [diff] [blame] | 117 | return; |
| 118 | } |
[email protected] | 1aec345 | 2013-08-16 22:29:52 | [diff] [blame] | 119 | |
| 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 Lambrou | 6fb4a12 | 2019-06-06 22:16:38 | [diff] [blame] | 131 | service_client_->RegisterHost(host_id_, host_name_, |
| 132 | key_pair_->GetPublicKey(), host_client_id, |
| 133 | directory_access_token_, this); |
[email protected] | 1aec345 | 2013-08-16 22:29:52 | [diff] [blame] | 134 | } 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] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 140 | } |
| 141 | |
[email protected] | 1aec345 | 2013-08-16 22:29:52 | [diff] [blame] | 142 | void HostStarter::OnHostRegistered(const std::string& authorization_code) { |
[email protected] | 3acb8047 | 2012-10-18 01:41:08 | [diff] [blame] | 143 | if (!main_task_runner_->BelongsToCurrentThread()) { |
kylechar | 2caf4d6 | 2019-02-15 20:03:42 | [diff] [blame] | 144 | main_task_runner_->PostTask( |
| 145 | FROM_HERE, base::BindOnce(&HostStarter::OnHostRegistered, weak_ptr_, |
| 146 | authorization_code)); |
[email protected] | 3acb8047 | 2012-10-18 01:41:08 | [diff] [blame] | 147 | return; |
| 148 | } |
[email protected] | 1aec345 | 2013-08-16 22:29:52 | [diff] [blame] | 149 | |
| 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 Lambrou | 6fb4a12 | 2019-06-06 22:16:38 | [diff] [blame] | 159 | DCHECK_EQ(pending_get_tokens_, GET_TOKENS_NONE); |
| 160 | pending_get_tokens_ = GET_TOKENS_HOST; |
| 161 | |
[email protected] | 1aec345 | 2013-08-16 22:29:52 | [diff] [blame] | 162 | 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 | |
| 173 | void HostStarter::StartHostProcess() { |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 174 | // Start the host. |
| 175 | std::string host_secret_hash = remoting::MakeHostPinHash(host_id_, host_pin_); |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 176 | std::unique_ptr<base::DictionaryValue> config(new base::DictionaryValue()); |
[email protected] | 1aec345 | 2013-08-16 22:29:52 | [diff] [blame] | 177 | if (host_owner_ != xmpp_login_) { |
| 178 | config->SetString("host_owner", host_owner_); |
| 179 | } |
| 180 | config->SetString("xmpp_login", xmpp_login_); |
Lambros Lambrou | 6fb4a12 | 2019-06-06 22:16:38 | [diff] [blame] | 181 | config->SetString("oauth_refresh_token", host_refresh_token_); |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 182 | config->SetString("host_id", host_id_); |
| 183 | config->SetString("host_name", host_name_); |
[email protected] | 8f1504b | 2013-03-07 13:43:10 | [diff] [blame] | 184 | config->SetString("private_key", key_pair_->ToString()); |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 185 | config->SetString("host_secret_hash", host_secret_hash); |
| 186 | daemon_controller_->SetConfigAndStart( |
sergeyu | 1417e013 | 2015-12-23 19:01:22 | [diff] [blame] | 187 | std::move(config), consent_to_data_collection_, |
[email protected] | 3acb8047 | 2012-10-18 01:41:08 | [diff] [blame] | 188 | base::Bind(&HostStarter::OnHostStarted, base::Unretained(this))); |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 189 | } |
| 190 | |
| 191 | void HostStarter::OnHostStarted(DaemonController::AsyncResult result) { |
[email protected] | 3acb8047 | 2012-10-18 01:41:08 | [diff] [blame] | 192 | if (!main_task_runner_->BelongsToCurrentThread()) { |
kylechar | 2caf4d6 | 2019-02-15 20:03:42 | [diff] [blame] | 193 | main_task_runner_->PostTask( |
| 194 | FROM_HERE, |
| 195 | base::BindOnce(&HostStarter::OnHostStarted, weak_ptr_, result)); |
[email protected] | 3acb8047 | 2012-10-18 01:41:08 | [diff] [blame] | 196 | return; |
| 197 | } |
[email protected] | d215b65 | 2012-10-27 00:50:10 | [diff] [blame] | 198 | if (result != DaemonController::RESULT_OK) { |
[email protected] | 761cc1ae | 2013-08-28 00:24:58 | [diff] [blame] | 199 | unregistering_host_ = true; |
Lambros Lambrou | 6fb4a12 | 2019-06-06 22:16:38 | [diff] [blame] | 200 | service_client_->UnregisterHost(host_id_, directory_access_token_, this); |
[email protected] | d215b65 | 2012-10-27 00:50:10 | [diff] [blame] | 201 | return; |
| 202 | } |
Daniel Cheng | ce48c3c4 | 2019-04-26 15:06:08 | [diff] [blame] | 203 | std::move(on_done_).Run(START_COMPLETE); |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 204 | } |
| 205 | |
| 206 | void HostStarter::OnOAuthError() { |
[email protected] | 3acb8047 | 2012-10-18 01:41:08 | [diff] [blame] | 207 | if (!main_task_runner_->BelongsToCurrentThread()) { |
kylechar | 2caf4d6 | 2019-02-15 20:03:42 | [diff] [blame] | 208 | main_task_runner_->PostTask( |
| 209 | FROM_HERE, base::BindOnce(&HostStarter::OnOAuthError, weak_ptr_)); |
[email protected] | 3acb8047 | 2012-10-18 01:41:08 | [diff] [blame] | 210 | return; |
| 211 | } |
Lambros Lambrou | 6fb4a12 | 2019-06-06 22:16:38 | [diff] [blame] | 212 | |
| 213 | pending_get_tokens_ = GET_TOKENS_NONE; |
[email protected] | 761cc1ae | 2013-08-28 00:24:58 | [diff] [blame] | 214 | if (unregistering_host_) { |
| 215 | LOG(ERROR) << "OAuth error occurred when unregistering host."; |
[email protected] | 761cc1ae | 2013-08-28 00:24:58 | [diff] [blame] | 216 | } |
sergeyu | d9bdcb6 | 2015-04-25 00:18:08 | [diff] [blame] | 217 | |
Daniel Cheng | ce48c3c4 | 2019-04-26 15:06:08 | [diff] [blame] | 218 | std::move(on_done_).Run(unregistering_host_ ? START_ERROR : OAUTH_ERROR); |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 219 | } |
| 220 | |
| 221 | void HostStarter::OnNetworkError(int response_code) { |
[email protected] | 3acb8047 | 2012-10-18 01:41:08 | [diff] [blame] | 222 | if (!main_task_runner_->BelongsToCurrentThread()) { |
kylechar | 2caf4d6 | 2019-02-15 20:03:42 | [diff] [blame] | 223 | main_task_runner_->PostTask( |
| 224 | FROM_HERE, |
| 225 | base::BindOnce(&HostStarter::OnNetworkError, weak_ptr_, response_code)); |
[email protected] | 3acb8047 | 2012-10-18 01:41:08 | [diff] [blame] | 226 | return; |
| 227 | } |
Lambros Lambrou | 6fb4a12 | 2019-06-06 22:16:38 | [diff] [blame] | 228 | |
| 229 | pending_get_tokens_ = GET_TOKENS_NONE; |
[email protected] | 761cc1ae | 2013-08-28 00:24:58 | [diff] [blame] | 230 | if (unregistering_host_) { |
| 231 | LOG(ERROR) << "Network error occurred when unregistering host."; |
[email protected] | 761cc1ae | 2013-08-28 00:24:58 | [diff] [blame] | 232 | } |
sergeyu | d9bdcb6 | 2015-04-25 00:18:08 | [diff] [blame] | 233 | |
Daniel Cheng | ce48c3c4 | 2019-04-26 15:06:08 | [diff] [blame] | 234 | std::move(on_done_).Run(unregistering_host_ ? START_ERROR : NETWORK_ERROR); |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 235 | } |
| 236 | |
[email protected] | d215b65 | 2012-10-27 00:50:10 | [diff] [blame] | 237 | void HostStarter::OnHostUnregistered() { |
| 238 | if (!main_task_runner_->BelongsToCurrentThread()) { |
kylechar | 2caf4d6 | 2019-02-15 20:03:42 | [diff] [blame] | 239 | main_task_runner_->PostTask( |
| 240 | FROM_HERE, base::BindOnce(&HostStarter::OnHostUnregistered, weak_ptr_)); |
[email protected] | d215b65 | 2012-10-27 00:50:10 | [diff] [blame] | 241 | return; |
| 242 | } |
Daniel Cheng | ce48c3c4 | 2019-04-26 15:06:08 | [diff] [blame] | 243 | std::move(on_done_).Run(START_ERROR); |
[email protected] | d215b65 | 2012-10-27 00:50:10 | [diff] [blame] | 244 | } |
| 245 | |
[email protected] | d0f6847 | 2012-10-05 03:27:35 | [diff] [blame] | 246 | } // namespace remoting |