Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / remoting / host / oauth_token_getter_impl.cc
blob37b51afa43087c8e51af76644b16b458be95d639
1 // Copyright 2014 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/oauth_token_getter_impl.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/strings/string_util.h"
10 #include "google_apis/google_api_keys.h"
11 #include "net/url_request/url_request_context_getter.h"
12 #include "remoting/base/logging.h"
14 namespace remoting {
16 namespace {
18 // Maximum number of retries on network/500 errors.
19 const int kMaxRetries = 3;
21 // Time when we we try to update OAuth token before its expiration.
22 const int kTokenUpdateTimeBeforeExpirySeconds = 60;
24 } // namespace
26 OAuthTokenGetterImpl::OAuthTokenGetterImpl(
27 scoped_ptr<OAuthCredentials> oauth_credentials,
28 const scoped_refptr<net::URLRequestContextGetter>&
29 url_request_context_getter,
30 bool auto_refresh)
31 : oauth_credentials_(oauth_credentials.Pass()),
32 gaia_oauth_client_(
33 new gaia::GaiaOAuthClient(url_request_context_getter.get())),
34 url_request_context_getter_(url_request_context_getter) {
35 if (auto_refresh) {
36 refresh_timer_.reset(new base::OneShotTimer<OAuthTokenGetterImpl>());
40 OAuthTokenGetterImpl::~OAuthTokenGetterImpl() {
43 void OAuthTokenGetterImpl::OnGetTokensResponse(const std::string& user_email,
44 const std::string& access_token,
45 int expires_seconds) {
46 NOTREACHED();
49 void OAuthTokenGetterImpl::OnRefreshTokenResponse(
50 const std::string& access_token,
51 int expires_seconds) {
52 DCHECK(CalledOnValidThread());
53 DCHECK(oauth_credentials_.get());
54 HOST_LOG << "Received OAuth token.";
56 oauth_access_token_ = access_token;
57 base::TimeDelta token_expiration =
58 base::TimeDelta::FromSeconds(expires_seconds) -
59 base::TimeDelta::FromSeconds(kTokenUpdateTimeBeforeExpirySeconds);
60 auth_token_expiry_time_ = base::Time::Now() + token_expiration;
62 if (refresh_timer_) {
63 refresh_timer_->Stop();
64 refresh_timer_->Start(FROM_HERE, token_expiration, this,
65 &OAuthTokenGetterImpl::RefreshOAuthToken);
68 if (!oauth_credentials_->is_service_account && !email_verified_) {
69 gaia_oauth_client_->GetUserEmail(access_token, kMaxRetries, this);
70 } else {
71 refreshing_oauth_token_ = false;
72 NotifyCallbacks(OAuthTokenGetterImpl::SUCCESS, oauth_credentials_->login,
73 oauth_access_token_);
77 void OAuthTokenGetterImpl::OnGetUserEmailResponse(
78 const std::string& user_email) {
79 DCHECK(CalledOnValidThread());
80 DCHECK(oauth_credentials_.get());
81 HOST_LOG << "Received user info.";
83 if (user_email != oauth_credentials_->login) {
84 LOG(ERROR) << "OAuth token and email address do not refer to "
85 "the same account.";
86 OnOAuthError();
87 return;
90 email_verified_ = true;
91 refreshing_oauth_token_ = false;
93 // Now that we've refreshed the token and verified that it's for the correct
94 // user account, try to connect using the new token.
95 NotifyCallbacks(OAuthTokenGetterImpl::SUCCESS, user_email,
96 oauth_access_token_);
99 void OAuthTokenGetterImpl::NotifyCallbacks(Status status,
100 const std::string& user_email,
101 const std::string& access_token) {
102 std::queue<TokenCallback> callbacks(pending_callbacks_);
103 pending_callbacks_ = std::queue<TokenCallback>();
105 while (!callbacks.empty()) {
106 callbacks.front().Run(status, user_email, access_token);
107 callbacks.pop();
111 void OAuthTokenGetterImpl::OnOAuthError() {
112 DCHECK(CalledOnValidThread());
113 LOG(ERROR) << "OAuth: invalid credentials.";
114 refreshing_oauth_token_ = false;
116 // Throw away invalid credentials and force a refresh.
117 oauth_access_token_.clear();
118 auth_token_expiry_time_ = base::Time();
119 email_verified_ = false;
121 NotifyCallbacks(OAuthTokenGetterImpl::AUTH_ERROR, std::string(),
122 std::string());
125 void OAuthTokenGetterImpl::OnNetworkError(int response_code) {
126 DCHECK(CalledOnValidThread());
127 LOG(ERROR) << "Network error when trying to update OAuth token: "
128 << response_code;
129 refreshing_oauth_token_ = false;
130 NotifyCallbacks(OAuthTokenGetterImpl::NETWORK_ERROR, std::string(),
131 std::string());
134 void OAuthTokenGetterImpl::CallWithToken(const TokenCallback& on_access_token) {
135 DCHECK(CalledOnValidThread());
136 bool need_new_auth_token = auth_token_expiry_time_.is_null() ||
137 base::Time::Now() >= auth_token_expiry_time_ ||
138 (!oauth_credentials_->is_service_account &&
139 !email_verified_);
141 if (need_new_auth_token) {
142 pending_callbacks_.push(on_access_token);
143 if (!refreshing_oauth_token_)
144 RefreshOAuthToken();
145 } else {
146 on_access_token.Run(SUCCESS, oauth_credentials_->login,
147 oauth_access_token_);
151 void OAuthTokenGetterImpl::RefreshOAuthToken() {
152 DCHECK(CalledOnValidThread());
153 HOST_LOG << "Refreshing OAuth token.";
154 DCHECK(!refreshing_oauth_token_);
156 // Service accounts use different API keys, as they use the client app flow.
157 google_apis::OAuth2Client oauth2_client =
158 oauth_credentials_->is_service_account ? google_apis::CLIENT_REMOTING_HOST
159 : google_apis::CLIENT_REMOTING;
161 gaia::OAuthClientInfo client_info = {
162 google_apis::GetOAuth2ClientID(oauth2_client),
163 google_apis::GetOAuth2ClientSecret(oauth2_client),
164 // Redirect URL is only used when getting tokens from auth code. It
165 // is not required when getting access tokens.
166 ""};
168 refreshing_oauth_token_ = true;
169 std::vector<std::string> empty_scope_list; // Use scope from refresh token.
170 gaia_oauth_client_->RefreshToken(client_info,
171 oauth_credentials_->refresh_token,
172 empty_scope_list, kMaxRetries, this);
175 } // namespace remoting