| OLD | NEW | 
|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "remoting/host/signaling_connector.h" | 5 #include "remoting/host/signaling_connector.h" | 
| 6 | 6 | 
| 7 #include "base/bind.h" | 7 #include "base/bind.h" | 
| 8 #include "base/callback.h" | 8 #include "base/callback.h" | 
| 9 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" | 
| 10 #include "google_apis/google_api_keys.h" | 10 #include "google_apis/google_api_keys.h" | 
| 11 #include "net/url_request/url_fetcher.h" | 11 #include "net/url_request/url_fetcher.h" | 
| 12 #include "net/url_request/url_request_context_getter.h" | 12 #include "net/url_request/url_request_context_getter.h" | 
| 13 #include "remoting/base/logging.h" | 13 #include "remoting/base/logging.h" | 
| 14 #include "remoting/host/dns_blackhole_checker.h" | 14 #include "remoting/host/dns_blackhole_checker.h" | 
| 15 | 15 | 
| 16 namespace remoting { | 16 namespace remoting { | 
| 17 | 17 | 
| 18 namespace { | 18 namespace { | 
| 19 | 19 | 
| 20 // The delay between reconnect attempts will increase exponentially up | 20 // The delay between reconnect attempts will increase exponentially up | 
| 21 // to the maximum specified here. | 21 // to the maximum specified here. | 
| 22 const int kMaxReconnectDelaySeconds = 10 * 60; | 22 const int kMaxReconnectDelaySeconds = 10 * 60; | 
| 23 | 23 | 
| 24 // Time when we we try to update OAuth token before its expiration. |  | 
| 25 const int kTokenUpdateTimeBeforeExpirySeconds = 60; |  | 
| 26 |  | 
| 27 }  // namespace | 24 }  // namespace | 
| 28 | 25 | 
| 29 SignalingConnector::OAuthCredentials::OAuthCredentials( |  | 
| 30     const std::string& login_value, |  | 
| 31     const std::string& refresh_token_value, |  | 
| 32     bool is_service_account) |  | 
| 33     : login(login_value), |  | 
| 34       refresh_token(refresh_token_value), |  | 
| 35       is_service_account(is_service_account) { |  | 
| 36 } |  | 
| 37 |  | 
| 38 SignalingConnector::SignalingConnector( | 26 SignalingConnector::SignalingConnector( | 
| 39     XmppSignalStrategy* signal_strategy, | 27     XmppSignalStrategy* signal_strategy, | 
| 40     scoped_refptr<net::URLRequestContextGetter> url_request_context_getter, |  | 
| 41     scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker, | 28     scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker, | 
| 42     const base::Closure& auth_failed_callback) | 29     const base::Closure& auth_failed_callback) | 
| 43     : signal_strategy_(signal_strategy), | 30     : signal_strategy_(signal_strategy), | 
| 44       url_request_context_getter_(url_request_context_getter), |  | 
| 45       auth_failed_callback_(auth_failed_callback), | 31       auth_failed_callback_(auth_failed_callback), | 
| 46       dns_blackhole_checker_(dns_blackhole_checker.Pass()), | 32       dns_blackhole_checker_(dns_blackhole_checker.Pass()), | 
| 47       reconnect_attempts_(0), | 33       reconnect_attempts_(0) { | 
| 48       refreshing_oauth_token_(false) { |  | 
| 49   DCHECK(!auth_failed_callback_.is_null()); | 34   DCHECK(!auth_failed_callback_.is_null()); | 
| 50   DCHECK(dns_blackhole_checker_.get()); | 35   DCHECK(dns_blackhole_checker_.get()); | 
| 51   net::NetworkChangeNotifier::AddConnectionTypeObserver(this); | 36   net::NetworkChangeNotifier::AddConnectionTypeObserver(this); | 
| 52   net::NetworkChangeNotifier::AddIPAddressObserver(this); | 37   net::NetworkChangeNotifier::AddIPAddressObserver(this); | 
| 53   signal_strategy_->AddListener(this); | 38   signal_strategy_->AddListener(this); | 
| 54   ScheduleTryReconnect(); | 39   ScheduleTryReconnect(); | 
| 55 } | 40 } | 
| 56 | 41 | 
| 57 SignalingConnector::~SignalingConnector() { | 42 SignalingConnector::~SignalingConnector() { | 
| 58   signal_strategy_->RemoveListener(this); | 43   signal_strategy_->RemoveListener(this); | 
| 59   net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this); | 44   net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this); | 
| 60   net::NetworkChangeNotifier::RemoveIPAddressObserver(this); | 45   net::NetworkChangeNotifier::RemoveIPAddressObserver(this); | 
| 61 } | 46 } | 
| 62 | 47 | 
| 63 void SignalingConnector::EnableOAuth( | 48 void SignalingConnector::EnableOAuth(OAuthTokenGetter* oauth_token_getter) { | 
| 64     scoped_ptr<OAuthCredentials> oauth_credentials) { | 49   oauth_token_getter_ = oauth_token_getter; | 
| 65   oauth_credentials_ = oauth_credentials.Pass(); |  | 
| 66   gaia_oauth_client_.reset( |  | 
| 67       new gaia::GaiaOAuthClient(url_request_context_getter_.get())); |  | 
| 68 } | 50 } | 
| 69 | 51 | 
| 70 void SignalingConnector::OnSignalStrategyStateChange( | 52 void SignalingConnector::OnSignalStrategyStateChange( | 
| 71     SignalStrategy::State state) { | 53     SignalStrategy::State state) { | 
| 72   DCHECK(CalledOnValidThread()); | 54   DCHECK(CalledOnValidThread()); | 
| 73 | 55 | 
| 74   if (state == SignalStrategy::CONNECTED) { | 56   if (state == SignalStrategy::CONNECTED) { | 
| 75     HOST_LOG << "Signaling connected."; | 57     HOST_LOG << "Signaling connected."; | 
| 76     reconnect_attempts_ = 0; | 58     reconnect_attempts_ = 0; | 
| 77   } else if (state == SignalStrategy::DISCONNECTED) { | 59   } else if (state == SignalStrategy::DISCONNECTED) { | 
| (...skipping 26 matching lines...) Expand all  Loading... | 
| 104 } | 86 } | 
| 105 | 87 | 
| 106 void SignalingConnector::OnIPAddressChanged() { | 88 void SignalingConnector::OnIPAddressChanged() { | 
| 107   DCHECK(CalledOnValidThread()); | 89   DCHECK(CalledOnValidThread()); | 
| 108   if (signal_strategy_->GetState() == SignalStrategy::DISCONNECTED) { | 90   if (signal_strategy_->GetState() == SignalStrategy::DISCONNECTED) { | 
| 109     HOST_LOG << "IP address has changed."; | 91     HOST_LOG << "IP address has changed."; | 
| 110     ResetAndTryReconnect(); | 92     ResetAndTryReconnect(); | 
| 111   } | 93   } | 
| 112 } | 94 } | 
| 113 | 95 | 
| 114 void SignalingConnector::OnGetTokensResponse(const std::string& user_email, | 96 void SignalingConnector::OnAccessToken(OAuthTokenGetter::Status status, | 
| 115                                              const std::string& access_token, | 97                                        const std::string& user_email, | 
| 116                                              int expires_seconds) { | 98                                        const std::string& access_token) { | 
| 117   NOTREACHED(); | 99   DCHECK(CalledOnValidThread()); | 
| 118 } |  | 
| 119 | 100 | 
| 120 void SignalingConnector::OnRefreshTokenResponse( | 101   if (status == OAuthTokenGetter::AUTH_ERROR) { | 
| 121     const std::string& access_token, |  | 
| 122     int expires_seconds) { |  | 
| 123   DCHECK(CalledOnValidThread()); |  | 
| 124   DCHECK(oauth_credentials_.get()); |  | 
| 125   HOST_LOG << "Received OAuth token."; |  | 
| 126 |  | 
| 127   oauth_access_token_ = access_token; |  | 
| 128   auth_token_expiry_time_ = base::Time::Now() + |  | 
| 129       base::TimeDelta::FromSeconds(expires_seconds) - |  | 
| 130       base::TimeDelta::FromSeconds(kTokenUpdateTimeBeforeExpirySeconds); |  | 
| 131 |  | 
| 132   gaia_oauth_client_->GetUserEmail(access_token, 1, this); |  | 
| 133 } |  | 
| 134 |  | 
| 135 void SignalingConnector::OnGetUserEmailResponse(const std::string& user_email) { |  | 
| 136   DCHECK(CalledOnValidThread()); |  | 
| 137   DCHECK(oauth_credentials_.get()); |  | 
| 138   HOST_LOG << "Received user info."; |  | 
| 139 |  | 
| 140   if (user_email != oauth_credentials_->login) { |  | 
| 141     LOG(ERROR) << "OAuth token and email address do not refer to " |  | 
| 142         "the same account."; |  | 
| 143     auth_failed_callback_.Run(); | 102     auth_failed_callback_.Run(); | 
| 144     return; | 103     return; | 
|  | 104   } else if (status == OAuthTokenGetter::NETWORK_ERROR) { | 
|  | 105     OnNetworkError(); | 
|  | 106     return; | 
| 145   } | 107   } | 
| 146 | 108 | 
| 147   signal_strategy_->SetAuthInfo(oauth_credentials_->login, | 109   DCHECK_EQ(status, OAuthTokenGetter::SUCCESS); | 
| 148                                 oauth_access_token_, "oauth2"); | 110   HOST_LOG << "Received user info."; | 
| 149   refreshing_oauth_token_ = false; | 111 | 
|  | 112   signal_strategy_->SetAuthInfo(user_email, access_token, "oauth2"); | 
| 150 | 113 | 
| 151   // Now that we've refreshed the token and verified that it's for the correct | 114   // Now that we've refreshed the token and verified that it's for the correct | 
| 152   // user account, try to connect using the new token. | 115   // user account, try to connect using the new token. | 
| 153   DCHECK_EQ(signal_strategy_->GetState(), SignalStrategy::DISCONNECTED); | 116   DCHECK_EQ(signal_strategy_->GetState(), SignalStrategy::DISCONNECTED); | 
| 154   signal_strategy_->Connect(); | 117   signal_strategy_->Connect(); | 
| 155 } | 118 } | 
| 156 | 119 | 
| 157 void SignalingConnector::OnOAuthError() { | 120 void SignalingConnector::OnNetworkError() { | 
| 158   DCHECK(CalledOnValidThread()); | 121   DCHECK(CalledOnValidThread()); | 
| 159   LOG(ERROR) << "OAuth: invalid credentials."; |  | 
| 160   refreshing_oauth_token_ = false; |  | 
| 161   reconnect_attempts_++; |  | 
| 162   auth_failed_callback_.Run(); |  | 
| 163 } |  | 
| 164 |  | 
| 165 void SignalingConnector::OnNetworkError(int response_code) { |  | 
| 166   DCHECK(CalledOnValidThread()); |  | 
| 167   LOG(ERROR) << "Network error when trying to update OAuth token: " |  | 
| 168              << response_code; |  | 
| 169   refreshing_oauth_token_ = false; |  | 
| 170   reconnect_attempts_++; | 122   reconnect_attempts_++; | 
| 171   ScheduleTryReconnect(); | 123   ScheduleTryReconnect(); | 
| 172 } | 124 } | 
| 173 | 125 | 
| 174 void SignalingConnector::ScheduleTryReconnect() { | 126 void SignalingConnector::ScheduleTryReconnect() { | 
| 175   DCHECK(CalledOnValidThread()); | 127   DCHECK(CalledOnValidThread()); | 
| 176   if (timer_.IsRunning() || net::NetworkChangeNotifier::IsOffline()) | 128   if (timer_.IsRunning() || net::NetworkChangeNotifier::IsOffline()) | 
| 177     return; | 129     return; | 
| 178   int delay_s = std::min(1 << reconnect_attempts_, | 130   int delay_s = std::min(1 << reconnect_attempts_, | 
| 179                          kMaxReconnectDelaySeconds); | 131                          kMaxReconnectDelaySeconds); | 
| (...skipping 28 matching lines...) Expand all  Loading... | 
| 208   // an outright block. | 160   // an outright block. | 
| 209   if (!allow) { | 161   if (!allow) { | 
| 210     reconnect_attempts_++; | 162     reconnect_attempts_++; | 
| 211     HOST_LOG << "Talkgadget check failed. Scheduling reconnect. Attempt " | 163     HOST_LOG << "Talkgadget check failed. Scheduling reconnect. Attempt " | 
| 212               << reconnect_attempts_; | 164               << reconnect_attempts_; | 
| 213     ScheduleTryReconnect(); | 165     ScheduleTryReconnect(); | 
| 214     return; | 166     return; | 
| 215   } | 167   } | 
| 216 | 168 | 
| 217   if (signal_strategy_->GetState() == SignalStrategy::DISCONNECTED) { | 169   if (signal_strategy_->GetState() == SignalStrategy::DISCONNECTED) { | 
| 218     bool need_new_auth_token = oauth_credentials_.get() && | 170     HOST_LOG << "Attempting to connect signaling."; | 
| 219         (auth_token_expiry_time_.is_null() || | 171     oauth_token_getter_->CallWithToken( | 
| 220          base::Time::Now() >= auth_token_expiry_time_); | 172         base::Bind(&SignalingConnector::OnAccessToken, AsWeakPtr())); | 
| 221     if (need_new_auth_token) { |  | 
| 222       RefreshOAuthToken(); |  | 
| 223     } else { |  | 
| 224       HOST_LOG << "Attempting to connect signaling."; |  | 
| 225       signal_strategy_->Connect(); |  | 
| 226     } |  | 
| 227   } | 173   } | 
| 228 } | 174 } | 
| 229 | 175 | 
| 230 void SignalingConnector::RefreshOAuthToken() { |  | 
| 231   DCHECK(CalledOnValidThread()); |  | 
| 232   HOST_LOG << "Refreshing OAuth token."; |  | 
| 233   DCHECK(!refreshing_oauth_token_); |  | 
| 234 |  | 
| 235   // Service accounts use different API keys, as they use the client app flow. |  | 
| 236   google_apis::OAuth2Client oauth2_client; |  | 
| 237   if (oauth_credentials_->is_service_account) { |  | 
| 238     oauth2_client = google_apis::CLIENT_REMOTING_HOST; |  | 
| 239   } else { |  | 
| 240     oauth2_client = google_apis::CLIENT_REMOTING; |  | 
| 241   } |  | 
| 242 |  | 
| 243   gaia::OAuthClientInfo client_info = { |  | 
| 244     google_apis::GetOAuth2ClientID(oauth2_client), |  | 
| 245     google_apis::GetOAuth2ClientSecret(oauth2_client), |  | 
| 246     // Redirect URL is only used when getting tokens from auth code. It |  | 
| 247     // is not required when getting access tokens. |  | 
| 248     "" |  | 
| 249   }; |  | 
| 250 |  | 
| 251   refreshing_oauth_token_ = true; |  | 
| 252   std::vector<std::string> empty_scope_list;  // (Use scope from refresh token.) |  | 
| 253   gaia_oauth_client_->RefreshToken( |  | 
| 254       client_info, oauth_credentials_->refresh_token, empty_scope_list, |  | 
| 255       1, this); |  | 
| 256 } |  | 
| 257 |  | 
| 258 }  // namespace remoting | 176 }  // namespace remoting | 
| OLD | NEW | 
|---|