cloud_print_auth.cc revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
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 "chrome/service/cloud_print/cloud_print_auth.h" 6 7#include "base/bind.h" 8#include "base/string_util.h" 9#include "chrome/common/cloud_print/cloud_print_constants.h" 10#include "chrome/common/cloud_print/cloud_print_helpers.h" 11#include "chrome/service/cloud_print/cloud_print_token_store.h" 12#include "chrome/service/gaia/service_gaia_authenticator.h" 13#include "chrome/service/net/service_url_request_context.h" 14#include "chrome/service/service_process.h" 15#include "google_apis/gaia/gaia_urls.h" 16 17namespace cloud_print { 18 19CloudPrintAuth::CloudPrintAuth( 20 Client* client, 21 const GURL& cloud_print_server_url, 22 const gaia::OAuthClientInfo& oauth_client_info, 23 const std::string& proxy_id) 24 : client_(client), 25 oauth_client_info_(oauth_client_info), 26 cloud_print_server_url_(cloud_print_server_url), 27 proxy_id_(proxy_id) { 28 DCHECK(client); 29} 30 31void CloudPrintAuth::AuthenticateWithLsid( 32 const std::string& lsid, 33 const std::string& last_robot_refresh_token, 34 const std::string& last_robot_email, 35 const std::string& last_user_email) { 36 // Keeping VLOGs for Cloud Print proxy logging. It is convinient for finding 37 // issues with GCP in the field, where only release version is avaialble. 38 VLOG(1) << "CP_AUTH: Authenticating with LSID"; 39 scoped_refptr<ServiceGaiaAuthenticator> gaia_auth_for_print( 40 new ServiceGaiaAuthenticator( 41 kProxyAuthUserAgent, kCloudPrintGaiaServiceId, 42 GaiaUrls::GetInstance()->client_login_url(), 43 g_service_process->io_thread()->message_loop_proxy())); 44 gaia_auth_for_print->set_message_loop(base::MessageLoop::current()); 45 if (gaia_auth_for_print->AuthenticateWithLsid(lsid)) { 46 // Stash away the user email so we can save it in prefs. 47 user_email_ = gaia_auth_for_print->email(); 48 // If the same user is re-enabling Cloud Print and we have stashed robot 49 // credentials, we will use those. 50 if ((0 == base::strcasecmp(user_email_.c_str(), last_user_email.c_str())) && 51 !last_robot_refresh_token.empty() && 52 !last_robot_email.empty()) { 53 AuthenticateWithRobotToken(last_robot_refresh_token, 54 last_robot_email); 55 } 56 AuthenticateWithToken(gaia_auth_for_print->auth_token()); 57 } else { 58 // Notify client about authentication error. 59 client_->OnInvalidCredentials(); 60 } 61} 62 63void CloudPrintAuth::AuthenticateWithToken( 64 const std::string& cloud_print_token) { 65 VLOG(1) << "CP_AUTH: Authenticating with token"; 66 67 client_login_token_ = cloud_print_token; 68 69 // We need to get the credentials of the robot here. 70 GURL get_authcode_url = GetUrlForGetAuthCode(cloud_print_server_url_, 71 oauth_client_info_.client_id, 72 proxy_id_); 73 request_ = CloudPrintURLFetcher::Create(); 74 request_->StartGetRequest(get_authcode_url, 75 this, 76 kCloudPrintAuthMaxRetryCount, 77 std::string()); 78} 79 80void CloudPrintAuth::AuthenticateWithRobotToken( 81 const std::string& robot_oauth_refresh_token, 82 const std::string& robot_email) { 83 VLOG(1) << "CP_AUTH: Authenticating with robot token"; 84 85 robot_email_ = robot_email; 86 refresh_token_ = robot_oauth_refresh_token; 87 RefreshAccessToken(); 88} 89 90void CloudPrintAuth::AuthenticateWithRobotAuthCode( 91 const std::string& robot_oauth_auth_code, 92 const std::string& robot_email) { 93 VLOG(1) << "CP_AUTH: Authenticating with robot auth code"; 94 95 robot_email_ = robot_email; 96 // Now that we have an auth code we need to get the refresh and access tokens. 97 oauth_client_.reset(new gaia::GaiaOAuthClient( 98 GaiaUrls::GetInstance()->oauth2_token_url(), 99 g_service_process->GetServiceURLRequestContextGetter())); 100 oauth_client_->GetTokensFromAuthCode(oauth_client_info_, 101 robot_oauth_auth_code, 102 kCloudPrintAuthMaxRetryCount, 103 this); 104} 105 106void CloudPrintAuth::RefreshAccessToken() { 107 oauth_client_.reset(new gaia::GaiaOAuthClient( 108 GaiaUrls::GetInstance()->oauth2_token_url(), 109 g_service_process->GetServiceURLRequestContextGetter())); 110 oauth_client_->RefreshToken(oauth_client_info_, 111 refresh_token_, 112 kCloudPrintAuthMaxRetryCount, 113 this); 114} 115 116void CloudPrintAuth::OnGetTokensResponse(const std::string& refresh_token, 117 const std::string& access_token, 118 int expires_in_seconds) { 119 refresh_token_ = refresh_token; 120 // After saving the refresh token, this is just like having just refreshed 121 // the access token. Just call OnRefreshTokenResponse. 122 OnRefreshTokenResponse(access_token, expires_in_seconds); 123} 124 125void CloudPrintAuth::OnRefreshTokenResponse(const std::string& access_token, 126 int expires_in_seconds) { 127 client_->OnAuthenticationComplete(access_token, refresh_token_, 128 robot_email_, user_email_); 129 130 // Schedule a task to refresh the access token again when it is about to 131 // expire. 132 DCHECK(expires_in_seconds > kTokenRefreshGracePeriodSecs); 133 base::TimeDelta refresh_delay = base::TimeDelta::FromSeconds( 134 expires_in_seconds - kTokenRefreshGracePeriodSecs); 135 base::MessageLoop::current()->PostDelayedTask( 136 FROM_HERE, 137 base::Bind(&CloudPrintAuth::RefreshAccessToken, this), 138 refresh_delay); 139} 140 141void CloudPrintAuth::OnOAuthError() { 142 // Notify client about authentication error. 143 client_->OnInvalidCredentials(); 144} 145 146void CloudPrintAuth::OnNetworkError(int response_code) { 147 // Since we specify infinite retries on network errors, this should never 148 // be called. 149 NOTREACHED() << 150 "OnNetworkError invoked when not expected, response code is " << 151 response_code; 152} 153 154CloudPrintURLFetcher::ResponseAction CloudPrintAuth::HandleJSONData( 155 const net::URLFetcher* source, 156 const GURL& url, 157 base::DictionaryValue* json_data, 158 bool succeeded) { 159 if (!succeeded) { 160 VLOG(1) << "CP_AUTH: Creating robot account failed"; 161 client_->OnInvalidCredentials(); 162 return CloudPrintURLFetcher::STOP_PROCESSING; 163 } 164 165 std::string auth_code; 166 if (!json_data->GetString(kOAuthCodeValue, &auth_code)) { 167 VLOG(1) << "CP_AUTH: Creating robot account returned invalid json response"; 168 client_->OnInvalidCredentials(); 169 return CloudPrintURLFetcher::STOP_PROCESSING; 170 } 171 172 json_data->GetString(kXMPPJidValue, &robot_email_); 173 // Now that we have an auth code we need to get the refresh and access tokens. 174 oauth_client_.reset(new gaia::GaiaOAuthClient( 175 GaiaUrls::GetInstance()->oauth2_token_url(), 176 g_service_process->GetServiceURLRequestContextGetter())); 177 oauth_client_->GetTokensFromAuthCode(oauth_client_info_, 178 auth_code, 179 kCloudPrintAPIMaxRetryCount, 180 this); 181 182 return CloudPrintURLFetcher::STOP_PROCESSING; 183} 184 185CloudPrintURLFetcher::ResponseAction CloudPrintAuth::OnRequestAuthError() { 186 VLOG(1) << "CP_AUTH: Creating robot account authentication error"; 187 // Notify client about authentication error. 188 client_->OnInvalidCredentials(); 189 return CloudPrintURLFetcher::STOP_PROCESSING; 190} 191 192std::string CloudPrintAuth::GetAuthHeader() { 193 DCHECK(!client_login_token_.empty()); 194 std::string header; 195 header = "Authorization: GoogleLogin auth="; 196 header += client_login_token_; 197 return header; 198} 199 200CloudPrintAuth::~CloudPrintAuth() {} 201 202} // namespace cloud_print 203