Home | History | Annotate | Download | only in settings
      1 // Copyright 2013 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/browser/chromeos/settings/device_oauth2_token_service.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/prefs/pref_registry_simple.h"
     11 #include "base/prefs/pref_service.h"
     12 #include "base/values.h"
     13 #include "chrome/browser/browser_process.h"
     14 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
     15 #include "chrome/browser/policy/browser_policy_connector.h"
     16 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
     17 #include "chrome/common/pref_names.h"
     18 #include "chromeos/cryptohome/cryptohome_library.h"
     19 #include "content/public/browser/browser_thread.h"
     20 #include "google_apis/gaia/gaia_urls.h"
     21 #include "google_apis/gaia/google_service_auth_error.h"
     22 
     23 namespace {
     24 const char kServiceScopeGetUserInfo[] =
     25     "https://www.googleapis.com/auth/userinfo.email";
     26 }  // namespace
     27 
     28 namespace chromeos {
     29 
     30 // A wrapper for the consumer passed to StartRequest, which doesn't call
     31 // through to the target Consumer unless the refresh token validation is
     32 // complete.  Additionally implements the Request interface, so that it
     33 // can be passed back to the caller and directly deleted when cancelling
     34 // the request.
     35 class DeviceOAuth2TokenService::ValidatingConsumer
     36     : public OAuth2TokenService::Consumer,
     37       public OAuth2TokenService::Request,
     38       public gaia::GaiaOAuthClient::Delegate {
     39  public:
     40   explicit ValidatingConsumer(DeviceOAuth2TokenService* token_service,
     41                               Consumer* consumer);
     42   virtual ~ValidatingConsumer();
     43 
     44   void StartValidation(scoped_ptr<Request> request);
     45 
     46   // OAuth2TokenService::Consumer
     47   virtual void OnGetTokenSuccess(
     48       const Request* request,
     49       const std::string& access_token,
     50       const base::Time& expiration_time) OVERRIDE;
     51   virtual void OnGetTokenFailure(
     52       const Request* request,
     53       const GoogleServiceAuthError& error) OVERRIDE;
     54 
     55   // gaia::GaiaOAuthClient::Delegate implementation.
     56   virtual void OnRefreshTokenResponse(const std::string& access_token,
     57                                       int expires_in_seconds) OVERRIDE;
     58   virtual void OnGetTokenInfoResponse(scoped_ptr<DictionaryValue> token_info)
     59       OVERRIDE;
     60   virtual void OnOAuthError() OVERRIDE;
     61   virtual void OnNetworkError(int response_code) OVERRIDE;
     62 
     63  private:
     64   void RefreshTokenIsValid(bool is_valid);
     65   void InformConsumer();
     66 
     67   DeviceOAuth2TokenService* token_service_;
     68   Consumer* consumer_;
     69   scoped_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_;
     70 
     71   // We don't know which will complete first: the validation or the token
     72   // minting.  So, we need to cache the results so the final callback can
     73   // take action.
     74 
     75   // RefreshTokenValidationConsumer results
     76   bool token_validation_done_;
     77   bool token_is_valid_;
     78 
     79   // The request instance returned by OAuth2TokenService, which we're
     80   // wrapping.  If the this object is deleted, |request_| will also be
     81   // deleted and the OAuth2TokenService won't call back on this object.
     82   scoped_ptr<OAuth2TokenService::Request> request_;
     83 
     84   // OAuth2TokenService::Consumer results
     85   bool token_fetch_done_;
     86   std::string access_token_;
     87   base::Time expiration_time_;
     88   scoped_ptr<GoogleServiceAuthError> error_;
     89 };
     90 
     91 DeviceOAuth2TokenService::ValidatingConsumer::ValidatingConsumer(
     92     DeviceOAuth2TokenService* token_service,
     93     Consumer* consumer)
     94         : token_service_(token_service),
     95           consumer_(consumer),
     96           token_validation_done_(false),
     97           token_is_valid_(false),
     98           token_fetch_done_(false) {
     99 }
    100 
    101 DeviceOAuth2TokenService::ValidatingConsumer::~ValidatingConsumer() {
    102 }
    103 
    104 void DeviceOAuth2TokenService::ValidatingConsumer::StartValidation(
    105     scoped_ptr<Request> request) {
    106   DCHECK(!gaia_oauth_client_);
    107   request_ = request.Pass();
    108   gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(
    109       g_browser_process->system_request_context()));
    110 
    111   GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
    112   gaia::OAuthClientInfo client_info;
    113   client_info.client_id = gaia_urls->oauth2_chrome_client_id();
    114   client_info.client_secret = gaia_urls->oauth2_chrome_client_secret();
    115 
    116   gaia_oauth_client_->RefreshToken(
    117       client_info,
    118       token_service_->GetRefreshToken(),
    119       std::vector<std::string>(1, kServiceScopeGetUserInfo),
    120       token_service_->max_refresh_token_validation_retries_,
    121       this);
    122 }
    123 
    124 void DeviceOAuth2TokenService::ValidatingConsumer::OnRefreshTokenResponse(
    125     const std::string& access_token,
    126     int expires_in_seconds) {
    127   gaia_oauth_client_->GetTokenInfo(
    128       access_token,
    129       token_service_->max_refresh_token_validation_retries_,
    130       this);
    131 }
    132 
    133 void DeviceOAuth2TokenService::ValidatingConsumer::OnGetTokenInfoResponse(
    134     scoped_ptr<DictionaryValue> token_info) {
    135   std::string gaia_robot_id;
    136   token_info->GetString("email", &gaia_robot_id);
    137 
    138   std::string policy_robot_id = token_service_->GetRobotAccountId();
    139 
    140   if (policy_robot_id == gaia_robot_id) {
    141     RefreshTokenIsValid(true);
    142   } else {
    143     if (gaia_robot_id.empty()) {
    144       LOG(WARNING) << "Device service account owner in policy is empty.";
    145     } else {
    146       LOG(INFO) << "Device service account owner in policy does not match "
    147                 << "refresh token owner \"" << gaia_robot_id << "\".";
    148     }
    149     RefreshTokenIsValid(false);
    150   }
    151 }
    152 
    153 void DeviceOAuth2TokenService::ValidatingConsumer::OnOAuthError() {
    154   RefreshTokenIsValid(false);
    155 }
    156 
    157 void DeviceOAuth2TokenService::ValidatingConsumer::OnNetworkError(
    158     int response_code) {
    159   RefreshTokenIsValid(false);
    160 }
    161 
    162 void DeviceOAuth2TokenService::ValidatingConsumer::OnGetTokenSuccess(
    163       const Request* request,
    164       const std::string& access_token,
    165       const base::Time& expiration_time) {
    166   token_fetch_done_ = true;
    167   access_token_ = access_token;
    168   expiration_time_ = expiration_time;
    169   if (token_validation_done_)
    170     InformConsumer();
    171 }
    172 
    173 void DeviceOAuth2TokenService::ValidatingConsumer::OnGetTokenFailure(
    174       const Request* request,
    175       const GoogleServiceAuthError& error) {
    176   token_fetch_done_ = true;
    177   error_.reset(new GoogleServiceAuthError(error.state()));
    178   if (token_validation_done_)
    179     InformConsumer();
    180 }
    181 
    182 void DeviceOAuth2TokenService::ValidatingConsumer::RefreshTokenIsValid(
    183     bool is_valid) {
    184   token_validation_done_ = true;
    185   token_is_valid_ = is_valid;
    186   if (token_fetch_done_)
    187     InformConsumer();
    188 }
    189 
    190 void DeviceOAuth2TokenService::ValidatingConsumer::InformConsumer() {
    191   DCHECK(token_fetch_done_);
    192   DCHECK(token_validation_done_);
    193   token_service_->OnValidationComplete(token_is_valid_);
    194   // Note: this object (which is also the Request instance) may be deleted in
    195   // these consumer callbacks, so the callbacks must be the last line executed.
    196   // Also, make copies of the parameters passed to the consumer to avoid invalid
    197   // memory accesses when the consumer deletes |this| immediately.
    198   if (!token_is_valid_) {
    199     consumer_->OnGetTokenFailure(this, GoogleServiceAuthError(
    200         GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
    201   } else if (error_) {
    202     GoogleServiceAuthError error_copy = *error_;
    203     consumer_->OnGetTokenFailure(this, error_copy);
    204   } else {
    205     std::string access_token_copy = access_token_;
    206     base::Time expiration_time_copy = expiration_time_;
    207     consumer_->OnGetTokenSuccess(this, access_token_copy, expiration_time_copy);
    208   }
    209 }
    210 
    211 DeviceOAuth2TokenService::DeviceOAuth2TokenService(
    212     net::URLRequestContextGetter* getter,
    213     PrefService* local_state)
    214     : refresh_token_is_valid_(false),
    215       max_refresh_token_validation_retries_(3),
    216       url_request_context_getter_(getter),
    217       local_state_(local_state) {
    218 }
    219 
    220 DeviceOAuth2TokenService::~DeviceOAuth2TokenService() {
    221 }
    222 
    223 net::URLRequestContextGetter* DeviceOAuth2TokenService::GetRequestContext() {
    224   return url_request_context_getter_.get();
    225 }
    226 
    227 scoped_ptr<OAuth2TokenService::Request> DeviceOAuth2TokenService::StartRequest(
    228     const OAuth2TokenService::ScopeSet& scopes,
    229     OAuth2TokenService::Consumer* consumer) {
    230   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    231 
    232   if (refresh_token_is_valid_) {
    233     return OAuth2TokenService::StartRequest(scopes, consumer).Pass();
    234   } else {
    235     scoped_ptr<ValidatingConsumer> validating_consumer(
    236         new ValidatingConsumer(this, consumer));
    237 
    238     scoped_ptr<Request> request = OAuth2TokenService::StartRequest(
    239         scopes, validating_consumer.get());
    240     validating_consumer->StartValidation(request.Pass());
    241     return validating_consumer.PassAs<Request>();
    242   }
    243 }
    244 
    245 void DeviceOAuth2TokenService::OnValidationComplete(
    246     bool refresh_token_is_valid) {
    247   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    248   refresh_token_is_valid_ = refresh_token_is_valid;
    249 }
    250 
    251 // static
    252 void DeviceOAuth2TokenService::RegisterPrefs(PrefRegistrySimple* registry) {
    253   registry->RegisterStringPref(prefs::kDeviceRobotAnyApiRefreshToken,
    254                                std::string());
    255 }
    256 
    257 void DeviceOAuth2TokenService::SetAndSaveRefreshToken(
    258     const std::string& refresh_token) {
    259   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    260   std::string encrypted_refresh_token =
    261       CryptohomeLibrary::Get()->EncryptWithSystemSalt(refresh_token);
    262 
    263   local_state_->SetString(prefs::kDeviceRobotAnyApiRefreshToken,
    264                           encrypted_refresh_token);
    265 }
    266 
    267 std::string DeviceOAuth2TokenService::GetRefreshToken() {
    268   if (refresh_token_.empty()) {
    269     std::string encrypted_refresh_token =
    270         local_state_->GetString(prefs::kDeviceRobotAnyApiRefreshToken);
    271 
    272     refresh_token_ = CryptohomeLibrary::Get()->DecryptWithSystemSalt(
    273         encrypted_refresh_token);
    274   }
    275   return refresh_token_;
    276 }
    277 
    278 std::string DeviceOAuth2TokenService::GetRobotAccountId() {
    279   policy::BrowserPolicyConnector* connector =
    280       g_browser_process->browser_policy_connector();
    281   if (connector)
    282     return connector->GetDeviceCloudPolicyManager()->GetRobotAccountId();
    283   return std::string();
    284 }
    285 
    286 }  // namespace chromeos
    287