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