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