• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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