diff options
author | sanjeevr@chromium.org <sanjeevr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-06 23:22:21 +0000 |
---|---|---|
committer | sanjeevr@chromium.org <sanjeevr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-06 23:22:21 +0000 |
commit | bb0733862079a1bdca18bedfbd5a17dc1ce700db (patch) | |
tree | d83668c995c5b11e1a6c7125eedc544b3bbed35f /chrome/service | |
parent | fa9c732ee03201e331df4c2d04f21740ec09f565 (diff) | |
download | chromium_src-bb0733862079a1bdca18bedfbd5a17dc1ce700db.zip chromium_src-bb0733862079a1bdca18bedfbd5a17dc1ce700db.tar.gz chromium_src-bb0733862079a1bdca18bedfbd5a17dc1ce700db.tar.bz2 |
Changed the cloud print connector logic to request the OAuth2 credentials of a robot account and use those credentials for all cloud print and Talk authentication. The OAuth2 tokens are also periodically refreshed.
BUG=None
TEST=Unit-tests, Cloud Print connector.
R=scottbyer@chromium.org
Review URL: http://codereview.chromium.org/6705013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@84525 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/service')
21 files changed, 580 insertions, 176 deletions
diff --git a/chrome/service/cloud_print/cloud_print_consts.cc b/chrome/service/cloud_print/cloud_print_consts.cc index 4481384..e53e411 100644 --- a/chrome/service/cloud_print/cloud_print_consts.cc +++ b/chrome/service/cloud_print/cloud_print_consts.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -27,6 +27,9 @@ const char kJobListValue[] = "jobs"; const char kTitleValue[] = "title"; const char kPrinterCapsHashValue[] = "capsHash"; const char kTagsValue[] = "tags"; +const char kXMPPJidValue[] = "xmpp_jid"; +const char kOAuthCodeValue[] = "authorization_code"; + const char kProxyTagPrefix[] = "__cp__"; const char kTagsHashTagName[] = "__cp__tagshash"; const char kTagDryRunFlag[] = "__cp__dry_run"; @@ -58,3 +61,8 @@ const char kJobFetchReasonQueryMore[] = "querymore"; const char kPrintSystemFailedMessageId[] = "printsystemfail"; const char kGetPrinterCapsFailedMessageId[] = "getprncapsfail"; const char kEnumPrintersFailedMessageId[] = "enumfail"; + +const char kDefaultCloudPrintOAuthClientId[] = + "551556820943.apps.googleusercontent.com"; +const char kDefaultCloudPrintOAuthClientSecret[] = "u3/mp8CgLFxh4uiX1855/MHe"; + diff --git a/chrome/service/cloud_print/cloud_print_consts.h b/chrome/service/cloud_print/cloud_print_consts.h index 160f20f..bf8ca55 100644 --- a/chrome/service/cloud_print/cloud_print_consts.h +++ b/chrome/service/cloud_print/cloud_print_consts.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -29,6 +29,9 @@ extern const char kJobListValue[]; extern const char kTitleValue[]; extern const char kPrinterCapsHashValue[]; extern const char kTagsValue[]; +extern const char kXMPPJidValue[]; +extern const char kOAuthCodeValue[]; + extern const char kProxyTagPrefix[]; extern const char kTagsHashTagName[]; extern const char kTagDryRunFlag[]; @@ -46,6 +49,9 @@ extern const char kJobFetchReasonQueryMore[]; extern const char kPrintSystemFailedMessageId[]; extern const char kGetPrinterCapsFailedMessageId[]; extern const char kEnumPrintersFailedMessageId[]; +extern const char kDefaultCloudPrintOAuthClientId[]; +extern const char kDefaultCloudPrintOAuthClientSecret[]; + // Max retry count for job data fetch requests. const int kJobDataMaxRetryCount = 5; @@ -57,5 +63,9 @@ const int kCloudPrintAPIMaxRetryCount = -1; const int kMinJobPollIntervalSecs = 5*60; // 5 minutes in seconds const int kMaxJobPollIntervalSecs = 8*60; // 8 minutes in seconds +// The number of seconds before the OAuth2 access token is due to expire that +// we try and refresh it. +const int kTokenRefreshGracePeriodSecs = 5*60; // 5 minutes in seconds + #endif // CHROME_SERVICE_CLOUD_PRINT_CLOUD_PRINT_CONSTS_H_ diff --git a/chrome/service/cloud_print/cloud_print_helpers.cc b/chrome/service/cloud_print/cloud_print_helpers.cc index 1b253cf..7fb9ddd 100644 --- a/chrome/service/cloud_print/cloud_print_helpers.cc +++ b/chrome/service/cloud_print/cloud_print_helpers.cc @@ -147,6 +147,22 @@ GURL CloudPrintHelpers::GetUrlForUserMessage(const GURL& cloud_print_server_url, return cloud_print_server_url.ReplaceComponents(replacements); } +GURL CloudPrintHelpers::GetUrlForGetAuthCode(const GURL& cloud_print_server_url, + const std::string& oauth_client_id, + const std::string& proxy_id) { + // We use the internal API "createrobot" instead of "getauthcode". This API + // will add the robot as owner to all the existing printers for this user. + std::string path(AppendPathToUrl(cloud_print_server_url, "createrobot")); + GURL::Replacements replacements; + replacements.SetPathStr(path); + std::string query = StringPrintf("oauth_client_id=%s&proxy=%s", + oauth_client_id.c_str(), + proxy_id.c_str()); + replacements.SetQueryStr(query); + return cloud_print_server_url.ReplaceComponents(replacements); +} + + bool CloudPrintHelpers::ParseResponseJSON( const std::string& response_data, bool* succeeded, DictionaryValue** response_dict) { diff --git a/chrome/service/cloud_print/cloud_print_helpers.h b/chrome/service/cloud_print/cloud_print_helpers.h index 7ee1ded..6f2034f 100644 --- a/chrome/service/cloud_print/cloud_print_helpers.h +++ b/chrome/service/cloud_print/cloud_print_helpers.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -37,6 +37,10 @@ class CloudPrintHelpers { const cloud_print::PrintJobDetails& details); static GURL GetUrlForUserMessage(const GURL& cloud_print_server_url, const std::string& message_id); + static GURL GetUrlForGetAuthCode(const GURL& cloud_print_server_url, + const std::string& oauth_client_id, + const std::string& proxy_id); + // Parses the response data for any cloud print server request. The method // returns false if there was an error in parsing the JSON. The succeeded diff --git a/chrome/service/cloud_print/cloud_print_helpers_unittest.cc b/chrome/service/cloud_print/cloud_print_helpers_unittest.cc index c60a0c3..cb1999a 100644 --- a/chrome/service/cloud_print/cloud_print_helpers_unittest.cc +++ b/chrome/service/cloud_print/cloud_print_helpers_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -79,6 +79,15 @@ void CheckURLs(const GURL& server_base_url) { expected_url = StringPrintf("%suser/message?code=blahmessageid", expected_url_base.c_str()); EXPECT_EQ(expected_url, url.spec()); + + url = CloudPrintHelpers::GetUrlForGetAuthCode( + server_base_url, + "fooclientid.apps.googleusercontent.com", + "test_proxy"); + expected_url = StringPrintf( + "%screaterobot?oauth_client_id=fooclientid.apps.googleusercontent.com&" + "proxy=test_proxy", expected_url_base.c_str()); + EXPECT_EQ(expected_url, url.spec()); } } // namespace diff --git a/chrome/service/cloud_print/cloud_print_proxy.cc b/chrome/service/cloud_print/cloud_print_proxy.cc index 7a5759b..8a99596 100644 --- a/chrome/service/cloud_print/cloud_print_proxy.cc +++ b/chrome/service/cloud_print/cloud_print_proxy.cc @@ -9,6 +9,7 @@ #include "base/process_util.h" #include "base/values.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/net/gaia/gaia_oauth_client.h" #include "chrome/common/pref_names.h" #include "chrome/service/cloud_print/cloud_print_consts.h" #include "chrome/service/cloud_print/print_system.h" @@ -41,7 +42,8 @@ static void ShowTokenExpiredNotificationInBrowser() { CloudPrintProxy::CloudPrintProxy() : service_prefs_(NULL), - client_(NULL) { + client_(NULL), + enabled_(false) { } CloudPrintProxy::~CloudPrintProxy() { @@ -81,6 +83,7 @@ void CloudPrintProxy::EnableForUser(const std::string& lsid) { if (cloud_print_server_url_str.empty()) { cloud_print_server_url_str = kDefaultCloudPrintServerUrl; } + service_prefs_->GetString(prefs::kCloudPrintEmail, &user_email_); // By default we don't poll for jobs when we lose XMPP connection. But this // behavior can be overridden by a preference. @@ -88,29 +91,49 @@ void CloudPrintProxy::EnableForUser(const std::string& lsid) { service_prefs_->GetBoolean(prefs::kCloudPrintEnableJobPoll, &enable_job_poll); + // TODO(sanjeevr): Allow overriding OAuthClientInfo in prefs. + gaia::OAuthClientInfo oauth_client_info; + oauth_client_info.client_id = kDefaultCloudPrintOAuthClientId; + oauth_client_info.client_secret = kDefaultCloudPrintOAuthClientSecret; + GURL cloud_print_server_url(cloud_print_server_url_str.c_str()); DCHECK(cloud_print_server_url.is_valid()); backend_.reset(new CloudPrintProxyBackend(this, cloud_print_server_url, print_system_settings, + oauth_client_info, enable_job_poll)); + // Read persisted robot credentials because we may decide to reuse it if the + // passed in LSID belongs the same user. + std::string robot_refresh_token; + service_prefs_->GetString(prefs::kCloudPrintRobotRefreshToken, + &robot_refresh_token); + std::string robot_email; + service_prefs_->GetString(prefs::kCloudPrintRobotEmail, + &robot_email); + // If we have been passed in an LSID, we want to use this to authenticate. // Else we will try and retrieve the last used auth tokens from prefs. if (!lsid.empty()) { - backend_->InitializeWithLsid(lsid, proxy_id); + backend_->InitializeWithLsid(lsid, + proxy_id, + robot_refresh_token, + robot_email, + user_email_); } else { - std::string cloud_print_token; - service_prefs_->GetString(prefs::kCloudPrintAuthToken, - &cloud_print_token); - DCHECK(!cloud_print_token.empty()); - std::string cloud_print_xmpp_token; - service_prefs_->GetString(prefs::kCloudPrintXMPPAuthToken, - &cloud_print_xmpp_token); - DCHECK(!cloud_print_xmpp_token.empty()); - service_prefs_->GetString(prefs::kCloudPrintEmail, - &cloud_print_email_); - DCHECK(!cloud_print_email_.empty()); - backend_->InitializeWithToken(cloud_print_token, cloud_print_xmpp_token, - cloud_print_email_, proxy_id); + // See if we have persisted robot credentials. + if (!robot_refresh_token.empty()) { + DCHECK(!robot_email.empty()); + backend_->InitializeWithRobotToken(robot_refresh_token, + robot_email, + proxy_id); + } else { + // Finally see if we have persisted user credentials (legacy case). + std::string cloud_print_token; + service_prefs_->GetString(prefs::kCloudPrintAuthToken, + &cloud_print_token); + DCHECK(!cloud_print_token.empty()); + backend_->InitializeWithToken(cloud_print_token, proxy_id); + } } if (client_) { client_->OnCloudPrintProxyEnabled(true); @@ -119,7 +142,8 @@ void CloudPrintProxy::EnableForUser(const std::string& lsid) { void CloudPrintProxy::DisableForUser() { DCHECK(CalledOnValidThread()); - cloud_print_email_.clear(); + user_email_.clear(); + enabled_ = false; Shutdown(); if (client_) { client_->OnCloudPrintProxyDisabled(true); @@ -127,11 +151,10 @@ void CloudPrintProxy::DisableForUser() { } bool CloudPrintProxy::IsEnabled(std::string* email) const { - bool enabled = !cloud_print_email().empty(); - if (enabled && email) { - *email = cloud_print_email(); + if (enabled_ && email) { + *email = user_email(); } - return enabled; + return enabled_; } // Notification methods from the backend. Called on UI thread. @@ -144,17 +167,21 @@ void CloudPrintProxy::OnPrinterListAvailable( } void CloudPrintProxy::OnAuthenticated( - const std::string& cloud_print_token, - const std::string& cloud_print_xmpp_token, - const std::string& email) { + const std::string& robot_oauth_refresh_token, + const std::string& robot_email, + const std::string& user_email) { DCHECK(CalledOnValidThread()); - cloud_print_email_ = email; - service_prefs_->SetString(prefs::kCloudPrintAuthToken, - cloud_print_token); - service_prefs_->SetString(prefs::kCloudPrintXMPPAuthToken, - cloud_print_xmpp_token); - service_prefs_->SetString(prefs::kCloudPrintEmail, - email); + service_prefs_->SetString(prefs::kCloudPrintRobotRefreshToken, + robot_oauth_refresh_token); + service_prefs_->SetString(prefs::kCloudPrintRobotEmail, + robot_email); + // If authenticating from a robot, the user email will be empty. + if (!user_email.empty()) { + user_email_ = user_email; + service_prefs_->SetString(prefs::kCloudPrintEmail, user_email); + } + enabled_ = true; + DCHECK(!user_email_.empty()); service_prefs_->WritePrefs(); } @@ -162,6 +189,12 @@ void CloudPrintProxy::OnAuthenticationFailed() { DCHECK(CalledOnValidThread()); // If authenticated failed, we will disable the cloud print proxy. DisableForUser(); + // Also delete the cached robot credentials since they may not be valid any + // longer. + service_prefs_->RemovePref(prefs::kCloudPrintRobotRefreshToken); + service_prefs_->RemovePref(prefs::kCloudPrintRobotEmail); + service_prefs_->WritePrefs(); + // Launch the browser to display a notification that the credentials have // expired (unless error dialogs are disabled). if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoErrorDialogs)) diff --git a/chrome/service/cloud_print/cloud_print_proxy.h b/chrome/service/cloud_print/cloud_print_proxy.h index 3727c55..2ff6dfb 100644 --- a/chrome/service/cloud_print/cloud_print_proxy.h +++ b/chrome/service/cloud_print/cloud_print_proxy.h @@ -40,16 +40,16 @@ class CloudPrintProxy : public CloudPrintProxyFrontend, // for authentication is also returned in the optional |email| argument. bool IsEnabled(std::string* email) const; - const std::string& cloud_print_email() const { - return cloud_print_email_; + const std::string& user_email() const { + return user_email_; } // CloudPrintProxyFrontend implementation. Called on UI thread. virtual void OnPrinterListAvailable( const printing::PrinterList& printer_list); - virtual void OnAuthenticated(const std::string& cloud_print_token, - const std::string& cloud_print_xmpp_token, - const std::string& email); + virtual void OnAuthenticated(const std::string& robot_oauth_refresh_token, + const std::string& robot_email, + const std::string& user_email); virtual void OnAuthenticationFailed(); virtual void OnPrintSystemUnavailable(); @@ -67,7 +67,10 @@ class CloudPrintProxy : public CloudPrintProxyFrontend, Client* client_; // The email address of the account used to authenticate to the Cloud Print // service. - std::string cloud_print_email_; + std::string user_email_; + // This is set to true when the Cloud Print proxy is enabled and after + // successful authentication with the Cloud Print service. + bool enabled_; DISALLOW_COPY_AND_ASSIGN(CloudPrintProxy); }; diff --git a/chrome/service/cloud_print/cloud_print_proxy_backend.cc b/chrome/service/cloud_print/cloud_print_proxy_backend.cc index 6681b12..490c30c 100644 --- a/chrome/service/cloud_print/cloud_print_proxy_backend.cc +++ b/chrome/service/cloud_print/cloud_print_proxy_backend.cc @@ -15,8 +15,10 @@ #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "base/values.h" +#include "chrome/common/net/gaia/gaia_oauth_client.h" #include "chrome/service/cloud_print/cloud_print_consts.h" #include "chrome/service/cloud_print/cloud_print_helpers.h" +#include "chrome/service/cloud_print/cloud_print_token_store.h" #include "chrome/service/cloud_print/cloud_print_url_fetcher.h" #include "chrome/service/cloud_print/printer_job_handler.h" #include "chrome/service/gaia/service_gaia_authenticator.h" @@ -36,13 +38,15 @@ class CloudPrintProxyBackend::Core public CloudPrintURLFetcherDelegate, public cloud_print::PrintServerWatcherDelegate, public PrinterJobHandlerDelegate, - public notifier::TalkMediator::Delegate { + public notifier::TalkMediator::Delegate, + public gaia::GaiaOAuthClient::Delegate { public: // It is OK for print_server_url to be empty. In this case system should // use system default (local) print server. explicit Core(CloudPrintProxyBackend* backend, const GURL& cloud_print_server_url, const DictionaryValue* print_system_settings, + const gaia::OAuthClientInfo& oauth_client_info, bool enable_job_poll); // Note: @@ -55,11 +59,16 @@ class CloudPrintProxyBackend::Core // initialization. When we are passed in an LSID we authenticate using that // and retrieve new auth tokens. void DoInitializeWithLsid(const std::string& lsid, - const std::string& proxy_id); + const std::string& proxy_id, + const std::string& last_robot_refresh_token, + const std::string& last_robot_email, + const std::string& last_user_email); + void DoInitializeWithToken(const std::string cloud_print_token, - const std::string cloud_print_xmpp_token, - const std::string email, const std::string& proxy_id); + void DoInitializeWithRobotToken(const std::string& robot_oauth_refresh_token, + const std::string& robot_email, + const std::string& proxy_id); // Called on the CloudPrintProxyBackend core_thread_ to perform // shutdown. @@ -92,6 +101,15 @@ class CloudPrintProxyBackend::Core const notifier::Notification& notification); virtual void OnOutgoingNotification(); + // gaia::GaiaOAuthClient::Delegate implementation. + virtual void OnGetTokensResponse(const std::string& refresh_token, + const std::string& access_token, + int expires_in_seconds); + virtual void OnRefreshTokenResponse(const std::string& access_token, + int expires_in_seconds); + virtual void OnOAuthError(); + virtual void OnNetworkError(int response_code); + private: // Prototype for a response handler. typedef CloudPrintURLFetcher::ResponseAction @@ -130,6 +148,13 @@ class CloudPrintProxyBackend::Core const GURL& url, DictionaryValue* json_data, bool succeeded); + + CloudPrintURLFetcher::ResponseAction HandleGetAuthCodeResponse( + const URLFetcher* source, + const GURL& url, + DictionaryValue* json_data, + bool succeeded); + // End response handlers // NotifyXXX is how the Core communicates with the frontend across @@ -137,12 +162,14 @@ class CloudPrintProxyBackend::Core void NotifyPrinterListAvailable( const printing::PrinterList& printer_list); void NotifyAuthenticated( - const std::string& cloud_print_token, - const std::string& cloud_print_xmpp_token, - const std::string& email); + const std::string& robot_oauth_refresh_token, + const std::string& robot_email, + const std::string& user_email); void NotifyAuthenticationFailed(); void NotifyPrintSystemUnavailable(); + // Once we have robot credentials, this method gets the ball rolling. + void PostAuthInitialization(); // Starts a new printer registration process. void StartRegistration(); // Ends the printer registration process. @@ -164,6 +191,8 @@ class CloudPrintProxyBackend::Core void ReportUserMessage(const std::string& message_id, const std::string& failure_message, ResponseHandler handler); + // Make a GAIA request to refresh the access token. + void RefreshAccessToken(); // Callback method for GetPrinterCapsAndDefaults. void OnReceivePrinterCaps( @@ -176,11 +205,13 @@ class CloudPrintProxyBackend::Core // Schedules a task to poll for jobs. Does nothing if a task is already // scheduled. void ScheduleJobPoll(); + CloudPrintTokenStore* GetTokenStore(); // Our parent CloudPrintProxyBackend CloudPrintProxyBackend* backend_; GURL cloud_print_server_url_; + gaia::OAuthClientInfo oauth_client_info_; scoped_ptr<DictionaryValue> print_system_settings_; // Pointer to current print system. scoped_refptr<cloud_print::PrintSystem> print_system_; @@ -201,8 +232,14 @@ class CloudPrintProxyBackend::Core size_t next_upload_index_; // The unique id for this proxy std::string proxy_id_; - // The GAIA auth token - std::string auth_token_; + // The OAuth2 refresh token for the robot. + std::string refresh_token_; + // The email address of the user. This is only used during initial + // authentication with an LSID. This is only used for storing in prefs for + // display purposes. + std::string user_email_; + // The email address of the robot account. + std::string robot_email_; // Cached info about the last printer that we tried to upload. We cache this // so we won't have to requery the printer if the upload fails and we need // to retry. @@ -231,6 +268,8 @@ class CloudPrintProxyBackend::Core // The channel we are interested in receiving push notifications for. // This is "cloudprint.google.com/proxy/<proxy_id>" std::string push_notifications_channel_; + scoped_ptr<gaia::GaiaOAuthClient> oauth_client_; + scoped_ptr<CloudPrintTokenStore> token_store_; DISALLOW_COPY_AND_ASSIGN(Core); }; @@ -239,6 +278,7 @@ CloudPrintProxyBackend::CloudPrintProxyBackend( CloudPrintProxyFrontend* frontend, const GURL& cloud_print_server_url, const DictionaryValue* print_system_settings, + const gaia::OAuthClientInfo& oauth_client_info, bool enable_job_poll) : core_thread_("Chrome_CloudPrintProxyCoreThread"), frontend_loop_(MessageLoop::current()), @@ -247,6 +287,7 @@ CloudPrintProxyBackend::CloudPrintProxyBackend( core_ = new Core(this, cloud_print_server_url, print_system_settings, + oauth_client_info, enable_job_poll); } @@ -254,31 +295,55 @@ CloudPrintProxyBackend::~CloudPrintProxyBackend() { DCHECK(!core_); } -bool CloudPrintProxyBackend::InitializeWithLsid(const std::string& lsid, - const std::string& proxy_id) { +bool CloudPrintProxyBackend::InitializeWithLsid( + const std::string& lsid, + const std::string& proxy_id, + const std::string& last_robot_refresh_token, + const std::string& last_robot_email, + const std::string& last_user_email) { if (!core_thread_.Start()) return false; core_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - core_.get(), &CloudPrintProxyBackend::Core::DoInitializeWithLsid, lsid, - proxy_id)); + core_.get(), + &CloudPrintProxyBackend::Core::DoInitializeWithLsid, + lsid, + proxy_id, + last_robot_refresh_token, + last_robot_email, + last_user_email)); return true; } bool CloudPrintProxyBackend::InitializeWithToken( const std::string& cloud_print_token, - const std::string& cloud_print_xmpp_token, - const std::string& email, const std::string& proxy_id) { if (!core_thread_.Start()) return false; core_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( core_.get(), &CloudPrintProxyBackend::Core::DoInitializeWithToken, - cloud_print_token, cloud_print_xmpp_token, email, proxy_id)); + cloud_print_token, proxy_id)); return true; } +bool CloudPrintProxyBackend::InitializeWithRobotToken( + const std::string& robot_oauth_refresh_token, + const std::string& robot_email, + const std::string& proxy_id) { + if (!core_thread_.Start()) + return false; + core_thread_.message_loop()->PostTask(FROM_HERE, + NewRunnableMethod( + core_.get(), + &CloudPrintProxyBackend::Core::DoInitializeWithRobotToken, + robot_oauth_refresh_token, + robot_email, + proxy_id)); + return true; +} + + void CloudPrintProxyBackend::Shutdown() { core_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(core_.get(), @@ -296,20 +361,23 @@ void CloudPrintProxyBackend::RegisterPrinters( printer_list)); } -CloudPrintProxyBackend::Core::Core(CloudPrintProxyBackend* backend, - const GURL& cloud_print_server_url, - const DictionaryValue* print_system_settings, - bool enable_job_poll) - : backend_(backend), - cloud_print_server_url_(cloud_print_server_url), - complete_list_available_(false), - next_upload_index_(0), - next_response_handler_(NULL), - new_printers_available_(false), - registration_in_progress_(false), - notifications_enabled_(false), - job_poll_scheduled_(false), - enable_job_poll_(enable_job_poll) { +CloudPrintProxyBackend::Core::Core( + CloudPrintProxyBackend* backend, + const GURL& cloud_print_server_url, + const DictionaryValue* print_system_settings, + const gaia::OAuthClientInfo& oauth_client_info, + bool enable_job_poll) + : backend_(backend), + cloud_print_server_url_(cloud_print_server_url), + oauth_client_info_(oauth_client_info), + complete_list_available_(false), + next_upload_index_(0), + next_response_handler_(NULL), + new_printers_available_(false), + registration_in_progress_(false), + notifications_enabled_(false), + job_poll_scheduled_(false), + enable_job_poll_(enable_job_poll) { if (print_system_settings) { // It is possible to have no print settings specified. print_system_settings_.reset(print_system_settings->DeepCopy()); @@ -317,93 +385,109 @@ CloudPrintProxyBackend::Core::Core(CloudPrintProxyBackend* backend, } void CloudPrintProxyBackend::Core::DoInitializeWithLsid( - const std::string& lsid, const std::string& proxy_id) { + const std::string& lsid, + const std::string& proxy_id, + const std::string& last_robot_refresh_token, + const std::string& last_robot_email, + const std::string& last_user_email) { DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); - // Since Talk does not accept a Cloud Print token, for now, we make 2 auth - // requests, one for the chromiumsync service and another for print. This is - // temporary and should be removed once Talk supports our token. // Note: The GAIA login is synchronous but that should be OK because we are in // the CloudPrintProxyCoreThread and we cannot really do anything else until // the GAIA signin is successful. std::string user_agent = "ChromiumBrowser"; - scoped_refptr<ServiceGaiaAuthenticator> gaia_auth_for_talk( + scoped_refptr<ServiceGaiaAuthenticator> gaia_auth_for_print( new ServiceGaiaAuthenticator( - user_agent, kSyncGaiaServiceId, kGaiaUrl, + user_agent, kCloudPrintGaiaServiceId, kGaiaUrl, g_service_process->io_thread()->message_loop_proxy())); - gaia_auth_for_talk->set_message_loop(MessageLoop::current()); - bool auth_succeeded = false; - if (gaia_auth_for_talk->AuthenticateWithLsid(lsid)) { - scoped_refptr<ServiceGaiaAuthenticator> gaia_auth_for_print( - new ServiceGaiaAuthenticator( - user_agent, kCloudPrintGaiaServiceId, kGaiaUrl, - g_service_process->io_thread()->message_loop_proxy())); - gaia_auth_for_print->set_message_loop(MessageLoop::current()); - if (gaia_auth_for_print->AuthenticateWithLsid(lsid)) { - auth_succeeded = true; - // Let the frontend know that we have authenticated. - backend_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, - &Core::NotifyAuthenticated, gaia_auth_for_print->auth_token(), - gaia_auth_for_talk->auth_token(), gaia_auth_for_talk->email())); - backend_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, - &Core::NotifyAuthenticated, gaia_auth_for_print->auth_token(), - gaia_auth_for_talk->auth_token(), gaia_auth_for_talk->email())); - DoInitializeWithToken(gaia_auth_for_print->auth_token(), - gaia_auth_for_talk->auth_token(), - gaia_auth_for_talk->email(), - proxy_id); + gaia_auth_for_print->set_message_loop(MessageLoop::current()); + if (gaia_auth_for_print->AuthenticateWithLsid(lsid)) { + // Stash away the user email so we can save it in prefs. + user_email_ = gaia_auth_for_print->email(); + // If the same user is re-enabling Cloud Print and we have stashed robot + // credentials, we will use those. + if ((0 == base::strcasecmp(user_email_.c_str(), last_user_email.c_str())) && + !last_robot_refresh_token.empty() && + !last_robot_email.empty()) { + DoInitializeWithRobotToken(last_robot_refresh_token, + last_robot_email, + proxy_id); } - } - - if (!auth_succeeded) { + DoInitializeWithToken(gaia_auth_for_print->auth_token(), + proxy_id); + } else { // Let the frontend know the of authentication failure. - backend_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, - &Core::NotifyAuthenticationFailed)); + OnAuthError(); } } void CloudPrintProxyBackend::Core::DoInitializeWithToken( const std::string cloud_print_token, - const std::string cloud_print_xmpp_token, - const std::string email, const std::string& proxy_id) { + const std::string& proxy_id) { DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); VLOG(1) << "CP_PROXY: Starting proxy, id: " << proxy_id; + proxy_id_ = proxy_id; + GetTokenStore()->SetToken(cloud_print_token, false); + + // We need to get the credentials of the robot here. + GURL get_authcode_url = + CloudPrintHelpers::GetUrlForGetAuthCode(cloud_print_server_url_, + oauth_client_info_.client_id, + proxy_id_); + next_response_handler_ = + &CloudPrintProxyBackend::Core::HandleGetAuthCodeResponse; + request_ = new CloudPrintURLFetcher; + request_->StartGetRequest(get_authcode_url, + this, + kCloudPrintAPIMaxRetryCount, + std::string()); +} + +void CloudPrintProxyBackend::Core::DoInitializeWithRobotToken( + const std::string& robot_oauth_refresh_token, + const std::string& robot_email, + const std::string& proxy_id) { + robot_email_ = robot_email; + proxy_id_ = proxy_id; + refresh_token_ = robot_oauth_refresh_token; + RefreshAccessToken(); +} +void CloudPrintProxyBackend::Core::PostAuthInitialization() { + DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); + // Now we can get down to registering printers. print_system_ = cloud_print::PrintSystem::CreateInstance(print_system_settings_.get()); if (!print_system_.get()) { NOTREACHED(); return; // No print system available, fail initalization. } - cloud_print::PrintSystem::PrintSystemResult result = print_system_->Init(); - // TODO(sanjeevr): Validate the tokens. - auth_token_ = cloud_print_token; - if (result.succeeded()) { notifier::NotifierOptions notifier_options; notifier_options.request_context_getter = g_service_process->GetServiceURLRequestContextGetter(); + notifier_options.auth_mechanism = "X-OAUTH2"; talk_mediator_.reset(new notifier::TalkMediatorImpl( new notifier::MediatorThreadImpl(notifier_options), notifier_options)); notifier::Subscription subscription; subscription.channel = kCloudPrintPushNotificationsSource; subscription.channel.append("/proxy/"); - subscription.channel.append(proxy_id); + subscription.channel.append(proxy_id_); subscription.from = kCloudPrintPushNotificationsSource; push_notifications_channel_ = subscription.channel; talk_mediator_->AddSubscription(subscription); talk_mediator_->SetDelegate(this); - talk_mediator_->SetAuthToken(email, cloud_print_xmpp_token, - kSyncGaiaServiceId); + talk_mediator_->SetAuthToken( + robot_email_, + CloudPrintTokenStore::current()->token(), + kSyncGaiaServiceId); talk_mediator_->Login(); print_server_watcher_ = print_system_->CreatePrintServerWatcher(); print_server_watcher_->StartWatching(this); - proxy_id_ = proxy_id; - StartRegistration(); } else { // We could not initialize the print system. We need to notify the server. @@ -466,6 +550,7 @@ void CloudPrintProxyBackend::Core::DoShutdown() { notifications_enabled_ = false; notifications_enabled_since_ = base::TimeTicks(); request_ = NULL; + token_store_.reset(); } void CloudPrintProxyBackend::Core::DoRegisterSelectedPrinters( @@ -488,7 +573,6 @@ void CloudPrintProxyBackend::Core::GetRegisteredPrinters() { request_ = new CloudPrintURLFetcher; request_->StartGetRequest(printer_list_url, this, - auth_token_, kCloudPrintAPIMaxRetryCount, std::string()); } @@ -581,7 +665,6 @@ void CloudPrintProxyBackend::Core::OnReceivePrinterCaps( request_ = new CloudPrintURLFetcher; request_->StartPostRequest(post_url, this, - auth_token_, kCloudPrintAPIMaxRetryCount, mime_type, post_data, @@ -642,6 +725,13 @@ void CloudPrintProxyBackend::Core::ScheduleJobPoll() { } } +CloudPrintTokenStore* CloudPrintProxyBackend::Core::GetTokenStore() { + DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); + if (!token_store_.get()) + token_store_.reset(new CloudPrintTokenStore); + return token_store_.get(); +} + // CloudPrintURLFetcher::Delegate implementation. CloudPrintURLFetcher::ResponseAction CloudPrintProxyBackend::Core::HandleJSONData( @@ -664,12 +754,13 @@ void CloudPrintProxyBackend::Core::NotifyPrinterListAvailable( } void CloudPrintProxyBackend::Core::NotifyAuthenticated( - const std::string& cloud_print_token, - const std::string& cloud_print_xmpp_token, - const std::string& email) { + const std::string& robot_oauth_refresh_token, + const std::string& robot_email, + const std::string& user_email) { DCHECK(MessageLoop::current() == backend_->frontend_loop_); - backend_->frontend_->OnAuthenticated(cloud_print_token, - cloud_print_xmpp_token, email); + backend_->frontend_->OnAuthenticated(robot_oauth_refresh_token, + robot_email, + user_email); } void CloudPrintProxyBackend::Core::NotifyAuthenticationFailed() { @@ -683,6 +774,35 @@ void CloudPrintProxyBackend::Core::NotifyPrintSystemUnavailable() { } CloudPrintURLFetcher::ResponseAction +CloudPrintProxyBackend::Core::HandleGetAuthCodeResponse( + const URLFetcher* source, + const GURL& url, + DictionaryValue* json_data, + bool succeeded) { + DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); + if (!succeeded) { + OnAuthError(); + return CloudPrintURLFetcher::STOP_PROCESSING; + } + std::string auth_code; + if (!json_data->GetString(kOAuthCodeValue, &auth_code)) { + OnAuthError(); + return CloudPrintURLFetcher::STOP_PROCESSING; + } + json_data->GetString(kXMPPJidValue, &robot_email_); + // Now that we have an auth code we need to get the refresh and access tokens. + oauth_client_.reset(new gaia::GaiaOAuthClient( + gaia::kGaiaOAuth2Url, + g_service_process->GetServiceURLRequestContextGetter())); + oauth_client_->GetTokensFromAuthCode(oauth_client_info_, + auth_code, + kCloudPrintAPIMaxRetryCount, + this); + + return CloudPrintURLFetcher::STOP_PROCESSING; +} + +CloudPrintURLFetcher::ResponseAction CloudPrintProxyBackend::Core::HandlePrinterListResponse( const URLFetcher* source, const GURL& url, @@ -763,9 +883,11 @@ void CloudPrintProxyBackend::Core::InitJobHandlerForPrinter( } } scoped_refptr<PrinterJobHandler> job_handler; - job_handler = new PrinterJobHandler(printer_info, printer_info_cloud, - auth_token_, cloud_print_server_url_, - print_system_.get(), this); + job_handler = new PrinterJobHandler(printer_info, + printer_info_cloud, + cloud_print_server_url_, + print_system_.get(), + this); job_handler_map_[printer_info_cloud.printer_id] = job_handler; job_handler->Initialize(); } @@ -795,7 +917,6 @@ void CloudPrintProxyBackend::Core::ReportUserMessage( request_ = new CloudPrintURLFetcher; request_->StartPostRequest(post_url, this, - auth_token_, kCloudPrintAPIMaxRetryCount, mime_type, post_data, @@ -885,6 +1006,17 @@ bool CloudPrintProxyBackend::Core::RemovePrinterFromList( return false; } +void CloudPrintProxyBackend::Core::RefreshAccessToken() { + DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); + oauth_client_.reset(new gaia::GaiaOAuthClient( + gaia::kGaiaOAuth2Url, + g_service_process->GetServiceURLRequestContextGetter())); + oauth_client_->RefreshToken(oauth_client_info_, + refresh_token_, + kCloudPrintAPIMaxRetryCount, + this); +} + void CloudPrintProxyBackend::Core::OnNotificationStateChange( bool notification_enabled) { DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); @@ -951,3 +1083,59 @@ void CloudPrintProxyBackend::Core::OnPrinterNotFound( // from the server. *delete_from_server = complete_list_available_; } + + // gaia::GaiaOAuthClient::Delegate implementation. +void CloudPrintProxyBackend::Core::OnGetTokensResponse( + const std::string& refresh_token, + const std::string& access_token, + int expires_in_seconds) { + refresh_token_ = refresh_token; + // After saving the refresh token, this is just like having just refreshed + // the access token. Just call OnRefreshTokenResponse. + OnRefreshTokenResponse(access_token, expires_in_seconds); +} + +void CloudPrintProxyBackend::Core::OnRefreshTokenResponse( + const std::string& access_token, int expires_in_seconds) { + // If our current token is not OAuth, we either have no token at all or we + // have a ClientLogin token which we just exchanged for an OAuth token. + // In this case we need to do the startup initialiazation. + // TODO(sanjeevr): Use an enum for state instead of using this as a signal. + // I will do this in a follow-up change. + CloudPrintTokenStore* token_store = GetTokenStore(); + bool first_time = !token_store->token_is_oauth(); + token_store->SetToken(access_token, true); + // Let the frontend know that we have authenticated. + backend_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, + &Core::NotifyAuthenticated, refresh_token_, robot_email_, user_email_)); + if (first_time) { + PostAuthInitialization(); + } else { + // If we are refreshing a token, update the XMPP token too. + DCHECK(talk_mediator_.get()); + talk_mediator_->SetAuthToken(robot_email_, + access_token, + kSyncGaiaServiceId); + } + // Schedule a task to refresh the access token again when it is about to + // expire. + DCHECK(expires_in_seconds > kTokenRefreshGracePeriodSecs); + int64 refresh_delay = + (expires_in_seconds - kTokenRefreshGracePeriodSecs)*1000; + MessageLoop::current()->PostDelayedTask( + FROM_HERE, + NewRunnableMethod(this, &Core::RefreshAccessToken), + refresh_delay); +} + +void CloudPrintProxyBackend::Core::OnOAuthError() { + OnAuthError(); +} + +void CloudPrintProxyBackend::Core::OnNetworkError(int response_code) { + // Since we specify inifinite retries on network errors, this should never + // be called. + NOTREACHED() << + "OnNetworkError invoked when not expected, response code is " << + response_code; +} diff --git a/chrome/service/cloud_print/cloud_print_proxy_backend.h b/chrome/service/cloud_print/cloud_print_proxy_backend.h index e1a3ef9..71cf92f 100644 --- a/chrome/service/cloud_print/cloud_print_proxy_backend.h +++ b/chrome/service/cloud_print/cloud_print_proxy_backend.h @@ -15,6 +15,10 @@ class CloudPrintProxyService; class GURL; class DictionaryValue; +namespace gaia { +struct OAuthClientInfo; +} + // CloudPrintProxyFrontend is the interface used by CloudPrintProxyBackend to // communicate with the entity that created it and, presumably, is interested in // cloud print proxy related activity. @@ -29,9 +33,9 @@ class CloudPrintProxyFrontend { const printing::PrinterList& printer_list) = 0; // We successfully authenticated with the cloud print server. This callback // allows the frontend to persist the tokens. - virtual void OnAuthenticated(const std::string& cloud_print_token, - const std::string& cloud_print_xmpp_token, - const std::string& email) = 0; + virtual void OnAuthenticated(const std::string& robot_oauth_refresh_token, + const std::string& robot_email, + const std::string& user_email) = 0; // We have invalid/expired credentials. virtual void OnAuthenticationFailed() = 0; // The print system could not be initialized. @@ -49,17 +53,31 @@ class CloudPrintProxyBackend { public: // It is OK for print_system_settings to be NULL. In this case system should // use system default settings. - explicit CloudPrintProxyBackend(CloudPrintProxyFrontend* frontend, - const GURL& cloud_print_server_url, - const DictionaryValue* print_sys_settings, - bool enable_job_poll); + CloudPrintProxyBackend( + CloudPrintProxyFrontend* frontend, + const GURL& cloud_print_server_url, + const DictionaryValue* print_sys_settings, + const gaia::OAuthClientInfo& oauth_client_info, + bool enable_job_poll); ~CloudPrintProxyBackend(); - bool InitializeWithLsid(const std::string& lsid, const std::string& proxy_id); + // Called when the user enables Google Cloud Print. + // |last_robot_refresh_token|, |last_robot_email| and |last_user_email| are + // the previously persisted credentials if any. We will use this is the passed + // in LSID belongs to the same user as |last_user_email|. + bool InitializeWithLsid(const std::string& lsid, + const std::string& proxy_id, + const std::string& last_robot_refresh_token, + const std::string& last_robot_email, + const std::string& last_user_email); + // Legacy mechanism when we have saved user credentials but no saved robot + // credentials. bool InitializeWithToken(const std::string& cloud_print_token, - const std::string& cloud_print_xmpp_token, - const std::string& email, const std::string& proxy_id); + // Called when we have saved robot credentials. + bool InitializeWithRobotToken(const std::string& robot_oauth_refresh_token, + const std::string& robot_email, + const std::string& proxy_id); void Shutdown(); void RegisterPrinters(const printing::PrinterList& printer_list); diff --git a/chrome/service/cloud_print/cloud_print_token_store.cc b/chrome/service/cloud_print/cloud_print_token_store.cc new file mode 100644 index 0000000..5c38314 --- /dev/null +++ b/chrome/service/cloud_print/cloud_print_token_store.cc @@ -0,0 +1,31 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/service/cloud_print/cloud_print_token_store.h" + +#include "base/lazy_instance.h" +#include "base/threading/thread_local.h" + +// Keep the global CloudPrintTokenStore in a TLS slot so it is impossible to +// incorrectly from the wrong thread. +static base::LazyInstance<base::ThreadLocalPointer<CloudPrintTokenStore> > + lazy_tls(base::LINKER_INITIALIZED); + +CloudPrintTokenStore* CloudPrintTokenStore::current() { + return lazy_tls.Pointer()->Get(); +} + +CloudPrintTokenStore::CloudPrintTokenStore() : token_is_oauth_(false) { + lazy_tls.Pointer()->Set(this); +} + +CloudPrintTokenStore::~CloudPrintTokenStore() { + lazy_tls.Pointer()->Set(NULL); +} + +void CloudPrintTokenStore::SetToken(const std::string& token, bool is_oauth) { + DCHECK(CalledOnValidThread()); + token_ = token; + token_is_oauth_ = is_oauth; +} diff --git a/chrome/service/cloud_print/cloud_print_token_store.h b/chrome/service/cloud_print/cloud_print_token_store.h new file mode 100644 index 0000000..b136983 --- /dev/null +++ b/chrome/service/cloud_print/cloud_print_token_store.h @@ -0,0 +1,43 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_SERVICE_CLOUD_PRINT_CLOUD_PRINT_TOKEN_STORE_H_ +#define CHROME_SERVICE_CLOUD_PRINT_CLOUD_PRINT_TOKEN_STORE_H_ +#pragma once + +#include <string> + +// This class serves as the single repository for cloud print auth tokens. This +// is only used within the CloudPrintProxyCoreThread. + +#include "base/logging.h" +#include "base/threading/non_thread_safe.h" + +class CloudPrintTokenStore : public base::NonThreadSafe { + public: + // Returns the CloudPrintTokenStore instance for this thread. Will be NULL + // if no instance was created in this thread before. + static CloudPrintTokenStore* current(); + + CloudPrintTokenStore(); + ~CloudPrintTokenStore(); + + void SetToken(const std::string& token, bool is_oauth); + std::string token() const { + DCHECK(CalledOnValidThread()); + return token_; + } + bool token_is_oauth() const { + DCHECK(CalledOnValidThread()); + return token_is_oauth_; + } + + private: + std::string token_; + bool token_is_oauth_; + + DISALLOW_COPY_AND_ASSIGN(CloudPrintTokenStore); +}; + +#endif // CHROME_SERVICE_CLOUD_PRINT_CLOUD_PRINT_TOKEN_STORE_H_ diff --git a/chrome/service/cloud_print/cloud_print_token_store_unittest.cc b/chrome/service/cloud_print/cloud_print_token_store_unittest.cc new file mode 100644 index 0000000..9cf9339 --- /dev/null +++ b/chrome/service/cloud_print/cloud_print_token_store_unittest.cc @@ -0,0 +1,22 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/service/cloud_print/cloud_print_token_store.h" + +#include "testing/gtest/include/gtest/gtest.h" + +TEST(CloudPrintTokenStoreTest, Basic) { + EXPECT_EQ(NULL, CloudPrintTokenStore::current()); + CloudPrintTokenStore* store = new CloudPrintTokenStore; + EXPECT_EQ(store, CloudPrintTokenStore::current()); + CloudPrintTokenStore::current()->SetToken("myclientlogintoken", false); + EXPECT_EQ(CloudPrintTokenStore::current()->token(), "myclientlogintoken"); + EXPECT_FALSE(CloudPrintTokenStore::current()->token_is_oauth()); + CloudPrintTokenStore::current()->SetToken("myoauth2token", true); + EXPECT_EQ(CloudPrintTokenStore::current()->token(), "myoauth2token"); + EXPECT_TRUE(CloudPrintTokenStore::current()->token_is_oauth()); + delete store; + EXPECT_EQ(NULL, CloudPrintTokenStore::current()); +} + diff --git a/chrome/service/cloud_print/cloud_print_url_fetcher.cc b/chrome/service/cloud_print/cloud_print_url_fetcher.cc index 6fa7510..ad4734e 100644 --- a/chrome/service/cloud_print/cloud_print_url_fetcher.cc +++ b/chrome/service/cloud_print/cloud_print_url_fetcher.cc @@ -9,6 +9,7 @@ #include "chrome/common/net/http_return.h" #include "chrome/service/cloud_print/cloud_print_consts.h" #include "chrome/service/cloud_print/cloud_print_helpers.h" +#include "chrome/service/cloud_print/cloud_print_token_store.h" #include "chrome/service/net/service_url_request_context.h" #include "chrome/service/service_process.h" #include "googleurl/src/gurl.h" @@ -22,23 +23,31 @@ CloudPrintURLFetcher::CloudPrintURLFetcher() void CloudPrintURLFetcher::StartGetRequest( const GURL& url, Delegate* delegate, - const std::string& auth_token, int max_retries, const std::string& additional_headers) { - StartRequestHelper(url, URLFetcher::GET, delegate, auth_token, max_retries, - std::string(), std::string(), additional_headers); + StartRequestHelper(url, + URLFetcher::GET, + delegate, + max_retries, + std::string(), + std::string(), + additional_headers); } void CloudPrintURLFetcher::StartPostRequest( const GURL& url, Delegate* delegate, - const std::string& auth_token, int max_retries, const std::string& post_data_mime_type, const std::string& post_data, const std::string& additional_headers) { - StartRequestHelper(url, URLFetcher::POST, delegate, auth_token, max_retries, - post_data_mime_type, post_data, additional_headers); + StartRequestHelper(url, + URLFetcher::POST, + delegate, + max_retries, + post_data_mime_type, + post_data, + additional_headers); } // URLFetcher::Delegate implementation. @@ -60,8 +69,11 @@ void CloudPrintURLFetcher::OnURLFetchComplete( cookies, data); if (action == CONTINUE_PROCESSING) { - // If there was an auth error, we are done. - if (RC_FORBIDDEN == response_code) { + // If we are not using an OAuth token, and we got an auth error, we are + // done. Else, the token may have been refreshed. Let us try again. + if ((RC_FORBIDDEN == response_code) && + (!CloudPrintTokenStore::current() || + !CloudPrintTokenStore::current()->token_is_oauth())) { delegate_->OnRequestAuthError(); return; } @@ -104,7 +116,9 @@ void CloudPrintURLFetcher::OnURLFetchComplete( delegate_->OnRequestGiveUp(); } else { // Either no retry limit specified or retry limit has not yet been - // reached. Try again. + // reached. Try again. Set up the request headers again because the token + // may have changed. + SetupRequestHeaders(); request_->Start(); } } @@ -114,27 +128,20 @@ void CloudPrintURLFetcher::StartRequestHelper( const GURL& url, URLFetcher::RequestType request_type, Delegate* delegate, - const std::string& auth_token, int max_retries, const std::string& post_data_mime_type, const std::string& post_data, const std::string& additional_headers) { DCHECK(delegate); + // Persist the additional headers in case we need to retry the request. + additional_headers_ = additional_headers; request_.reset(new URLFetcher(url, request_type, this)); request_->set_request_context(GetRequestContextGetter()); // Since we implement our own retry logic, disable the retry in URLFetcher. request_->set_automatically_retry_on_5xx(false); request_->set_max_retries(max_retries); + SetupRequestHeaders(); delegate_ = delegate; - std::string headers = "Authorization: GoogleLogin auth="; - headers += auth_token; - headers += "\r\n"; - headers += kChromeCloudPrintProxyHeader; - if (!additional_headers.empty()) { - headers += "\r\n"; - headers += additional_headers; - } - request_->set_extra_request_headers(headers); if (request_type == URLFetcher::POST) { request_->set_upload_data(post_data_mime_type, post_data); } @@ -142,6 +149,23 @@ void CloudPrintURLFetcher::StartRequestHelper( request_->Start(); } +void CloudPrintURLFetcher::SetupRequestHeaders() { + std::string headers; + CloudPrintTokenStore* token_store = CloudPrintTokenStore::current(); + if (token_store) { + headers = token_store->token_is_oauth() ? + "Authorization: OAuth " : "Authorization: GoogleLogin auth="; + headers += token_store->token(); + headers += "\r\n"; + } + headers += kChromeCloudPrintProxyHeader; + if (!additional_headers_.empty()) { + headers += "\r\n"; + headers += additional_headers_; + } + request_->set_extra_request_headers(headers); +} + CloudPrintURLFetcher::~CloudPrintURLFetcher() {} net::URLRequestContextGetter* CloudPrintURLFetcher::GetRequestContextGetter() { diff --git a/chrome/service/cloud_print/cloud_print_url_fetcher.h b/chrome/service/cloud_print/cloud_print_url_fetcher.h index c56fd16..433ed56 100644 --- a/chrome/service/cloud_print/cloud_print_url_fetcher.h +++ b/chrome/service/cloud_print/cloud_print_url_fetcher.h @@ -73,19 +73,17 @@ class CloudPrintURLFetcher // was a retry limit - a limit of -1 implies no limit). virtual void OnRequestGiveUp() { } // Invoked when the request returns a 403 error (applicable only when - // HandleRawResponse returns CONTINUE_PROCESSING) + // HandleRawResponse returns CONTINUE_PROCESSING). virtual void OnRequestAuthError() = 0; }; CloudPrintURLFetcher(); void StartGetRequest(const GURL& url, Delegate* delegate, - const std::string& auth_token, int max_retries, const std::string& additional_headers); void StartPostRequest(const GURL& url, Delegate* delegate, - const std::string& auth_token, int max_retries, const std::string& post_data_mime_type, const std::string& post_data, @@ -108,15 +106,16 @@ class CloudPrintURLFetcher void StartRequestHelper(const GURL& url, URLFetcher::RequestType request_type, Delegate* delegate, - const std::string& auth_token, int max_retries, const std::string& post_data_mime_type, const std::string& post_data, const std::string& additional_headers); + void SetupRequestHeaders(); scoped_ptr<URLFetcher> request_; Delegate* delegate_; int num_retries_; + std::string additional_headers_; }; typedef CloudPrintURLFetcher::Delegate CloudPrintURLFetcherDelegate; diff --git a/chrome/service/cloud_print/cloud_print_url_fetcher_unittest.cc b/chrome/service/cloud_print/cloud_print_url_fetcher_unittest.cc index 4e61856..6a2637d 100644 --- a/chrome/service/cloud_print/cloud_print_url_fetcher_unittest.cc +++ b/chrome/service/cloud_print/cloud_print_url_fetcher_unittest.cc @@ -192,7 +192,7 @@ void CloudPrintURLFetcherTest::CreateFetcher(const GURL& url, int max_retries) { fetcher_ = new TestCloudPrintURLFetcher(io_message_loop_proxy()); max_retries_ = max_retries; start_time_ = Time::Now(); - fetcher_->StartGetRequest(url, this, "", max_retries_, std::string()); + fetcher_->StartGetRequest(url, this, max_retries_, std::string()); } CloudPrintURLFetcher::ResponseAction @@ -264,7 +264,10 @@ CloudPrintURLFetcherOverloadTest::HandleRawData(const URLFetcher* source, const TimeDelta one_second = TimeDelta::FromMilliseconds(1000); response_count_++; if (response_count_ < 20) { - fetcher_->StartGetRequest(url, this, "", max_retries_, std::string()); + fetcher_->StartGetRequest(url, + this, + max_retries_, + std::string()); } else { // We have already sent 20 requests continuously. And we expect that // it takes more than 1 second due to the overload protection settings. diff --git a/chrome/service/cloud_print/job_status_updater.cc b/chrome/service/cloud_print/job_status_updater.cc index 56632b1..2f16536 100644 --- a/chrome/service/cloud_print/job_status_updater.cc +++ b/chrome/service/cloud_print/job_status_updater.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -15,12 +15,11 @@ JobStatusUpdater::JobStatusUpdater(const std::string& printer_name, const std::string& job_id, cloud_print::PlatformJobId& local_job_id, - const std::string& auth_token, const GURL& cloud_print_server_url, cloud_print::PrintSystem* print_system, Delegate* delegate) : printer_name_(printer_name), job_id_(job_id), - local_job_id_(local_job_id), auth_token_(auth_token), + local_job_id_(local_job_id), cloud_print_server_url_(cloud_print_server_url), print_system_(print_system), delegate_(delegate), stopped_(false) { DCHECK(delegate_); @@ -63,7 +62,6 @@ void JobStatusUpdater::UpdateStatus() { CloudPrintHelpers::GetUrlForJobStatusUpdate( cloud_print_server_url_, job_id_, last_job_details_), this, - auth_token_, kCloudPrintAPIMaxRetryCount, std::string()); } diff --git a/chrome/service/cloud_print/job_status_updater.h b/chrome/service/cloud_print/job_status_updater.h index 9c7f6cf..cece13a 100644 --- a/chrome/service/cloud_print/job_status_updater.h +++ b/chrome/service/cloud_print/job_status_updater.h @@ -35,7 +35,6 @@ class JobStatusUpdater : public base::RefCountedThreadSafe<JobStatusUpdater>, JobStatusUpdater(const std::string& printer_name, const std::string& job_id, cloud_print::PlatformJobId& local_job_id, - const std::string& auth_token, const GURL& cloud_print_server_url, cloud_print::PrintSystem* print_system, Delegate* delegate); @@ -59,7 +58,6 @@ class JobStatusUpdater : public base::RefCountedThreadSafe<JobStatusUpdater>, cloud_print::PlatformJobId local_job_id_; cloud_print::PrintJobDetails last_job_details_; scoped_refptr<CloudPrintURLFetcher> request_; - std::string auth_token_; GURL cloud_print_server_url_; scoped_refptr<cloud_print::PrintSystem> print_system_; Delegate* delegate_; diff --git a/chrome/service/cloud_print/printer_job_handler.cc b/chrome/service/cloud_print/printer_job_handler.cc index 20ea7f4..5aba550 100644 --- a/chrome/service/cloud_print/printer_job_handler.cc +++ b/chrome/service/cloud_print/printer_job_handler.cc @@ -33,14 +33,12 @@ void PrinterJobHandler::JobDetails::Clear() { PrinterJobHandler::PrinterJobHandler( const printing::PrinterBasicInfo& printer_info, const PrinterInfoFromCloud& printer_info_cloud, - const std::string& auth_token, const GURL& cloud_print_server_url, cloud_print::PrintSystem* print_system, Delegate* delegate) : print_system_(print_system), printer_info_(printer_info), printer_info_cloud_(printer_info_cloud), - auth_token_(auth_token), cloud_print_server_url_(cloud_print_server_url), delegate_(delegate), local_job_id_(-1), @@ -110,7 +108,6 @@ void PrinterJobHandler::Start() { CloudPrintHelpers::GetUrlForPrinterDelete( cloud_print_server_url_, printer_info_cloud_.printer_id), this, - auth_token_, kCloudPrintAPIMaxRetryCount, std::string()); } @@ -129,7 +126,6 @@ void PrinterJobHandler::Start() { cloud_print_server_url_, printer_info_cloud_.printer_id, job_fetch_reason_), this, - auth_token_, kCloudPrintAPIMaxRetryCount, std::string()); last_job_fetch_time_ = base::TimeTicks::Now(); @@ -261,7 +257,6 @@ void PrinterJobHandler::OnReceivePrinterCaps( CloudPrintHelpers::GetUrlForPrinterUpdate( cloud_print_server_url_, printer_info_cloud_.printer_id), this, - auth_token_, kCloudPrintAPIMaxRetryCount, mime_type, post_data, @@ -443,7 +438,6 @@ PrinterJobHandler::HandleJobMetadataResponse( request_ = new CloudPrintURLFetcher; request_->StartGetRequest(GURL(print_ticket_url.c_str()), this, - auth_token_, kCloudPrintAPIMaxRetryCount, std::string()); } @@ -470,7 +464,6 @@ PrinterJobHandler::HandlePrintTicketResponse(const URLFetcher* source, accept_headers += print_system_->GetSupportedMimeTypes(); request_->StartGetRequest(GURL(print_data_url_.c_str()), this, - auth_token_, kJobDataMaxRetryCount, accept_headers); } else { @@ -520,7 +513,7 @@ PrinterJobHandler::HandleSuccessStatusUpdateResponse( // that monitors the status of the job and updates the server. scoped_refptr<JobStatusUpdater> job_status_updater( new JobStatusUpdater(printer_info_.printer_name, job_details_.job_id_, - local_job_id_, auth_token_, cloud_print_server_url_, + local_job_id_, cloud_print_server_url_, print_system_.get(), this)); job_status_updater_list_.push_back(job_status_updater); MessageLoop::current()->PostTask( @@ -619,7 +612,6 @@ void PrinterJobHandler::UpdateJobStatus(cloud_print::PrintJobStatus status, job_details_.job_id_, status), this, - auth_token_, kCloudPrintAPIMaxRetryCount, std::string()); } diff --git a/chrome/service/cloud_print/printer_job_handler.h b/chrome/service/cloud_print/printer_job_handler.h index 8633875..6e804f9 100644 --- a/chrome/service/cloud_print/printer_job_handler.h +++ b/chrome/service/cloud_print/printer_job_handler.h @@ -110,7 +110,6 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>, // Begin public interface PrinterJobHandler(const printing::PrinterBasicInfo& printer_info, const PrinterInfoFromCloud& printer_info_from_server, - const std::string& auth_token, const GURL& cloud_print_server_url, cloud_print::PrintSystem* print_system, Delegate* delegate); @@ -256,7 +255,6 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>, scoped_refptr<cloud_print::PrintSystem> print_system_; printing::PrinterBasicInfo printer_info_; PrinterInfoFromCloud printer_info_cloud_; - std::string auth_token_; GURL cloud_print_server_url_; std::string print_data_url_; JobDetails job_details_; diff --git a/chrome/service/service_process_prefs.cc b/chrome/service/service_process_prefs.cc index 7aa94b05..8eb2962 100644 --- a/chrome/service/service_process_prefs.cc +++ b/chrome/service/service_process_prefs.cc @@ -54,3 +54,7 @@ void ServiceProcessPrefs::GetDictionary(const std::string& key, *result = static_cast<const DictionaryValue*>(value); } + +void ServiceProcessPrefs::RemovePref(const std::string& key) { + prefs_->RemoveValue(key); +} diff --git a/chrome/service/service_process_prefs.h b/chrome/service/service_process_prefs.h index a16f620..6816f50 100644 --- a/chrome/service/service_process_prefs.h +++ b/chrome/service/service_process_prefs.h @@ -41,6 +41,9 @@ class ServiceProcessPrefs { // Get a dictionary preference for |key| and store it in |result|. void GetDictionary(const std::string& key, const DictionaryValue** result); + // Removes the pref specified by |key|. + void RemovePref(const std::string& key); + private: scoped_refptr<JsonPrefStore> prefs_; |