• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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_getter.h"
14 #include "chrome/service/service_process.h"
15 #include "google_apis/gaia/gaia_urls.h"
16 
17 namespace cloud_print {
18 
19 namespace {
20 
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,
33   AUTH_EVENT_NET_ERROR,
34   AUTH_EVENT_MAX
35 };
36 
37 }  // namespace
38 
CloudPrintAuth(Client * client,const GURL & cloud_print_server_url,const gaia::OAuthClientInfo & oauth_client_info,const std::string & proxy_id)39 CloudPrintAuth::CloudPrintAuth(
40     Client* client,
41     const GURL& cloud_print_server_url,
42     const gaia::OAuthClientInfo& oauth_client_info,
43     const std::string& proxy_id)
44       : client_(client),
45         oauth_client_info_(oauth_client_info),
46         cloud_print_server_url_(cloud_print_server_url),
47         proxy_id_(proxy_id) {
48   DCHECK(client);
49 }
50 
AuthenticateWithToken(const std::string & cloud_print_token)51 void CloudPrintAuth::AuthenticateWithToken(
52     const std::string& cloud_print_token) {
53   VLOG(1) << "CP_AUTH: Authenticating with token";
54 
55   UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_ROBO_CREATE,
56                             AUTH_EVENT_MAX);
57 
58   client_login_token_ = cloud_print_token;
59 
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,
63                                                proxy_id_);
64   request_ = CloudPrintURLFetcher::Create();
65   request_->StartGetRequest(CloudPrintURLFetcher::REQUEST_AUTH_CODE,
66                             get_authcode_url, this,
67                             kCloudPrintAuthMaxRetryCount, std::string());
68 }
69 
AuthenticateWithRobotToken(const std::string & robot_oauth_refresh_token,const std::string & robot_email)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";
74 
75   UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_AUTH_WITH_TOKEN,
76                             AUTH_EVENT_MAX);
77 
78   robot_email_ = robot_email;
79   refresh_token_ = robot_oauth_refresh_token;
80   RefreshAccessToken();
81 }
82 
AuthenticateWithRobotAuthCode(const std::string & robot_oauth_auth_code,const std::string & robot_email)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";
87 
88   UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_AUTH_WITH_CODE,
89                             AUTH_EVENT_MAX);
90 
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,
98                                        this);
99 }
100 
RefreshAccessToken()101 void CloudPrintAuth::RefreshAccessToken() {
102   UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_REFRESH_REQUEST,
103                             AUTH_EVENT_MAX);
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_,
108                               refresh_token_,
109                               empty_scope_list,
110                               kCloudPrintAuthMaxRetryCount,
111                               this);
112 }
113 
OnGetTokensResponse(const std::string & refresh_token,const std::string & access_token,int expires_in_seconds)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,
118                             AUTH_EVENT_MAX);
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 
OnRefreshTokenResponse(const std::string & access_token,int 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,
128                             AUTH_EVENT_MAX);
129   client_->OnAuthenticationComplete(access_token, refresh_token_,
130                                     robot_email_, user_email_);
131 
132   // Schedule a task to refresh the access token again when it is about to
133   // expire.
134   DCHECK(expires_in_seconds > kTokenRefreshGracePeriodSecs);
135   base::TimeDelta refresh_delay = base::TimeDelta::FromSeconds(
136       expires_in_seconds - kTokenRefreshGracePeriodSecs);
137   base::MessageLoop::current()->PostDelayedTask(
138       FROM_HERE,
139       base::Bind(&CloudPrintAuth::RefreshAccessToken, this),
140       refresh_delay);
141 }
142 
OnOAuthError()143 void CloudPrintAuth::OnOAuthError() {
144   UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_AUTH_ERROR,
145                             AUTH_EVENT_MAX);
146   // Notify client about authentication error.
147   client_->OnInvalidCredentials();
148 }
149 
OnNetworkError(int response_code)150 void CloudPrintAuth::OnNetworkError(int response_code) {
151   UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent", AUTH_EVENT_NET_ERROR,
152                             AUTH_EVENT_MAX);
153   // Since we specify infinite retries on network errors, this should never
154   // be called.
155   NOTREACHED() <<
156       "OnNetworkError invoked when not expected, response code is " <<
157       response_code;
158 }
159 
HandleJSONData(const net::URLFetcher * source,const GURL & url,base::DictionaryValue * json_data,bool succeeded)160 CloudPrintURLFetcher::ResponseAction CloudPrintAuth::HandleJSONData(
161     const net::URLFetcher* source,
162     const GURL& url,
163     base::DictionaryValue* json_data,
164     bool succeeded) {
165   if (!succeeded) {
166     VLOG(1) << "CP_AUTH: Creating robot account failed";
167     UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent",
168                               AUTH_EVENT_ROBO_FAILED,
169                               AUTH_EVENT_MAX);
170     client_->OnInvalidCredentials();
171     return CloudPrintURLFetcher::STOP_PROCESSING;
172   }
173 
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,
179                               AUTH_EVENT_MAX);
180     client_->OnInvalidCredentials();
181     return CloudPrintURLFetcher::STOP_PROCESSING;
182   }
183 
184   UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent",
185                               AUTH_EVENT_ROBO_SUCCEEDED,
186                               AUTH_EVENT_MAX);
187 
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_,
193                                        auth_code,
194                                        kCloudPrintAPIMaxRetryCount,
195                                        this);
196 
197   return CloudPrintURLFetcher::STOP_PROCESSING;
198 }
199 
OnRequestAuthError()200 CloudPrintURLFetcher::ResponseAction CloudPrintAuth::OnRequestAuthError() {
201   VLOG(1) << "CP_AUTH: Creating robot account authentication error";
202 
203   UMA_HISTOGRAM_ENUMERATION("CloudPrint.AuthEvent",
204                             AUTH_EVENT_ROBO_AUTH_ERROR,
205                             AUTH_EVENT_MAX);
206 
207   // Notify client about authentication error.
208   client_->OnInvalidCredentials();
209   return CloudPrintURLFetcher::STOP_PROCESSING;
210 }
211 
GetAuthHeader()212 std::string CloudPrintAuth::GetAuthHeader() {
213   DCHECK(!client_login_token_.empty());
214   std::string header;
215   header = "Authorization: GoogleLogin auth=";
216   header += client_login_token_;
217   return header;
218 }
219 
~CloudPrintAuth()220 CloudPrintAuth::~CloudPrintAuth() {}
221 
222 }  // namespace cloud_print
223