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