Home | History | Annotate | Download | only in cloud_print
      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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    220 CloudPrintAuth::~CloudPrintAuth() {}
    221 
    222 }  // namespace cloud_print
    223