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.
5 #include "chrome/service/cloud_print/cloud_print_auth.h"
8 #include "base/metrics/histogram.h"
9 #include "base/strings/string_util.h"
10 #include "chrome/common/cloud_print/cloud_print_constants.h"
11 #include "chrome/common/cloud_print/cloud_print_helpers.h"
12 #include "chrome/service/cloud_print/cloud_print_token_store.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"
17 namespace cloud_print {
21 enum CloudPrintAuthEvent {
22 AUTH_EVENT_ROBO_CREATE,
23 AUTH_EVENT_ROBO_SUCCEEDED,
24 AUTH_EVENT_ROBO_FAILED,
25 AUTH_EVENT_ROBO_JSON_ERROR,
26 AUTH_EVENT_ROBO_AUTH_ERROR,
27 AUTH_EVENT_AUTH_WITH_TOKEN,
28 AUTH_EVENT_AUTH_WITH_CODE,
29 AUTH_EVENT_TOKEN_RESPONSE,
30 AUTH_EVENT_REFRESH_REQUEST,
31 AUTH_EVENT_REFRESH_RESPONSE,
32 AUTH_EVENT_AUTH_ERROR,
39 CloudPrintAuth::CloudPrintAuth(
41 const GURL& cloud_print_server_url,
42 const gaia::OAuthClientInfo& oauth_client_info,
43 const std::string& proxy_id)
45 oauth_client_info_(oauth_client_info),
46 cloud_print_server_url_(cloud_print_server_url),
51 void CloudPrintAuth::AuthenticateWithToken(
52 const std::string& cloud_print_token) {
53 VLOG(1) << "CP_AUTH: Authenticating with token";
55 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_ROBO_CREATE,
58 client_login_token_ = cloud_print_token;
60 // We need to get the credentials of the robot here.
61 GURL get_authcode_url = GetUrlForGetAuthCode(cloud_print_server_url_,
62 oauth_client_info_.client_id,
64 request_ = CloudPrintURLFetcher::Create();
65 request_->StartGetRequest(CloudPrintURLFetcher::REQUEST_AUTH_CODE,
66 get_authcode_url, this,
67 kCloudPrintAuthMaxRetryCount, std::string());
70 void CloudPrintAuth::AuthenticateWithRobotToken(
71 const std::string& robot_oauth_refresh_token,
72 const std::string& robot_email) {
73 VLOG(1) << "CP_AUTH: Authenticating with robot token";
75 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_AUTH_WITH_TOKEN,
78 robot_email_ = robot_email;
79 refresh_token_ = robot_oauth_refresh_token;
83 void CloudPrintAuth::AuthenticateWithRobotAuthCode(
84 const std::string& robot_oauth_auth_code,
85 const std::string& robot_email) {
86 VLOG(1) << "CP_AUTH: Authenticating with robot auth code";
88 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_AUTH_WITH_CODE,
91 robot_email_ = robot_email;
92 // Now that we have an auth code we need to get the refresh and access tokens.
93 oauth_client_.reset(new gaia::GaiaOAuthClient(
94 g_service_process->GetServiceURLRequestContextGetter()));
95 oauth_client_->GetTokensFromAuthCode(oauth_client_info_,
96 robot_oauth_auth_code,
97 kCloudPrintAuthMaxRetryCount,
101 void CloudPrintAuth::RefreshAccessToken() {
102 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_REFRESH_REQUEST,
104 oauth_client_.reset(new gaia::GaiaOAuthClient(
105 g_service_process->GetServiceURLRequestContextGetter()));
106 std::vector<std::string> empty_scope_list; // (Use scope from refresh token.)
107 oauth_client_->RefreshToken(oauth_client_info_,
110 kCloudPrintAuthMaxRetryCount,
114 void CloudPrintAuth::OnGetTokensResponse(const std::string& refresh_token,
115 const std::string& access_token,
116 int expires_in_seconds) {
117 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_TOKEN_RESPONSE,
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);
125 void CloudPrintAuth::OnRefreshTokenResponse(const std::string& access_token,
126 int expires_in_seconds) {
127 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_REFRESH_RESPONSE,
129 client_->OnAuthenticationComplete(access_token, refresh_token_,
130 robot_email_, user_email_);
132 // Schedule a task to refresh the access token again when it is about to
134 DCHECK(expires_in_seconds > kTokenRefreshGracePeriodSecs);
135 base::TimeDelta refresh_delay = base::TimeDelta::FromSeconds(
136 expires_in_seconds - kTokenRefreshGracePeriodSecs);
137 base::MessageLoop::current()->PostDelayedTask(
139 base::Bind(&CloudPrintAuth::RefreshAccessToken, this),
143 void CloudPrintAuth::OnOAuthError() {
144 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_AUTH_ERROR,
146 // Notify client about authentication error.
147 client_->OnInvalidCredentials();
150 void CloudPrintAuth::OnNetworkError(int response_code) {
151 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_NET_ERROR,
153 // Since we specify infinite retries on network errors, this should never
156 "OnNetworkError invoked when not expected, response code is " <<
160 CloudPrintURLFetcher::ResponseAction CloudPrintAuth::HandleJSONData(
161 const net::URLFetcher* source,
163 base::DictionaryValue* json_data,
166 VLOG(1) << "CP_AUTH: Creating robot account failed";
167 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent",
168 AUTH_EVENT_ROBO_FAILED,
170 client_->OnInvalidCredentials();
171 return CloudPrintURLFetcher::STOP_PROCESSING;
174 std::string auth_code;
175 if (!json_data->GetString(kOAuthCodeValue, &auth_code)) {
176 VLOG(1) << "CP_AUTH: Creating robot account returned invalid json response";
177 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent",
178 AUTH_EVENT_ROBO_JSON_ERROR,
180 client_->OnInvalidCredentials();
181 return CloudPrintURLFetcher::STOP_PROCESSING;
184 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent",
185 AUTH_EVENT_ROBO_SUCCEEDED,
188 json_data->GetString(kXMPPJidValue, &robot_email_);
189 // Now that we have an auth code we need to get the refresh and access tokens.
190 oauth_client_.reset(new gaia::GaiaOAuthClient(
191 g_service_process->GetServiceURLRequestContextGetter()));
192 oauth_client_->GetTokensFromAuthCode(oauth_client_info_,
194 kCloudPrintAPIMaxRetryCount,
197 return CloudPrintURLFetcher::STOP_PROCESSING;
200 CloudPrintURLFetcher::ResponseAction CloudPrintAuth::OnRequestAuthError() {
201 VLOG(1) << "CP_AUTH: Creating robot account authentication error";
203 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent",
204 AUTH_EVENT_ROBO_AUTH_ERROR,
207 // Notify client about authentication error.
208 client_->OnInvalidCredentials();
209 return CloudPrintURLFetcher::STOP_PROCESSING;
212 std::string CloudPrintAuth::GetAuthHeader() {
213 DCHECK(!client_login_token_.empty());
215 header = "Authorization: GoogleLogin auth=";
216 header += client_login_token_;
220 CloudPrintAuth::~CloudPrintAuth() {}
222 } // namespace cloud_print