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); 238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!encrypted_refresh_token.empty()) { 239116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch CryptohomeTokenEncryptor encryptor(system_salt_); 240116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch refresh_token_ = encryptor.DecryptWithSystemSalt(encrypted_refresh_token); 241116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (refresh_token_.empty()) { 242116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch LOG(ERROR) << "Failed to decrypt refresh token."; 243116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch state_ = STATE_NO_TOKEN; 244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch FireRefreshTokensLoaded(); 245116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return; 246116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state_ = STATE_VALIDATION_PENDING; 250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // If there are pending requests, start a validation. 252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!pending_requests_.empty()) 253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) StartValidation(); 254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Announce the token. 256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FireRefreshTokenAvailable(GetRobotAccountId()); 257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FireRefreshTokensLoaded(); 258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::CheckRobotAccountId( 261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const std::string& gaia_robot_id) { 262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Make sure the value returned by GetRobotAccountId has been validated 263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // against current device settings. 264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) switch (CrosSettings::Get()->PrepareTrustedValues( 265a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::Bind(&DeviceOAuth2TokenService::CheckRobotAccountId, 266a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 267a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gaia_robot_id))) { 268a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case CrosSettingsProvider::TRUSTED: 269a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // All good, compare account ids below. 270a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) break; 271a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case CrosSettingsProvider::TEMPORARILY_UNTRUSTED: 272a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // The callback passed to PrepareTrustedValues above will trigger a 273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // re-check eventually. 274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case CrosSettingsProvider::PERMANENTLY_UNTRUSTED: 276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // There's no trusted account id, which is equivalent to no token present. 277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) LOG(WARNING) << "Device settings permanently untrusted."; 278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state_ = STATE_NO_TOKEN; 279a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FlushPendingRequests(false, GoogleServiceAuthError::USER_NOT_SIGNED_UP); 280a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 281a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 282a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 283a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::string policy_robot_id = GetRobotAccountId(); 284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (policy_robot_id == gaia_robot_id) { 285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state_ = STATE_TOKEN_VALID; 286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FlushPendingRequests(true, GoogleServiceAuthError::NONE); 287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (gaia_robot_id.empty()) { 289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) LOG(WARNING) << "Device service account owner in policy is empty."; 290a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 291a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) LOG(WARNING) << "Device service account owner in policy does not match " 292a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) << "refresh token owner \"" << gaia_robot_id << "\"."; 293a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 294a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state_ = STATE_TOKEN_INVALID; 295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FlushPendingRequests(false, 296a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); 297a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::EncryptAndSaveToken() { 301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK_NE(state_, STATE_LOADING); 3024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 303a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CryptohomeTokenEncryptor encryptor(system_salt_); 304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::string encrypted_refresh_token = 305a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) encryptor.EncryptWithSystemSalt(refresh_token_); 306a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool result = true; 3071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (encrypted_refresh_token.empty()) { 3081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) LOG(ERROR) << "Failed to encrypt refresh token; save aborted."; 309a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) result = false; 310a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 311a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) local_state_->SetString(prefs::kDeviceRobotAnyApiRefreshToken, 312a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) encrypted_refresh_token); 3131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 315a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FlushTokenSaveCallbacks(result); 316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 318a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::StartValidation() { 319a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK_EQ(state_, STATE_VALIDATION_PENDING); 320a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(!gaia_oauth_client_); 321a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 322a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) state_ = STATE_VALIDATION_STARTED; 323a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 324a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gaia_oauth_client_.reset(new gaia::GaiaOAuthClient( 325a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) g_browser_process->system_request_context())); 326a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 327a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GaiaUrls* gaia_urls = GaiaUrls::GetInstance(); 328a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gaia::OAuthClientInfo client_info; 329a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) client_info.client_id = gaia_urls->oauth2_chrome_client_id(); 330a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) client_info.client_secret = gaia_urls->oauth2_chrome_client_secret(); 331a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 332a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gaia_oauth_client_->RefreshToken( 333a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) client_info, 334a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) refresh_token_, 335a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::vector<std::string>(1, GaiaConstants::kOAuthWrapBridgeUserInfoScope), 336a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) max_refresh_token_validation_retries_, 337a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) this); 338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 340a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::FlushPendingRequests( 341a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool token_is_valid, 342a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GoogleServiceAuthError::State error) { 343a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::vector<PendingRequest*> requests; 344a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) requests.swap(pending_requests_); 345a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (std::vector<PendingRequest*>::iterator request(requests.begin()); 346a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) request != requests.end(); 347a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ++request) { 348a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_ptr<PendingRequest> scoped_request(*request); 349a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!scoped_request->request) 350a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) continue; 351a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 352a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (token_is_valid) { 353a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) OAuth2TokenService::FetchOAuth2Token( 354a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_request->request.get(), 355a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_request->request->GetAccountId(), 356a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GetRequestContext(), 357a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_request->client_id, 358a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_request->client_secret, 359a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_request->scopes); 360a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 361a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FailRequest(scoped_request->request.get(), error); 362a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 363a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 364eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 365eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 366a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::FlushTokenSaveCallbacks(bool result) { 367a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::vector<StatusCallback> callbacks; 368a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) callbacks.swap(token_save_callbacks_); 369a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (std::vector<StatusCallback>::iterator callback(callbacks.begin()); 370a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) callback != callbacks.end(); 371a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ++callback) { 372a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!callback->is_null()) 373a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) callback->Run(result); 374a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 3753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)} 3763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 377a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DeviceOAuth2TokenService::FailRequest( 378a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) RequestImpl* request, 379a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GoogleServiceAuthError::State error) { 380a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GoogleServiceAuthError auth_error(error); 381a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 382a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) &RequestImpl::InformConsumer, 383a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) request->AsWeakPtr(), 384a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) auth_error, 385a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::string(), 386a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::Time())); 38768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 38868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace chromeos 390