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/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 
     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 
     34 HostStarter::~HostStarter() {
     35 }
     36 
     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 
     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 
     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 
     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.
    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 
    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 
    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 
    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 
    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 
    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 
    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