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
7 #include "base/guid.h"
8 #include "base/thread_task_runner_handle.h"
9 #include "base/values.h"
10 #include "google_apis/google_api_keys.h"
11 #include "remoting/host/pin_hash.h"
12 #include "remoting/host/setup/oauth_helper.h"
13
14 namespace {
15 const int kMaxGetTokensRetries = 3;
16 } // namespace
17
18 namespace remoting {
19
HostStarter(scoped_ptr<gaia::GaiaOAuthClient> oauth_client,scoped_ptr<remoting::ServiceClient> service_client,scoped_refptr<remoting::DaemonController> daemon_controller)20 HostStarter::HostStarter(
21 scoped_ptr<gaia::GaiaOAuthClient> oauth_client,
22 scoped_ptr<remoting::ServiceClient> service_client,
23 scoped_refptr<remoting::DaemonController> daemon_controller)
24 : oauth_client_(oauth_client.Pass()),
25 service_client_(service_client.Pass()),
26 daemon_controller_(daemon_controller),
27 consent_to_data_collection_(false),
28 unregistering_host_(false),
29 weak_ptr_factory_(this) {
30 weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
31 main_task_runner_ = base::ThreadTaskRunnerHandle::Get();
32 }
33
~HostStarter()34 HostStarter::~HostStarter() {
35 }
36
Create(const std::string & chromoting_hosts_url,net::URLRequestContextGetter * url_request_context_getter)37 scoped_ptr<HostStarter> HostStarter::Create(
38 const std::string& chromoting_hosts_url,
39 net::URLRequestContextGetter* url_request_context_getter) {
40 scoped_ptr<gaia::GaiaOAuthClient> oauth_client(
41 new gaia::GaiaOAuthClient(url_request_context_getter));
42 scoped_ptr<remoting::ServiceClient> service_client(
43 new remoting::ServiceClient(
44 chromoting_hosts_url, url_request_context_getter));
45 scoped_refptr<remoting::DaemonController> daemon_controller(
46 remoting::DaemonController::Create());
47 return scoped_ptr<HostStarter>(
48 new HostStarter(oauth_client.Pass(), service_client.Pass(),
49 daemon_controller));
50 }
51
StartHost(const std::string & host_name,const std::string & host_pin,bool consent_to_data_collection,const std::string & auth_code,const std::string & redirect_url,CompletionCallback on_done)52 void HostStarter::StartHost(
53 const std::string& host_name,
54 const std::string& host_pin,
55 bool consent_to_data_collection,
56 const std::string& auth_code,
57 const std::string& redirect_url,
58 CompletionCallback on_done) {
59 DCHECK(main_task_runner_->BelongsToCurrentThread());
60 DCHECK(on_done_.is_null());
61
62 host_name_ = host_name;
63 host_pin_ = host_pin;
64 consent_to_data_collection_ = consent_to_data_collection;
65 on_done_ = on_done;
66 oauth_client_info_.client_id =
67 google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING);
68 oauth_client_info_.client_secret =
69 google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_REMOTING);
70 oauth_client_info_.redirect_uri = redirect_url;
71 // Map the authorization code to refresh and access tokens.
72 oauth_client_->GetTokensFromAuthCode(oauth_client_info_, auth_code,
73 kMaxGetTokensRetries, this);
74 }
75
OnGetTokensResponse(const std::string & refresh_token,const std::string & access_token,int expires_in_seconds)76 void HostStarter::OnGetTokensResponse(
77 const std::string& refresh_token,
78 const std::string& access_token,
79 int expires_in_seconds) {
80 if (!main_task_runner_->BelongsToCurrentThread()) {
81 main_task_runner_->PostTask(FROM_HERE, base::Bind(
82 &HostStarter::OnGetTokensResponse, weak_ptr_,
83 refresh_token, access_token, expires_in_seconds));
84 return;
85 }
86 refresh_token_ = refresh_token;
87 access_token_ = access_token;
88 // Get the email corresponding to the access token.
89 oauth_client_->GetUserEmail(access_token_, 1, this);
90 }
91
OnRefreshTokenResponse(const std::string & access_token,int expires_in_seconds)92 void HostStarter::OnRefreshTokenResponse(
93 const std::string& access_token,
94 int expires_in_seconds) {
95 // We never request a refresh token, so this call is not expected.
96 NOTREACHED();
97 }
98
99 // This function is called twice: once with the host owner credentials, and once
100 // with the service account credentials.
OnGetUserEmailResponse(const std::string & user_email)101 void HostStarter::OnGetUserEmailResponse(const std::string& user_email) {
102 if (!main_task_runner_->BelongsToCurrentThread()) {
103 main_task_runner_->PostTask(FROM_HERE, base::Bind(
104 &HostStarter::OnGetUserEmailResponse, weak_ptr_, user_email));
105 return;
106 }
107
108 if (host_owner_.empty()) {
109 // This is the first callback, with the host owner credentials. Store the
110 // owner's email, and register the host.
111 host_owner_ = user_email;
112 host_id_ = base::GenerateGUID();
113 key_pair_ = RsaKeyPair::Generate();
114
115 std::string host_client_id;
116 host_client_id = google_apis::GetOAuth2ClientID(
117 google_apis::CLIENT_REMOTING_HOST);
118
119 service_client_->RegisterHost(
120 host_id_, host_name_, key_pair_->GetPublicKey(), host_client_id,
121 access_token_, this);
122 } else {
123 // This is the second callback, with the service account credentials.
124 // This email is the service account's email, used to login to XMPP.
125 xmpp_login_ = user_email;
126 StartHostProcess();
127 }
128 }
129
OnHostRegistered(const std::string & authorization_code)130 void HostStarter::OnHostRegistered(const std::string& authorization_code) {
131 if (!main_task_runner_->BelongsToCurrentThread()) {
132 main_task_runner_->PostTask(FROM_HERE, base::Bind(
133 &HostStarter::OnHostRegistered, weak_ptr_, authorization_code));
134 return;
135 }
136
137 if (authorization_code.empty()) {
138 // No service account code, start the host with the owner's credentials.
139 xmpp_login_ = host_owner_;
140 StartHostProcess();
141 return;
142 }
143
144 // Received a service account authorization code, update oauth_client_info_
145 // to use the service account client keys, and get service account tokens.
146 oauth_client_info_.client_id =
147 google_apis::GetOAuth2ClientID(
148 google_apis::CLIENT_REMOTING_HOST);
149 oauth_client_info_.client_secret =
150 google_apis::GetOAuth2ClientSecret(
151 google_apis::CLIENT_REMOTING_HOST);
152 oauth_client_info_.redirect_uri = "oob";
153 oauth_client_->GetTokensFromAuthCode(
154 oauth_client_info_, authorization_code, kMaxGetTokensRetries, this);
155 }
156
StartHostProcess()157 void HostStarter::StartHostProcess() {
158 // Start the host.
159 std::string host_secret_hash = remoting::MakeHostPinHash(host_id_, host_pin_);
160 scoped_ptr<base::DictionaryValue> config(new base::DictionaryValue());
161 if (host_owner_ != xmpp_login_) {
162 config->SetString("host_owner", host_owner_);
163 }
164 config->SetString("xmpp_login", xmpp_login_);
165 config->SetString("oauth_refresh_token", refresh_token_);
166 config->SetString("host_id", host_id_);
167 config->SetString("host_name", host_name_);
168 config->SetString("private_key", key_pair_->ToString());
169 config->SetString("host_secret_hash", host_secret_hash);
170 daemon_controller_->SetConfigAndStart(
171 config.Pass(), consent_to_data_collection_,
172 base::Bind(&HostStarter::OnHostStarted, base::Unretained(this)));
173 }
174
OnHostStarted(DaemonController::AsyncResult result)175 void HostStarter::OnHostStarted(DaemonController::AsyncResult result) {
176 if (!main_task_runner_->BelongsToCurrentThread()) {
177 main_task_runner_->PostTask(FROM_HERE, base::Bind(
178 &HostStarter::OnHostStarted, weak_ptr_, result));
179 return;
180 }
181 if (result != DaemonController::RESULT_OK) {
182 unregistering_host_ = true;
183 service_client_->UnregisterHost(host_id_, access_token_, this);
184 return;
185 }
186 CompletionCallback cb = on_done_;
187 on_done_.Reset();
188 cb.Run(START_COMPLETE);
189 }
190
OnOAuthError()191 void HostStarter::OnOAuthError() {
192 if (!main_task_runner_->BelongsToCurrentThread()) {
193 main_task_runner_->PostTask(FROM_HERE, base::Bind(
194 &HostStarter::OnOAuthError, weak_ptr_));
195 return;
196 }
197 CompletionCallback cb = on_done_;
198 on_done_.Reset();
199 if (unregistering_host_) {
200 LOG(ERROR) << "OAuth error occurred when unregistering host.";
201 cb.Run(START_ERROR);
202 } else {
203 cb.Run(OAUTH_ERROR);
204 }
205 }
206
OnNetworkError(int response_code)207 void HostStarter::OnNetworkError(int response_code) {
208 if (!main_task_runner_->BelongsToCurrentThread()) {
209 main_task_runner_->PostTask(FROM_HERE, base::Bind(
210 &HostStarter::OnNetworkError, weak_ptr_, response_code));
211 return;
212 }
213 CompletionCallback cb = on_done_;
214 on_done_.Reset();
215 if (unregistering_host_) {
216 LOG(ERROR) << "Network error occurred when unregistering host.";
217 cb.Run(START_ERROR);
218 } else {
219 cb.Run(NETWORK_ERROR);
220 }
221 }
222
OnHostUnregistered()223 void HostStarter::OnHostUnregistered() {
224 if (!main_task_runner_->BelongsToCurrentThread()) {
225 main_task_runner_->PostTask(FROM_HERE, base::Bind(
226 &HostStarter::OnHostUnregistered, weak_ptr_));
227 return;
228 }
229 CompletionCallback cb = on_done_;
230 on_done_.Reset();
231 cb.Run(START_ERROR);
232 }
233
234 } // namespace remoting
235