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/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"
15 const int kMaxGetTokensRetries
= 3;
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();
34 HostStarter::~HostStarter() {
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(),
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());
62 host_name_
= host_name
;
64 consent_to_data_collection_
= consent_to_data_collection
;
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);
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
));
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);
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.
99 // This function is called twice: once with the host owner credentials, and once
100 // with the service account credentials.
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
));
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();
115 std::string host_client_id
;
116 host_client_id
= google_apis::GetOAuth2ClientID(
117 google_apis::CLIENT_REMOTING_HOST
);
119 service_client_
->RegisterHost(
120 host_id_
, host_name_
, key_pair_
->GetPublicKey(), host_client_id
,
121 access_token_
, this);
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
;
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
));
137 if (authorization_code
.empty()) {
138 // No service account code, start the host with the owner's credentials.
139 xmpp_login_
= host_owner_
;
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);
157 void HostStarter::StartHostProcess() {
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_
);
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)));
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
));
181 if (result
!= DaemonController::RESULT_OK
) {
182 unregistering_host_
= true;
183 service_client_
->UnregisterHost(host_id_
, access_token_
, this);
186 CompletionCallback cb
= on_done_
;
188 cb
.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 CompletionCallback cb
= on_done_
;
199 if (unregistering_host_
) {
200 LOG(ERROR
) << "OAuth error occurred when unregistering host.";
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
));
213 CompletionCallback cb
= on_done_
;
215 if (unregistering_host_
) {
216 LOG(ERROR
) << "Network error occurred when unregistering host.";
219 cb
.Run(NETWORK_ERROR
);
223 void HostStarter::OnHostUnregistered() {
224 if (!main_task_runner_
->BelongsToCurrentThread()) {
225 main_task_runner_
->PostTask(FROM_HERE
, base::Bind(
226 &HostStarter::OnHostUnregistered
, weak_ptr_
));
229 CompletionCallback cb
= on_done_
;
234 } // namespace remoting