Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(128)

Unified Diff: chrome/browser/chromeos/settings/device_oauth2_token_service.cc

Issue 1143323005: Refactor AO2TS to make it easier to componentize. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address final comments Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/settings/device_oauth2_token_service.cc
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
index 1dc6bde934c3f50fbc53cff2d0e33b5f09c50b46..fb3490e9daa4fa9c4e87e3be924a61fdeea02aac 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
@@ -12,18 +12,9 @@
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_registry_simple.h"
-#include "base/prefs/pref_service.h"
-#include "base/values.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/settings/token_encryptor.h"
+#include "base/time/time.h"
#include "chrome/common/pref_names.h"
-#include "chromeos/cryptohome/system_salt_getter.h"
-#include "chromeos/settings/cros_settings_names.h"
-#include "google_apis/gaia/gaia_constants.h"
-#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"
-#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
-#include "policy/proto/device_management_backend.pb.h"
namespace chromeos {
@@ -43,34 +34,24 @@ struct DeviceOAuth2TokenService::PendingRequest {
const ScopeSet scopes;
};
-void DeviceOAuth2TokenService::OnServiceAccountIdentityChanged() {
- if (!GetRobotAccountId().empty() && !refresh_token_.empty())
- FireRefreshTokenAvailable(GetRobotAccountId());
+void DeviceOAuth2TokenService::OnValidationCompleted(
+ GoogleServiceAuthError::State error) {
+ if (error == GoogleServiceAuthError::NONE)
+ FlushPendingRequests(true, GoogleServiceAuthError::NONE);
+ else
+ FlushPendingRequests(false, error);
}
DeviceOAuth2TokenService::DeviceOAuth2TokenService(
- net::URLRequestContextGetter* getter,
- PrefService* local_state)
- : url_request_context_getter_(getter),
- local_state_(local_state),
- state_(STATE_LOADING),
- max_refresh_token_validation_retries_(3),
- service_account_identity_subscription_(
- CrosSettings::Get()->AddSettingsObserver(
- kServiceAccountIdentity,
- base::Bind(
- &DeviceOAuth2TokenService::OnServiceAccountIdentityChanged,
- base::Unretained(this))).Pass()),
- weak_ptr_factory_(this) {
- // Pull in the system salt.
- SystemSaltGetter::Get()->GetSystemSalt(
- base::Bind(&DeviceOAuth2TokenService::DidGetSystemSalt,
- weak_ptr_factory_.GetWeakPtr()));
+ DeviceOAuth2TokenServiceDelegate* delegate)
+ : OAuth2TokenService(delegate),
+ delegate_(static_cast<DeviceOAuth2TokenServiceDelegate*>(delegate)) {
+ delegate_->SetValidationStatusDelegate(this);
}
DeviceOAuth2TokenService::~DeviceOAuth2TokenService() {
+ delegate_->SetValidationStatusDelegate(nullptr);
FlushPendingRequests(false, GoogleServiceAuthError::REQUEST_CANCELED);
- FlushTokenSaveCallbacks(false);
}
// static
@@ -82,107 +63,11 @@ void DeviceOAuth2TokenService::RegisterPrefs(PrefRegistrySimple* registry) {
void DeviceOAuth2TokenService::SetAndSaveRefreshToken(
const std::string& refresh_token,
const StatusCallback& result_callback) {
- FlushPendingRequests(false, GoogleServiceAuthError::REQUEST_CANCELED);
-
- bool waiting_for_salt = state_ == STATE_LOADING;
- refresh_token_ = refresh_token;
- state_ = STATE_VALIDATION_PENDING;
-
- // If the robot account ID is not available yet, do not announce the token. It
- // will be done from OnServiceAccountIdentityChanged() once the robot account
- // ID becomes available as well.
- if (!GetRobotAccountId().empty())
- FireRefreshTokenAvailable(GetRobotAccountId());
-
- token_save_callbacks_.push_back(result_callback);
- if (!waiting_for_salt) {
- if (system_salt_.empty())
- FlushTokenSaveCallbacks(false);
- else
- EncryptAndSaveToken();
- }
-}
-
-bool DeviceOAuth2TokenService::RefreshTokenIsAvailable(
- const std::string& account_id) const {
- switch (state_) {
- case STATE_NO_TOKEN:
- case STATE_TOKEN_INVALID:
- return false;
- case STATE_LOADING:
- case STATE_VALIDATION_PENDING:
- case STATE_VALIDATION_STARTED:
- case STATE_TOKEN_VALID:
- return account_id == GetRobotAccountId();
- }
-
- NOTREACHED() << "Unhandled state " << state_;
- return false;
+ delegate_->SetAndSaveRefreshToken(refresh_token, result_callback);
}
std::string DeviceOAuth2TokenService::GetRobotAccountId() const {
- std::string result;
- CrosSettings::Get()->GetString(kServiceAccountIdentity, &result);
- return result;
-}
-
-void DeviceOAuth2TokenService::OnRefreshTokenResponse(
- const std::string& access_token,
- int expires_in_seconds) {
- gaia_oauth_client_->GetTokenInfo(
- access_token,
- max_refresh_token_validation_retries_,
- this);
-}
-
-void DeviceOAuth2TokenService::OnGetTokenInfoResponse(
- scoped_ptr<base::DictionaryValue> token_info) {
- std::string gaia_robot_id;
- token_info->GetString("email", &gaia_robot_id);
- gaia_oauth_client_.reset();
-
- CheckRobotAccountId(gaia_robot_id);
-}
-
-void DeviceOAuth2TokenService::OnOAuthError() {
- gaia_oauth_client_.reset();
- state_ = STATE_TOKEN_INVALID;
- FlushPendingRequests(false, GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
-}
-
-void DeviceOAuth2TokenService::OnNetworkError(int response_code) {
- gaia_oauth_client_.reset();
-
- // Go back to pending validation state. That'll allow a retry on subsequent
- // token minting requests.
- state_ = STATE_VALIDATION_PENDING;
- FlushPendingRequests(false, GoogleServiceAuthError::CONNECTION_FAILED);
-}
-
-std::string DeviceOAuth2TokenService::GetRefreshToken(
- const std::string& account_id) const {
- switch (state_) {
- case STATE_LOADING:
- case STATE_NO_TOKEN:
- case STATE_TOKEN_INVALID:
- // This shouldn't happen: GetRefreshToken() is only called for actual
- // token minting operations. In above states, requests are either queued
- // or short-circuited to signal error immediately, so no actual token
- // minting via OAuth2TokenService::FetchOAuth2Token should be triggered.
- NOTREACHED();
- return std::string();
- case STATE_VALIDATION_PENDING:
- case STATE_VALIDATION_STARTED:
- case STATE_TOKEN_VALID:
- return refresh_token_;
- }
-
- NOTREACHED() << "Unhandled state " << state_;
- return std::string();
-}
-
-net::URLRequestContextGetter* DeviceOAuth2TokenService::GetRequestContext() {
- return url_request_context_getter_.get();
+ return delegate_->GetRobotAccountId();
}
void DeviceOAuth2TokenService::FetchOAuth2Token(
@@ -192,166 +77,32 @@ void DeviceOAuth2TokenService::FetchOAuth2Token(
const std::string& client_id,
const std::string& client_secret,
const ScopeSet& scopes) {
- switch (state_) {
- case STATE_VALIDATION_PENDING:
+ switch (delegate_->state_) {
+ case DeviceOAuth2TokenServiceDelegate::STATE_VALIDATION_PENDING:
// If this is the first request for a token, start validation.
- StartValidation();
+ delegate_->StartValidation();
// fall through.
- case STATE_LOADING:
- case STATE_VALIDATION_STARTED:
+ case DeviceOAuth2TokenServiceDelegate::STATE_LOADING:
+ case DeviceOAuth2TokenServiceDelegate::STATE_VALIDATION_STARTED:
// Add a pending request that will be satisfied once validation completes.
pending_requests_.push_back(new PendingRequest(
request->AsWeakPtr(), client_id, client_secret, scopes));
+ delegate_->RequestValidation();
return;
- case STATE_NO_TOKEN:
+ case DeviceOAuth2TokenServiceDelegate::STATE_NO_TOKEN:
FailRequest(request, GoogleServiceAuthError::USER_NOT_SIGNED_UP);
return;
- case STATE_TOKEN_INVALID:
+ case DeviceOAuth2TokenServiceDelegate::STATE_TOKEN_INVALID:
FailRequest(request, GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
return;
- case STATE_TOKEN_VALID:
+ case DeviceOAuth2TokenServiceDelegate::STATE_TOKEN_VALID:
// Pass through to OAuth2TokenService to satisfy the request.
OAuth2TokenService::FetchOAuth2Token(
request, account_id, getter, client_id, client_secret, scopes);
return;
}
- NOTREACHED() << "Unexpected state " << state_;
-}
-
-OAuth2AccessTokenFetcher* DeviceOAuth2TokenService::CreateAccessTokenFetcher(
- const std::string& account_id,
- net::URLRequestContextGetter* getter,
- OAuth2AccessTokenConsumer* consumer) {
- std::string refresh_token = GetRefreshToken(account_id);
- DCHECK(!refresh_token.empty());
- return new OAuth2AccessTokenFetcherImpl(consumer, getter, refresh_token);
-}
-
-
-void DeviceOAuth2TokenService::DidGetSystemSalt(
- const std::string& system_salt) {
- system_salt_ = system_salt;
-
- // Bail out if system salt is not available.
- if (system_salt_.empty()) {
- LOG(ERROR) << "Failed to get system salt.";
- FlushTokenSaveCallbacks(false);
- state_ = STATE_NO_TOKEN;
- FireRefreshTokensLoaded();
- return;
- }
-
- // If the token has been set meanwhile, write it to |local_state_|.
- if (!refresh_token_.empty()) {
- EncryptAndSaveToken();
- FireRefreshTokensLoaded();
- return;
- }
-
- // Otherwise, load the refresh token from |local_state_|.
- std::string encrypted_refresh_token =
- local_state_->GetString(prefs::kDeviceRobotAnyApiRefreshToken);
- if (!encrypted_refresh_token.empty()) {
- CryptohomeTokenEncryptor encryptor(system_salt_);
- refresh_token_ = encryptor.DecryptWithSystemSalt(encrypted_refresh_token);
- if (refresh_token_.empty()) {
- LOG(ERROR) << "Failed to decrypt refresh token.";
- state_ = STATE_NO_TOKEN;
- FireRefreshTokensLoaded();
- return;
- }
- }
-
- state_ = STATE_VALIDATION_PENDING;
-
- // If there are pending requests, start a validation.
- if (!pending_requests_.empty())
- StartValidation();
-
- // Announce the token.
- FireRefreshTokenAvailable(GetRobotAccountId());
- FireRefreshTokensLoaded();
-}
-
-void DeviceOAuth2TokenService::CheckRobotAccountId(
- const std::string& gaia_robot_id) {
- // Make sure the value returned by GetRobotAccountId has been validated
- // against current device settings.
- switch (CrosSettings::Get()->PrepareTrustedValues(base::Bind(
- &DeviceOAuth2TokenService::CheckRobotAccountId,
- weak_ptr_factory_.GetWeakPtr(),
- gaia_robot_id))) {
- case CrosSettingsProvider::TRUSTED:
- // All good, compare account ids below.
- break;
- case CrosSettingsProvider::TEMPORARILY_UNTRUSTED:
- // The callback passed to PrepareTrustedValues above will trigger a
- // re-check eventually.
- return;
- case CrosSettingsProvider::PERMANENTLY_UNTRUSTED:
- // There's no trusted account id, which is equivalent to no token present.
- LOG(WARNING) << "Device settings permanently untrusted.";
- state_ = STATE_NO_TOKEN;
- FlushPendingRequests(false, GoogleServiceAuthError::USER_NOT_SIGNED_UP);
- return;
- }
-
- std::string policy_robot_id = GetRobotAccountId();
- if (policy_robot_id == gaia_robot_id) {
- state_ = STATE_TOKEN_VALID;
- FlushPendingRequests(true, GoogleServiceAuthError::NONE);
- } else {
- if (gaia_robot_id.empty()) {
- LOG(WARNING) << "Device service account owner in policy is empty.";
- } else {
- LOG(WARNING) << "Device service account owner in policy does not match "
- << "refresh token owner \"" << gaia_robot_id << "\".";
- }
- state_ = STATE_TOKEN_INVALID;
- FlushPendingRequests(false,
- GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
- }
-}
-
-void DeviceOAuth2TokenService::EncryptAndSaveToken() {
- DCHECK_NE(state_, STATE_LOADING);
-
- CryptohomeTokenEncryptor encryptor(system_salt_);
- std::string encrypted_refresh_token =
- encryptor.EncryptWithSystemSalt(refresh_token_);
- bool result = true;
- if (encrypted_refresh_token.empty()) {
- LOG(ERROR) << "Failed to encrypt refresh token; save aborted.";
- result = false;
- } else {
- local_state_->SetString(prefs::kDeviceRobotAnyApiRefreshToken,
- encrypted_refresh_token);
- }
-
- FlushTokenSaveCallbacks(result);
-}
-
-void DeviceOAuth2TokenService::StartValidation() {
- DCHECK_EQ(state_, STATE_VALIDATION_PENDING);
- DCHECK(!gaia_oauth_client_);
-
- state_ = STATE_VALIDATION_STARTED;
-
- gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(
- g_browser_process->system_request_context()));
-
- GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
- gaia::OAuthClientInfo client_info;
- client_info.client_id = gaia_urls->oauth2_chrome_client_id();
- client_info.client_secret = gaia_urls->oauth2_chrome_client_secret();
-
- gaia_oauth_client_->RefreshToken(
- client_info,
- refresh_token_,
- std::vector<std::string>(1, GaiaConstants::kOAuthWrapBridgeUserInfoScope),
- max_refresh_token_validation_retries_,
- this);
+ NOTREACHED() << "Unexpected state " << delegate_->state_;
}
void DeviceOAuth2TokenService::FlushPendingRequests(
@@ -370,27 +121,14 @@ void DeviceOAuth2TokenService::FlushPendingRequests(
OAuth2TokenService::FetchOAuth2Token(
scoped_request->request.get(),
scoped_request->request->GetAccountId(),
- GetRequestContext(),
- scoped_request->client_id,
- scoped_request->client_secret,
- scoped_request->scopes);
+ delegate_->GetRequestContext(), scoped_request->client_id,
+ scoped_request->client_secret, scoped_request->scopes);
} else {
FailRequest(scoped_request->request.get(), error);
}
}
}
-void DeviceOAuth2TokenService::FlushTokenSaveCallbacks(bool result) {
- std::vector<StatusCallback> callbacks;
- callbacks.swap(token_save_callbacks_);
- for (std::vector<StatusCallback>::iterator callback(callbacks.begin());
- callback != callbacks.end();
- ++callback) {
- if (!callback->is_null())
- callback->Run(result);
- }
-}
-
void DeviceOAuth2TokenService::FailRequest(
RequestImpl* request,
GoogleServiceAuthError::State error) {

Powered by Google App Engine
This is Rietveld 408576698