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