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/location.h"
9 #include "base/metrics/histogram.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/strings/string_util.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "chrome/common/cloud_print/cloud_print_constants.h"
14 #include "chrome/common/cloud_print/cloud_print_helpers.h"
15 #include "chrome/service/cloud_print/cloud_print_token_store.h"
16 #include "chrome/service/net/service_url_request_context_getter.h"
17 #include "chrome/service/service_process.h"
18 #include "google_apis/gaia/gaia_urls.h"
20 namespace cloud_print
{
24 enum CloudPrintAuthEvent
{
25 AUTH_EVENT_ROBO_CREATE
,
26 AUTH_EVENT_ROBO_SUCCEEDED
,
27 AUTH_EVENT_ROBO_FAILED
,
28 AUTH_EVENT_ROBO_JSON_ERROR
,
29 AUTH_EVENT_ROBO_AUTH_ERROR
,
30 AUTH_EVENT_AUTH_WITH_TOKEN
,
31 AUTH_EVENT_AUTH_WITH_CODE
,
32 AUTH_EVENT_TOKEN_RESPONSE
,
33 AUTH_EVENT_REFRESH_REQUEST
,
34 AUTH_EVENT_REFRESH_RESPONSE
,
35 AUTH_EVENT_AUTH_ERROR
,
42 CloudPrintAuth::CloudPrintAuth(
44 const GURL
& cloud_print_server_url
,
45 const gaia::OAuthClientInfo
& oauth_client_info
,
46 const std::string
& proxy_id
)
48 oauth_client_info_(oauth_client_info
),
49 cloud_print_server_url_(cloud_print_server_url
),
54 void CloudPrintAuth::AuthenticateWithToken(
55 const std::string
& cloud_print_token
) {
56 VLOG(1) << "CP_AUTH: Authenticating with token";
58 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_ROBO_CREATE
,
61 client_login_token_
= cloud_print_token
;
63 // We need to get the credentials of the robot here.
64 GURL get_authcode_url
= GetUrlForGetAuthCode(cloud_print_server_url_
,
65 oauth_client_info_
.client_id
,
67 request_
= CloudPrintURLFetcher::Create();
68 request_
->StartGetRequest(CloudPrintURLFetcher::REQUEST_AUTH_CODE
,
69 get_authcode_url
, this,
70 kCloudPrintAuthMaxRetryCount
, std::string());
73 void CloudPrintAuth::AuthenticateWithRobotToken(
74 const std::string
& robot_oauth_refresh_token
,
75 const std::string
& robot_email
) {
76 VLOG(1) << "CP_AUTH: Authenticating with robot token";
78 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_AUTH_WITH_TOKEN
,
81 robot_email_
= robot_email
;
82 refresh_token_
= robot_oauth_refresh_token
;
86 void CloudPrintAuth::AuthenticateWithRobotAuthCode(
87 const std::string
& robot_oauth_auth_code
,
88 const std::string
& robot_email
) {
89 VLOG(1) << "CP_AUTH: Authenticating with robot auth code";
91 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_AUTH_WITH_CODE
,
94 robot_email_
= robot_email
;
95 // Now that we have an auth code we need to get the refresh and access tokens.
96 oauth_client_
.reset(new gaia::GaiaOAuthClient(
97 g_service_process
->GetServiceURLRequestContextGetter()));
98 oauth_client_
->GetTokensFromAuthCode(oauth_client_info_
,
99 robot_oauth_auth_code
,
100 kCloudPrintAuthMaxRetryCount
,
104 void CloudPrintAuth::RefreshAccessToken() {
105 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_REFRESH_REQUEST
,
107 oauth_client_
.reset(new gaia::GaiaOAuthClient(
108 g_service_process
->GetServiceURLRequestContextGetter()));
109 std::vector
<std::string
> empty_scope_list
; // (Use scope from refresh token.)
110 oauth_client_
->RefreshToken(oauth_client_info_
,
113 kCloudPrintAuthMaxRetryCount
,
117 void CloudPrintAuth::OnGetTokensResponse(const std::string
& refresh_token
,
118 const std::string
& access_token
,
119 int expires_in_seconds
) {
120 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_TOKEN_RESPONSE
,
122 refresh_token_
= refresh_token
;
123 // After saving the refresh token, this is just like having just refreshed
124 // the access token. Just call OnRefreshTokenResponse.
125 OnRefreshTokenResponse(access_token
, expires_in_seconds
);
128 void CloudPrintAuth::OnRefreshTokenResponse(const std::string
& access_token
,
129 int expires_in_seconds
) {
130 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_REFRESH_RESPONSE
,
132 client_
->OnAuthenticationComplete(access_token
, refresh_token_
,
133 robot_email_
, user_email_
);
135 // Schedule a task to refresh the access token again when it is about to
137 DCHECK(expires_in_seconds
> kTokenRefreshGracePeriodSecs
);
138 base::TimeDelta refresh_delay
= base::TimeDelta::FromSeconds(
139 expires_in_seconds
- kTokenRefreshGracePeriodSecs
);
140 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
141 FROM_HERE
, base::Bind(&CloudPrintAuth::RefreshAccessToken
, this),
145 void CloudPrintAuth::OnOAuthError() {
146 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_AUTH_ERROR
,
148 // Notify client about authentication error.
149 client_
->OnInvalidCredentials();
152 void CloudPrintAuth::OnNetworkError(int response_code
) {
153 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_NET_ERROR
,
155 // Since we specify infinite retries on network errors, this should never
158 "OnNetworkError invoked when not expected, response code is " <<
162 CloudPrintURLFetcher::ResponseAction
CloudPrintAuth::HandleJSONData(
163 const net::URLFetcher
* source
,
165 base::DictionaryValue
* json_data
,
168 VLOG(1) << "CP_AUTH: Creating robot account failed";
169 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent",
170 AUTH_EVENT_ROBO_FAILED
,
172 client_
->OnInvalidCredentials();
173 return CloudPrintURLFetcher::STOP_PROCESSING
;
176 std::string auth_code
;
177 if (!json_data
->GetString(kOAuthCodeValue
, &auth_code
)) {
178 VLOG(1) << "CP_AUTH: Creating robot account returned invalid json response";
179 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent",
180 AUTH_EVENT_ROBO_JSON_ERROR
,
182 client_
->OnInvalidCredentials();
183 return CloudPrintURLFetcher::STOP_PROCESSING
;
186 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent",
187 AUTH_EVENT_ROBO_SUCCEEDED
,
190 json_data
->GetString(kXMPPJidValue
, &robot_email_
);
191 // Now that we have an auth code we need to get the refresh and access tokens.
192 oauth_client_
.reset(new gaia::GaiaOAuthClient(
193 g_service_process
->GetServiceURLRequestContextGetter()));
194 oauth_client_
->GetTokensFromAuthCode(oauth_client_info_
,
196 kCloudPrintAPIMaxRetryCount
,
199 return CloudPrintURLFetcher::STOP_PROCESSING
;
202 CloudPrintURLFetcher::ResponseAction
CloudPrintAuth::OnRequestAuthError() {
203 VLOG(1) << "CP_AUTH: Creating robot account authentication error";
205 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent",
206 AUTH_EVENT_ROBO_AUTH_ERROR
,
209 // Notify client about authentication error.
210 client_
->OnInvalidCredentials();
211 return CloudPrintURLFetcher::STOP_PROCESSING
;
214 std::string
CloudPrintAuth::GetAuthHeader() {
215 DCHECK(!client_login_token_
.empty());
217 header
= "Authorization: GoogleLogin auth=";
218 header
+= client_login_token_
;
222 CloudPrintAuth::~CloudPrintAuth() {}
224 } // namespace cloud_print