Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / service / cloud_print / cloud_print_auth.cc
blob663aca79d2993accb18006b4ef3a647b403dd8da
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"
7 #include "base/bind.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 {
22 namespace {
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,
36 AUTH_EVENT_NET_ERROR,
37 AUTH_EVENT_MAX
40 } // namespace
42 CloudPrintAuth::CloudPrintAuth(
43 Client* client,
44 const GURL& cloud_print_server_url,
45 const gaia::OAuthClientInfo& oauth_client_info,
46 const std::string& proxy_id)
47 : client_(client),
48 oauth_client_info_(oauth_client_info),
49 cloud_print_server_url_(cloud_print_server_url),
50 proxy_id_(proxy_id) {
51 DCHECK(client);
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,
59 AUTH_EVENT_MAX);
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,
66 proxy_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,
79 AUTH_EVENT_MAX);
81 robot_email_ = robot_email;
82 refresh_token_ = robot_oauth_refresh_token;
83 RefreshAccessToken();
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,
92 AUTH_EVENT_MAX);
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,
101 this);
104 void CloudPrintAuth::RefreshAccessToken() {
105 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_REFRESH_REQUEST,
106 AUTH_EVENT_MAX);
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_,
111 refresh_token_,
112 empty_scope_list,
113 kCloudPrintAuthMaxRetryCount,
114 this);
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,
121 AUTH_EVENT_MAX);
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,
131 AUTH_EVENT_MAX);
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
136 // expire.
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),
142 refresh_delay);
145 void CloudPrintAuth::OnOAuthError() {
146 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_AUTH_ERROR,
147 AUTH_EVENT_MAX);
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,
154 AUTH_EVENT_MAX);
155 // Since we specify infinite retries on network errors, this should never
156 // be called.
157 NOTREACHED() <<
158 "OnNetworkError invoked when not expected, response code is " <<
159 response_code;
162 CloudPrintURLFetcher::ResponseAction CloudPrintAuth::HandleJSONData(
163 const net::URLFetcher* source,
164 const GURL& url,
165 base::DictionaryValue* json_data,
166 bool succeeded) {
167 if (!succeeded) {
168 VLOG(1) << "CP_AUTH: Creating robot account failed";
169 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent",
170 AUTH_EVENT_ROBO_FAILED,
171 AUTH_EVENT_MAX);
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,
181 AUTH_EVENT_MAX);
182 client_->OnInvalidCredentials();
183 return CloudPrintURLFetcher::STOP_PROCESSING;
186 UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent",
187 AUTH_EVENT_ROBO_SUCCEEDED,
188 AUTH_EVENT_MAX);
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_,
195 auth_code,
196 kCloudPrintAPIMaxRetryCount,
197 this);
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,
207 AUTH_EVENT_MAX);
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());
216 std::string header;
217 header = "Authorization: GoogleLogin auth=";
218 header += client_login_token_;
219 return header;
222 CloudPrintAuth::~CloudPrintAuth() {}
224 } // namespace cloud_print