device_oauth2_token_service.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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 10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/bind.h" 11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/memory/weak_ptr.h" 12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/message_loop/message_loop.h" 13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/prefs/pref_registry_simple.h" 14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/prefs/pref_service.h" 15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/values.h" 16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/browser_process.h" 17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/chromeos/settings/cros_settings.h" 184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/chromeos/settings/token_encryptor.h" 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/pref_names.h" 20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chromeos/cryptohome/system_salt_getter.h" 21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "google_apis/gaia/gaia_constants.h" 22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "google_apis/gaia/gaia_urls.h" 23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "google_apis/gaia/google_service_auth_error.h" 24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h" 25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "policy/proto/device_management_backend.pb.h" 26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace chromeos { 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)struct DeviceOAuth2TokenService::PendingRequest { 30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) PendingRequest(const base::WeakPtr<RequestImpl>& request, 31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const std::string& client_id, 32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const std::string& client_secret, 33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const ScopeSet& scopes) 34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) : request(request), 35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) client_id(client_id), 36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) client_secret(client_secret), 37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scopes(scopes) {} 38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const base::WeakPtr<RequestImpl> request; 40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const std::string client_id; 41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const std::string client_secret; 42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const ScopeSet scopes; 43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}; 44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)DeviceOAuth2TokenService::DeviceOAuth2TokenService( 46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) net::URLRequestContextGetter* getter, 47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) PrefService* local_state) 48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) : url_request_context_getter_(getter), 49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) local_state_(local_state), 50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state_(STATE_LOADING), 51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) max_refresh_token_validation_retries_(3), 52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) weak_ptr_factory_(this) { 53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Pull in the system salt. 54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SystemSaltGetter::Get()->GetSystemSalt( 55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::Bind(&DeviceOAuth2TokenService::DidGetSystemSalt, 56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr())); 57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)DeviceOAuth2TokenService::~DeviceOAuth2TokenService() { 60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FlushPendingRequests(false, GoogleServiceAuthError::REQUEST_CANCELED); 61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FlushTokenSaveCallbacks(false); 62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// static 65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::RegisterPrefs(PrefRegistrySimple* registry) { 66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) registry->RegisterStringPref(prefs::kDeviceRobotAnyApiRefreshToken, 67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::string()); 68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::SetAndSaveRefreshToken( 71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const std::string& refresh_token, 72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const StatusCallback& result_callback) { 73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FlushPendingRequests(false, GoogleServiceAuthError::REQUEST_CANCELED); 74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool waiting_for_salt = state_ == STATE_LOADING; 76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) refresh_token_ = refresh_token; 77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state_ = STATE_VALIDATION_PENDING; 78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FireRefreshTokenAvailable(GetRobotAccountId()); 79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) token_save_callbacks_.push_back(result_callback); 81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!waiting_for_salt) { 82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (system_salt_.empty()) 83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FlushTokenSaveCallbacks(false); 84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) else 85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EncryptAndSaveToken(); 86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool DeviceOAuth2TokenService::RefreshTokenIsAvailable( 90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const std::string& account_id) const { 91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) switch (state_) { 92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case STATE_NO_TOKEN: 93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case STATE_TOKEN_INVALID: 94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case STATE_LOADING: 96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case STATE_VALIDATION_PENDING: 97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case STATE_VALIDATION_STARTED: 98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case STATE_TOKEN_VALID: 99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return account_id == GetRobotAccountId(); 100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) NOTREACHED() << "Unhandled state " << state_; 103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)std::string DeviceOAuth2TokenService::GetRobotAccountId() const { 107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::string result; 108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CrosSettings::Get()->GetString(kServiceAccountIdentity, &result); 109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return result; 110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::OnRefreshTokenResponse( 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& access_token, 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int expires_in_seconds) { 115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch gaia_oauth_client_->GetTokenInfo( 116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch access_token, 117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) max_refresh_token_validation_retries_, 118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch this); 119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::OnGetTokenInfoResponse( 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<base::DictionaryValue> token_info) { 123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string gaia_robot_id; 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch token_info->GetString("email", &gaia_robot_id); 125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gaia_oauth_client_.reset(); 126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CheckRobotAccountId(gaia_robot_id); 128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::OnOAuthError() { 131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gaia_oauth_client_.reset(); 132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state_ = STATE_TOKEN_INVALID; 133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FlushPendingRequests(false, GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::OnNetworkError(int response_code) { 137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gaia_oauth_client_.reset(); 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Go back to pending validation state. That'll allow a retry on subsequent 140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // token minting requests. 141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state_ = STATE_VALIDATION_PENDING; 142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FlushPendingRequests(false, GoogleServiceAuthError::CONNECTION_FAILED); 143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)std::string DeviceOAuth2TokenService::GetRefreshToken( 146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const std::string& account_id) const { 147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) switch (state_) { 148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case STATE_LOADING: 149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case STATE_NO_TOKEN: 150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case STATE_TOKEN_INVALID: 151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // This shouldn't happen: GetRefreshToken() is only called for actual 152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // token minting operations. In above states, requests are either queued 153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // or short-circuited to signal error immediately, so no actual token 154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // minting via OAuth2TokenService::FetchOAuth2Token should be triggered. 155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) NOTREACHED(); 156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return std::string(); 157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case STATE_VALIDATION_PENDING: 158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case STATE_VALIDATION_STARTED: 159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case STATE_TOKEN_VALID: 160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return refresh_token_; 161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) NOTREACHED() << "Unhandled state " << state_; 164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return std::string(); 165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)net::URLRequestContextGetter* DeviceOAuth2TokenService::GetRequestContext() { 168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return url_request_context_getter_.get(); 169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::FetchOAuth2Token( 172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) RequestImpl* request, 173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const std::string& account_id, 174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) net::URLRequestContextGetter* getter, 175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const std::string& client_id, 176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const std::string& client_secret, 177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const ScopeSet& scopes) { 178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) switch (state_) { 179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case STATE_VALIDATION_PENDING: 180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // If this is the first request for a token, start validation. 181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) StartValidation(); 182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // fall through. 183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case STATE_LOADING: 184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case STATE_VALIDATION_STARTED: 185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Add a pending request that will be satisfied once validation completes. 186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) pending_requests_.push_back(new PendingRequest( 187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) request->AsWeakPtr(), client_id, client_secret, scopes)); 188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case STATE_NO_TOKEN: 190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FailRequest(request, GoogleServiceAuthError::USER_NOT_SIGNED_UP); 191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case STATE_TOKEN_INVALID: 193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FailRequest(request, GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); 194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case STATE_TOKEN_VALID: 196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Pass through to OAuth2TokenService to satisfy the request. 197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) OAuth2TokenService::FetchOAuth2Token( 198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) request, account_id, getter, client_id, client_secret, scopes); 199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) NOTREACHED() << "Unexpected state " << state_; 203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)OAuth2AccessTokenFetcher* DeviceOAuth2TokenService::CreateAccessTokenFetcher( 206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const std::string& account_id, 207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) net::URLRequestContextGetter* getter, 208a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) OAuth2AccessTokenConsumer* consumer) { 209a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::string refresh_token = GetRefreshToken(account_id); 210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(!refresh_token.empty()); 211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return new OAuth2AccessTokenFetcherImpl(consumer, getter, refresh_token); 212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::DidGetSystemSalt( 216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const std::string& system_salt) { 217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) system_salt_ = system_salt; 218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Bail out if system salt is not available. 220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (system_salt_.empty()) { 221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) LOG(ERROR) << "Failed to get system salt."; 222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FlushTokenSaveCallbacks(false); 223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state_ = STATE_NO_TOKEN; 224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FireRefreshTokensLoaded(); 225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // If the token has been set meanwhile, write it to |local_state_|. 229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!refresh_token_.empty()) { 230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) EncryptAndSaveToken(); 231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FireRefreshTokensLoaded(); 232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 235a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Otherwise, load the refresh token from |local_state_|. 236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::string encrypted_refresh_token = 237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) local_state_->GetString(prefs::kDeviceRobotAnyApiRefreshToken); 238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CryptohomeTokenEncryptor encryptor(system_salt_); 239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) refresh_token_ = encryptor.DecryptWithSystemSalt(encrypted_refresh_token); 240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!encrypted_refresh_token.empty() && refresh_token_.empty()) { 241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) LOG(ERROR) << "Failed to decrypt refresh token."; 242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state_ = STATE_NO_TOKEN; 243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FireRefreshTokensLoaded(); 244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state_ = STATE_VALIDATION_PENDING; 248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // If there are pending requests, start a validation. 250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!pending_requests_.empty()) 251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) StartValidation(); 252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Announce the token. 254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FireRefreshTokenAvailable(GetRobotAccountId()); 255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FireRefreshTokensLoaded(); 256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::CheckRobotAccountId( 259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const std::string& gaia_robot_id) { 260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Make sure the value returned by GetRobotAccountId has been validated 261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // against current device settings. 262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) switch (CrosSettings::Get()->PrepareTrustedValues( 263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::Bind(&DeviceOAuth2TokenService::CheckRobotAccountId, 264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 265a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gaia_robot_id))) { 266a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case CrosSettingsProvider::TRUSTED: 267a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // All good, compare account ids below. 268a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) break; 269a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case CrosSettingsProvider::TEMPORARILY_UNTRUSTED: 270a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // The callback passed to PrepareTrustedValues above will trigger a 271a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // re-check eventually. 272a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case CrosSettingsProvider::PERMANENTLY_UNTRUSTED: 274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // There's no trusted account id, which is equivalent to no token present. 275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) LOG(WARNING) << "Device settings permanently untrusted."; 276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state_ = STATE_NO_TOKEN; 277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FlushPendingRequests(false, GoogleServiceAuthError::USER_NOT_SIGNED_UP); 278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 279a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 280a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 281a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::string policy_robot_id = GetRobotAccountId(); 282a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (policy_robot_id == gaia_robot_id) { 283a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state_ = STATE_TOKEN_VALID; 284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FlushPendingRequests(true, GoogleServiceAuthError::NONE); 285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (gaia_robot_id.empty()) { 287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) LOG(WARNING) << "Device service account owner in policy is empty."; 288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) LOG(WARNING) << "Device service account owner in policy does not match " 290a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) << "refresh token owner \"" << gaia_robot_id << "\"."; 291a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 292a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state_ = STATE_TOKEN_INVALID; 293a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FlushPendingRequests(false, 294a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); 295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::EncryptAndSaveToken() { 299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK_NE(state_, STATE_LOADING); 3004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CryptohomeTokenEncryptor encryptor(system_salt_); 302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::string encrypted_refresh_token = 303a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) encryptor.EncryptWithSystemSalt(refresh_token_); 304a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool result = true; 3051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (encrypted_refresh_token.empty()) { 3061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) LOG(ERROR) << "Failed to encrypt refresh token; save aborted."; 307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) result = false; 308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 309a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) local_state_->SetString(prefs::kDeviceRobotAnyApiRefreshToken, 310a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) encrypted_refresh_token); 3111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 313a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FlushTokenSaveCallbacks(result); 314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 316a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::StartValidation() { 317a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK_EQ(state_, STATE_VALIDATION_PENDING); 318a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(!gaia_oauth_client_); 319a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 320a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state_ = STATE_VALIDATION_STARTED; 321a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 322a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gaia_oauth_client_.reset(new gaia::GaiaOAuthClient( 323a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) g_browser_process->system_request_context())); 324a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 325a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GaiaUrls* gaia_urls = GaiaUrls::GetInstance(); 326a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gaia::OAuthClientInfo client_info; 327a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) client_info.client_id = gaia_urls->oauth2_chrome_client_id(); 328a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) client_info.client_secret = gaia_urls->oauth2_chrome_client_secret(); 329a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 330a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gaia_oauth_client_->RefreshToken( 331a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) client_info, 332a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) refresh_token_, 333a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::vector<std::string>(1, GaiaConstants::kOAuthWrapBridgeUserInfoScope), 334a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) max_refresh_token_validation_retries_, 335a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) this); 336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 338a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::FlushPendingRequests( 339a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool token_is_valid, 340a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GoogleServiceAuthError::State error) { 341a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::vector<PendingRequest*> requests; 342a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) requests.swap(pending_requests_); 343a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (std::vector<PendingRequest*>::iterator request(requests.begin()); 344a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) request != requests.end(); 345a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ++request) { 346a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_ptr<PendingRequest> scoped_request(*request); 347a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!scoped_request->request) 348a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) continue; 349a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 350a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (token_is_valid) { 351a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) OAuth2TokenService::FetchOAuth2Token( 352a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_request->request.get(), 353a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_request->request->GetAccountId(), 354a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GetRequestContext(), 355a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_request->client_id, 356a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_request->client_secret, 357a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_request->scopes); 358a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 359a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FailRequest(scoped_request->request.get(), error); 360a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 361a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 362eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 363eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 364a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::FlushTokenSaveCallbacks(bool result) { 365a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::vector<StatusCallback> callbacks; 366a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) callbacks.swap(token_save_callbacks_); 367a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (std::vector<StatusCallback>::iterator callback(callbacks.begin()); 368a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) callback != callbacks.end(); 369a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ++callback) { 370a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!callback->is_null()) 371a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) callback->Run(result); 372a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 3733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)} 3743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 375a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::FailRequest( 376a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) RequestImpl* request, 377a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GoogleServiceAuthError::State error) { 378a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GoogleServiceAuthError auth_error(error); 379a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 380a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) &RequestImpl::InformConsumer, 381a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) request->AsWeakPtr(), 382a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) auth_error, 383a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::string(), 384a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::Time())); 38568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 38668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace chromeos 388