Home | History | Annotate | Download | only in setup
      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/bind.h"
      8 #include "base/guid.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"
     15 
     16 namespace {
     17 const int kMaxGetTokensRetries = 3;
     18 }  // namespace
     19 
     20 namespace remoting {
     21 
     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();
     34 }
     35 
     36 HostStarter::~HostStarter() {
     37 }
     38 
     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 scoped_ptr<HostStarter>(
     50       new HostStarter(oauth_client.Pass(), service_client.Pass(),
     51                       daemon_controller));
     52 }
     53 
     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());
     63 
     64   host_name_ = host_name;
     65   host_pin_ = host_pin;
     66   consent_to_data_collection_ = consent_to_data_collection;
     67   on_done_ = on_done;
     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);
     76 }
     77 
     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));
     86     return;
     87   }
     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);
     92 }
     93 
     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.
     98   NOTREACHED();
     99 }
    100 
    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));
    107     return;
    108   }
    109 
    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();
    116 
    117     std::string host_client_id;
    118     host_client_id = google_apis::GetOAuth2ClientID(
    119         google_apis::CLIENT_REMOTING_HOST);
    120 
    121     service_client_->RegisterHost(
    122         host_id_, host_name_, key_pair_->GetPublicKey(), host_client_id,
    123         access_token_, this);
    124   } else {
    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;
    128     StartHostProcess();
    129   }
    130 }
    131 
    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));
    136     return;
    137   }
    138 
    139   if (authorization_code.empty()) {
    140     // No service account code, start the host with the owner's credentials.
    141     xmpp_login_ = host_owner_;
    142     StartHostProcess();
    143     return;
    144   }
    145 
    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);
    157 }
    158 
    159 void HostStarter::StartHostProcess() {
    160   // Start the host.
    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_);
    165   }
    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)));
    175 }
    176 
    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));
    181     return;
    182   }
    183   if (result != DaemonController::RESULT_OK) {
    184     unregistering_host_ = true;
    185     service_client_->UnregisterHost(host_id_, access_token_, this);
    186     return;
    187   }
    188   CompletionCallback cb = on_done_;
    189   on_done_.Reset();
    190   cb.Run(START_COMPLETE);
    191 }
    192 
    193 void HostStarter::OnOAuthError() {
    194   if (!main_task_runner_->BelongsToCurrentThread()) {
    195     main_task_runner_->PostTask(FROM_HERE, base::Bind(
    196         &HostStarter::OnOAuthError, weak_ptr_));
    197     return;
    198   }
    199   CompletionCallback cb = on_done_;
    200   on_done_.Reset();
    201   if (unregistering_host_) {
    202     LOG(ERROR) << "OAuth error occurred when unregistering host.";
    203     cb.Run(START_ERROR);
    204   } else {
    205     cb.Run(OAUTH_ERROR);
    206   }
    207 }
    208 
    209 void HostStarter::OnNetworkError(int response_code) {
    210   if (!main_task_runner_->BelongsToCurrentThread()) {
    211     main_task_runner_->PostTask(FROM_HERE, base::Bind(
    212         &HostStarter::OnNetworkError, weak_ptr_, response_code));
    213     return;
    214   }
    215   CompletionCallback cb = on_done_;
    216   on_done_.Reset();
    217   if (unregistering_host_) {
    218     LOG(ERROR) << "Network error occurred when unregistering host.";
    219     cb.Run(START_ERROR);
    220   } else {
    221     cb.Run(NETWORK_ERROR);
    222   }
    223 }
    224 
    225 void HostStarter::OnHostUnregistered() {
    226   if (!main_task_runner_->BelongsToCurrentThread()) {
    227     main_task_runner_->PostTask(FROM_HERE, base::Bind(
    228         &HostStarter::OnHostUnregistered, weak_ptr_));
    229     return;
    230   }
    231   CompletionCallback cb = on_done_;
    232   on_done_.Reset();
    233   cb.Run(START_ERROR);
    234 }
    235 
    236 }  // namespace remoting
    237