Enable DeviceOAuth2TokenService on desktop platforms
This change adds a desktop (win/linux/mac) implementation of
DeviceOAuth2TokenStore, and enables compilation of
DeviceOAuth2TokenService (and related classes) on desktop platforms.
This should allow getting and storing a refresh token for the service
account passed to the browser through the Chrome Policy data. See
go/cbcm-machine-policy-invalidations for context about this change.
Bug: 1026261
Change-Id: I44a1f7fe30640dec0886cbe881a4f5a335c23fa2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2067624
Commit-Queue: anthonyvd <[email protected]>
Reviewed-by: Mihai Sardarescu <[email protected]>
Reviewed-by: Gabriel Charette <[email protected]>
Reviewed-by: Rebekah Potter <[email protected]>
Reviewed-by: Marc Treib <[email protected]>
Reviewed-by: Pavol Marko <[email protected]>
Reviewed-by: Julian Pastarmov <[email protected]>
Cr-Commit-Position: refs/heads/master@{#752973}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index c4117c7..f97a214 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3144,6 +3144,13 @@
"component_updater/intervention_policy_database_component_installer.h",
"custom_handlers/register_protocol_handler_permission_request.cc",
"custom_handlers/register_protocol_handler_permission_request.h",
+ "device_identity/device_identity_provider.cc",
+ "device_identity/device_identity_provider.h",
+ "device_identity/device_oauth2_token_service.cc",
+ "device_identity/device_oauth2_token_service.h",
+ "device_identity/device_oauth2_token_service_factory.cc",
+ "device_identity/device_oauth2_token_service_factory.h",
+ "device_identity/device_oauth2_token_store.h",
"diagnostics/diagnostics_controller.cc",
"diagnostics/diagnostics_controller.h",
"diagnostics/diagnostics_metrics.cc",
@@ -3829,13 +3836,6 @@
"component_updater/smart_dim_component_installer.h",
"device_identity/chromeos/device_oauth2_token_store_chromeos.cc",
"device_identity/chromeos/device_oauth2_token_store_chromeos.h",
- "device_identity/device_identity_provider.cc",
- "device_identity/device_identity_provider.h",
- "device_identity/device_oauth2_token_service.cc",
- "device_identity/device_oauth2_token_service.h",
- "device_identity/device_oauth2_token_service_factory.cc",
- "device_identity/device_oauth2_token_service_factory.h",
- "device_identity/device_oauth2_token_store.h",
"download/notification/download_item_notification.cc",
"download/notification/download_item_notification.h",
"download/notification/download_notification_manager.cc",
@@ -4319,6 +4319,8 @@
if (!is_android && !is_chromeos) {
sources += [
+ "device_identity/device_oauth2_token_store_desktop.cc",
+ "device_identity/device_oauth2_token_store_desktop.h",
"first_run/upgrade_util.cc",
"first_run/upgrade_util.h",
"first_run/upgrade_util_mac.cc",
diff --git a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc
index aec7111..c31f521 100644
--- a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc
+++ b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc
@@ -428,9 +428,8 @@
DCHECK(url_loader_factory);
}
- device_identity_provider_ =
- std::make_unique<chromeos::DeviceIdentityProvider>(
- chromeos::DeviceOAuth2TokenServiceFactory::Get());
+ device_identity_provider_ = std::make_unique<DeviceIdentityProvider>(
+ DeviceOAuth2TokenServiceFactory::Get());
device_instance_id_driver_ = std::make_unique<instance_id::InstanceIDDriver>(
g_browser_process->gcm_driver());
diff --git a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
index 2820239..2fb1a80 100644
--- a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
+++ b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
@@ -221,7 +221,7 @@
chromeos::CryptohomeClient::InitializeFake();
ASSERT_TRUE(profile_manager_.SetUp());
- chromeos::DeviceOAuth2TokenServiceFactory::Initialize(
+ DeviceOAuth2TokenServiceFactory::Initialize(
test_url_loader_factory_.GetSafeWeakWrapper(),
TestingBrowserProcess::GetGlobal()->local_state());
@@ -240,7 +240,7 @@
invalidation::ProfileInvalidationProviderFactory::GetInstance()
->RegisterTestingFactory(
BrowserContextKeyedServiceFactory::TestingFactory());
- chromeos::DeviceOAuth2TokenServiceFactory::Shutdown();
+ DeviceOAuth2TokenServiceFactory::Shutdown();
chromeos::CryptohomeClient::Shutdown();
chromeos::SystemSaltGetter::Shutdown();
}
diff --git a/chrome/browser/chromeos/policy/device_account_initializer.cc b/chrome/browser/chromeos/policy/device_account_initializer.cc
index 97a11dfb..b395d56 100644
--- a/chrome/browser/chromeos/policy/device_account_initializer.cc
+++ b/chrome/browser/chromeos/policy/device_account_initializer.cc
@@ -138,7 +138,7 @@
void DeviceAccountInitializer::StoreToken() {
handling_request_ = true;
- chromeos::DeviceOAuth2TokenServiceFactory::Get()->SetAndSaveRefreshToken(
+ DeviceOAuth2TokenServiceFactory::Get()->SetAndSaveRefreshToken(
robot_refresh_token_,
base::AdaptCallbackForRepeating(base::BindOnce(
&DeviceAccountInitializer::HandleStoreRobotAuthTokenResult,
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
index f3989be1..ca5c339 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
@@ -184,7 +184,7 @@
// SystemSaltGetter is used in DeviceOAuth2TokenService.
chromeos::SystemSaltGetter::Initialize();
- chromeos::DeviceOAuth2TokenServiceFactory::Initialize(
+ DeviceOAuth2TokenServiceFactory::Initialize(
test_url_loader_factory_.GetSafeWeakWrapper(), &local_state_);
url_fetcher_response_code_ = net::HTTP_OK;
@@ -205,7 +205,7 @@
manager_.reset();
install_attributes_.reset();
- chromeos::DeviceOAuth2TokenServiceFactory::Shutdown();
+ DeviceOAuth2TokenServiceFactory::Shutdown();
chromeos::SystemSaltGetter::Shutdown();
TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
@@ -685,8 +685,8 @@
// Verify the state only if the task is not yet failed.
// Note that, if the flow is not yet |done_| here, assume that it is
// in the "succeeding" flow, so verify here, too.
- chromeos::DeviceOAuth2TokenService* token_service =
- chromeos::DeviceOAuth2TokenServiceFactory::Get();
+ DeviceOAuth2TokenService* token_service =
+ DeviceOAuth2TokenServiceFactory::Get();
// For the refresh token for the robot account to be visible, the robot
// account ID must not be empty.
diff --git a/chrome/browser/chromeos/policy/remote_commands/crd_host_delegate.cc b/chrome/browser/chromeos/policy/remote_commands/crd_host_delegate.cc
index 9d6a9c0..2f6efcf 100644
--- a/chrome/browser/chromeos/policy/remote_commands/crd_host_delegate.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/crd_host_delegate.cc
@@ -92,8 +92,7 @@
CRDHostDelegate::CRDHostDelegate()
: OAuth2AccessTokenManager::Consumer("crd_host_delegate") {}
-CRDHostDelegate::~CRDHostDelegate() {
-}
+CRDHostDelegate::~CRDHostDelegate() {}
bool CRDHostDelegate::HasActiveSession() const {
return host_ != nullptr;
@@ -108,7 +107,7 @@
return user_manager::UserManager::IsInitialized() &&
ui::UserActivityDetector::Get() != nullptr &&
chromeos::ProfileHelper::Get() != nullptr &&
- chromeos::DeviceOAuth2TokenServiceFactory::Get() != nullptr;
+ DeviceOAuth2TokenServiceFactory::Get() != nullptr;
}
bool CRDHostDelegate::IsRunningKiosk() const {
@@ -147,8 +146,8 @@
DeviceCommandStartCRDSessionJob::ErrorCallback error_callback) {
DCHECK(!oauth_success_callback_);
DCHECK(!error_callback_);
- chromeos::DeviceOAuth2TokenService* oauth_service =
- chromeos::DeviceOAuth2TokenServiceFactory::Get();
+ DeviceOAuth2TokenService* oauth_service =
+ DeviceOAuth2TokenServiceFactory::Get();
OAuth2AccessTokenManager::ScopeSet scopes;
scopes.insert(GaiaConstants::kGoogleUserInfoEmail);
@@ -196,7 +195,7 @@
// Store all parameters for future connect call.
base::Value connect_params(base::Value::Type::DICTIONARY);
CoreAccountId account_id =
- chromeos::DeviceOAuth2TokenServiceFactory::Get()->GetRobotAccountId();
+ DeviceOAuth2TokenServiceFactory::Get()->GetRobotAccountId();
// TODO(msarda): This conversion will not be correct once account id is
// migrated to be the Gaia ID on ChromeOS. Fix it.
diff --git a/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc b/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc
index b66d3f0..ac23eea 100644
--- a/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.cc
@@ -24,8 +24,7 @@
ScreenshotDelegate::ScreenshotDelegate() {}
-ScreenshotDelegate::~ScreenshotDelegate() {
-}
+ScreenshotDelegate::~ScreenshotDelegate() {}
bool ScreenshotDelegate::IsScreenshotAllowed() {
BrowserPolicyConnectorChromeOS* connector =
@@ -52,8 +51,8 @@
std::unique_ptr<UploadJob> ScreenshotDelegate::CreateUploadJob(
const GURL& upload_url,
UploadJob::Delegate* delegate) {
- chromeos::DeviceOAuth2TokenService* device_oauth2_token_service =
- chromeos::DeviceOAuth2TokenServiceFactory::Get();
+ DeviceOAuth2TokenService* device_oauth2_token_service =
+ DeviceOAuth2TokenServiceFactory::Get();
CoreAccountId robot_account_id =
device_oauth2_token_service->GetRobotAccountId();
diff --git a/chrome/browser/chromeos/policy/system_log_uploader.cc b/chrome/browser/chromeos/policy/system_log_uploader.cc
index 21f0f3f4..5f856ef5 100644
--- a/chrome/browser/chromeos/policy/system_log_uploader.cc
+++ b/chrome/browser/chromeos/policy/system_log_uploader.cc
@@ -205,8 +205,8 @@
std::unique_ptr<UploadJob> SystemLogDelegate::CreateUploadJob(
const GURL& upload_url,
UploadJob::Delegate* delegate) {
- chromeos::DeviceOAuth2TokenService* device_oauth2_token_service =
- chromeos::DeviceOAuth2TokenServiceFactory::Get();
+ DeviceOAuth2TokenService* device_oauth2_token_service =
+ DeviceOAuth2TokenServiceFactory::Get();
CoreAccountId robot_account_id =
device_oauth2_token_service->GetRobotAccountId();
diff --git a/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.cc b/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.cc
index ed8fb33..385af0e 100644
--- a/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.cc
+++ b/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.cc
@@ -9,6 +9,7 @@
#include "chrome/common/pref_names.h"
#include "chromeos/cryptohome/system_salt_getter.h"
#include "chromeos/settings/cros_settings_names.h"
+#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
namespace chromeos {
@@ -26,6 +27,13 @@
FlushTokenSaveCallbacks(false);
}
+// static
+void DeviceOAuth2TokenStoreChromeOS::RegisterPrefs(
+ PrefRegistrySimple* registry) {
+ registry->RegisterStringPref(prefs::kDeviceRobotAnyApiRefreshToken,
+ std::string());
+}
+
void DeviceOAuth2TokenStoreChromeOS::Init(InitCallback callback) {
state_ = State::INITIALIZING;
// Pull in the system salt.
@@ -51,7 +59,7 @@
// 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 (!GetAccountId().empty())
+ if (observer() && !GetAccountId().empty())
observer()->OnRefreshTokenAvailable();
token_save_callbacks_.push_back(std::move(callback));
@@ -151,7 +159,7 @@
}
void DeviceOAuth2TokenStoreChromeOS::OnServiceAccountIdentityChanged() {
- if (!GetAccountId().empty() && !refresh_token_.empty())
+ if (observer() && !GetAccountId().empty() && !refresh_token_.empty())
observer()->OnRefreshTokenAvailable();
}
diff --git a/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.h b/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.h
index 8023447..ec23125 100644
--- a/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.h
+++ b/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.h
@@ -9,6 +9,8 @@
#include "chrome/browser/chromeos/settings/cros_settings.h"
+class PrefRegistrySimple;
+
namespace chromeos {
// ChromeOS specific implementation of the DeviceOAuth2TokenStore interface used
@@ -25,6 +27,13 @@
explicit DeviceOAuth2TokenStoreChromeOS(PrefService* local_state);
~DeviceOAuth2TokenStoreChromeOS() override;
+ DeviceOAuth2TokenStoreChromeOS(const DeviceOAuth2TokenStoreChromeOS& other) =
+ delete;
+ DeviceOAuth2TokenStoreChromeOS& operator=(
+ const DeviceOAuth2TokenStoreChromeOS& other) = delete;
+
+ static void RegisterPrefs(PrefRegistrySimple* registry);
+
// DeviceOAuth2TokenStore:
void Init(InitCallback callback) override;
CoreAccountId GetAccountId() const override;
diff --git a/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos_unittest.cc b/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos_unittest.cc
new file mode 100644
index 0000000..f9eba7c
--- /dev/null
+++ b/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos_unittest.cc
@@ -0,0 +1,250 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.h"
+
+#include "base/run_loop.h"
+#include "base/task/thread_pool/thread_pool_instance.h"
+#include "base/test/bind_test_util.h"
+#include "chrome/browser/chromeos/policy/device_policy_builder.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/chromeos/settings/device_settings_service.h"
+#include "chrome/browser/chromeos/settings/scoped_testing_cros_settings.h"
+#include "chrome/browser/chromeos/settings/token_encryptor.h"
+#include "chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/scoped_testing_local_state.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chromeos/cryptohome/system_salt_getter.h"
+#include "chromeos/dbus/cryptohome/fake_cryptohome_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "chromeos/tpm/stub_install_attributes.h"
+#include "components/ownership/mock_owner_key_util.h"
+#include "content/public/test/browser_task_environment.h"
+#include "content/public/test/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+// Helper class for tests to wait until the store's init procedure is completed.
+class DeviceOAuth2TokenStoreInitWaiter {
+ public:
+ DeviceOAuth2TokenStoreInitWaiter() = default;
+ // The caller must ensure that the DeviceOAuth2TokenStoreInitWaiter outlives
+ // the callback it returns.
+ DeviceOAuth2TokenStore::InitCallback GetCallback() {
+ return base::BindOnce(&DeviceOAuth2TokenStoreInitWaiter::OnInit,
+ base::Unretained(this));
+ }
+ void Wait() { run_loop_.Run(); }
+ bool HasInitBeenCalled() { return init_called_; }
+ bool GetInitResult() {
+ CHECK(init_called_);
+ return init_result_;
+ }
+ bool GetValidationRequired() {
+ CHECK(init_called_);
+ return validation_required_;
+ }
+
+ private:
+ void OnInit(bool init_result, bool validation_required) {
+ ASSERT_FALSE(init_called_);
+ init_called_ = true;
+ init_result_ = init_result;
+ validation_required_ = validation_required;
+ run_loop_.Quit();
+ }
+ base::RunLoop run_loop_;
+ bool init_called_ = false;
+ bool init_result_ = false;
+ bool validation_required_ = false;
+};
+} // namespace
+
+class DeviceOAuth2TokenStoreChromeOSTest : public testing::Test {
+ public:
+ DeviceOAuth2TokenStoreChromeOSTest()
+ : scoped_testing_local_state_(TestingBrowserProcess::GetGlobal()) {}
+
+ void SetUp() override {
+ chromeos::CryptohomeClient::InitializeFake();
+ chromeos::FakeCryptohomeClient::Get()->SetServiceIsAvailable(true);
+ chromeos::FakeCryptohomeClient::Get()->set_system_salt(
+ chromeos::FakeCryptohomeClient::GetStubSystemSalt());
+
+ chromeos::SystemSaltGetter::Initialize();
+
+ scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util_(
+ new ownership::MockOwnerKeyUtil());
+ owner_key_util_->SetPublicKeyFromPrivateKey(
+ *device_policy_.GetSigningKey());
+ chromeos::DeviceSettingsService::Get()->SetSessionManager(
+ &session_manager_client_, owner_key_util_);
+ }
+
+ void TearDown() override {
+ base::ThreadPoolInstance::Get()->FlushForTesting();
+ chromeos::DeviceSettingsService::Get()->UnsetSessionManager();
+ chromeos::SystemSaltGetter::Shutdown();
+ chromeos::CryptohomeClient::Shutdown();
+ }
+
+ void SetUpDefaultValues() {
+ SetDeviceRefreshTokenInLocalState("device_refresh_token_4_test");
+ SetRobotAccountId("[email protected]");
+ }
+
+ void InitWithPendingSalt(chromeos::DeviceOAuth2TokenStoreChromeOS* store) {
+ chromeos::FakeCryptohomeClient::Get()->set_system_salt(
+ std::vector<uint8_t>());
+ chromeos::FakeCryptohomeClient::Get()->SetServiceIsAvailable(false);
+ store->Init(base::BindLambdaForTesting([](bool, bool) {}));
+ SetUpDefaultValues();
+ }
+
+ void InitStore(chromeos::DeviceOAuth2TokenStoreChromeOS* store) {
+ chromeos::FakeCryptohomeClient::Get()->set_system_salt(
+ std::vector<uint8_t>());
+ chromeos::FakeCryptohomeClient::Get()->SetServiceIsAvailable(false);
+
+ DeviceOAuth2TokenStoreInitWaiter init_waiter;
+ store->Init(init_waiter.GetCallback());
+
+ // Make the system salt available.
+ chromeos::FakeCryptohomeClient::Get()->set_system_salt(
+ chromeos::FakeCryptohomeClient::GetStubSystemSalt());
+ chromeos::FakeCryptohomeClient::Get()->SetServiceIsAvailable(true);
+
+ // Wait for init to complete before continuing with the test.
+ init_waiter.Wait();
+ }
+
+ void SetRobotAccountId(const std::string& account_id) {
+ device_policy_.policy_data().set_service_account_identity(account_id);
+ device_policy_.Build();
+ session_manager_client_.set_device_policy(device_policy_.GetBlob());
+ chromeos::DeviceSettingsService::Get()->Load();
+ content::RunAllTasksUntilIdle();
+ }
+
+ void SetDeviceRefreshTokenInLocalState(const std::string& refresh_token) {
+ scoped_testing_local_state_.Get()->SetUserPref(
+ prefs::kDeviceRobotAnyApiRefreshToken,
+ std::make_unique<base::Value>(refresh_token));
+ }
+
+ content::BrowserTaskEnvironment task_environment_;
+ ScopedTestingLocalState scoped_testing_local_state_;
+ chromeos::ScopedStubInstallAttributes scoped_stub_install_attributes_;
+ chromeos::ScopedTestDeviceSettingsService scoped_device_settings_service_;
+ chromeos::ScopedTestCrosSettings scoped_test_cros_settings_{
+ scoped_testing_local_state_.Get()};
+ chromeos::FakeSessionManagerClient session_manager_client_;
+ policy::DevicePolicyBuilder device_policy_;
+};
+
+TEST_F(DeviceOAuth2TokenStoreChromeOSTest, InitSuccessful) {
+ chromeos::FakeCryptohomeClient::Get()->set_system_salt(
+ std::vector<uint8_t>());
+ chromeos::FakeCryptohomeClient::Get()->SetServiceIsAvailable(false);
+
+ chromeos::DeviceOAuth2TokenStoreChromeOS store(
+ scoped_testing_local_state_.Get());
+
+ EXPECT_TRUE(store.GetAccountId().empty());
+ EXPECT_TRUE(store.GetRefreshToken().empty());
+
+ DeviceOAuth2TokenStoreInitWaiter init_waiter;
+ store.Init(init_waiter.GetCallback());
+
+ EXPECT_FALSE(init_waiter.HasInitBeenCalled());
+
+ // Make the system salt available.
+ chromeos::FakeCryptohomeClient::Get()->set_system_salt(
+ chromeos::FakeCryptohomeClient::GetStubSystemSalt());
+ chromeos::FakeCryptohomeClient::Get()->SetServiceIsAvailable(true);
+ init_waiter.Wait();
+
+ EXPECT_TRUE(init_waiter.HasInitBeenCalled());
+ EXPECT_TRUE(init_waiter.GetInitResult());
+ EXPECT_TRUE(init_waiter.GetValidationRequired());
+}
+
+TEST_F(DeviceOAuth2TokenStoreChromeOSTest, SaveToken) {
+ chromeos::DeviceOAuth2TokenStoreChromeOS store(
+ scoped_testing_local_state_.Get());
+
+ InitStore(&store);
+
+ store.SetAndSaveRefreshToken("test-token",
+ DeviceOAuth2TokenStore::StatusCallback());
+ EXPECT_EQ("test-token", store.GetRefreshToken());
+}
+
+TEST_F(DeviceOAuth2TokenStoreChromeOSTest, SaveEncryptedTokenEarly) {
+ chromeos::DeviceOAuth2TokenStoreChromeOS store(
+ scoped_testing_local_state_.Get());
+
+ // Set a new refresh token without the system salt available.
+ InitWithPendingSalt(&store);
+
+ store.SetAndSaveRefreshToken("test-token",
+ DeviceOAuth2TokenStore::StatusCallback());
+ EXPECT_EQ("test-token", store.GetRefreshToken());
+
+ // Make the system salt available.
+ chromeos::FakeCryptohomeClient::Get()->set_system_salt(
+ chromeos::FakeCryptohomeClient::GetStubSystemSalt());
+ chromeos::FakeCryptohomeClient::Get()->SetServiceIsAvailable(true);
+ base::RunLoop().RunUntilIdle();
+
+ // The original token should still be present.
+ EXPECT_EQ("test-token", store.GetRefreshToken());
+
+ // Reloading shouldn't change the token either.
+ chromeos::DeviceOAuth2TokenStoreChromeOS other_store(
+ scoped_testing_local_state_.Get());
+ InitStore(&other_store);
+
+ EXPECT_EQ("test-token", other_store.GetRefreshToken());
+}
+
+TEST_F(DeviceOAuth2TokenStoreChromeOSTest, DoNotAnnounceTokenWithoutAccountID) {
+ chromeos::DeviceOAuth2TokenStoreChromeOS store(
+ scoped_testing_local_state_.Get());
+ InitStore(&store);
+
+ class StoreObserver : public DeviceOAuth2TokenStore::Observer {
+ public:
+ using Callback = base::Callback<void()>;
+ explicit StoreObserver(Callback callback) : callback_(callback) {}
+
+ void OnRefreshTokenAvailable() override { callback_.Run(); }
+
+ Callback callback_;
+ };
+
+ auto callback_that_should_not_be_called =
+ base::BindRepeating([]() { FAIL(); });
+ StoreObserver observer_not_called(
+ std::move(callback_that_should_not_be_called));
+ store.SetObserver(&observer_not_called);
+
+ // Make a token available during enrollment. Verify that the token is not
+ // announced yet.
+ store.SetAndSaveRefreshToken("test-token",
+ DeviceOAuth2TokenStore::StatusCallback());
+
+ base::RunLoop run_loop;
+ auto callback_that_should_be_called_once =
+ base::BindRepeating([](base::RunLoop* loop) { loop->Quit(); }, &run_loop);
+ StoreObserver observer_called_once(
+ std::move(callback_that_should_be_called_once));
+ store.SetObserver(&observer_called_once);
+
+ // Also make the robot account ID available. Verify that the token is
+ // announced now.
+ SetRobotAccountId("[email protected]");
+ run_loop.Run();
+}
diff --git a/chrome/browser/device_identity/device_identity_provider.cc b/chrome/browser/device_identity/device_identity_provider.cc
index 34972082..dfed68a 100644
--- a/chrome/browser/device_identity/device_identity_provider.cc
+++ b/chrome/browser/device_identity/device_identity_provider.cc
@@ -7,8 +7,6 @@
#include "base/bind_helpers.h"
#include "chrome/browser/device_identity/device_oauth2_token_service.h"
-namespace chromeos {
-
namespace {
// An implementation of ActiveAccountAccessTokenFetcher that is backed by
@@ -83,7 +81,7 @@
}
DeviceIdentityProvider::DeviceIdentityProvider(
- chromeos::DeviceOAuth2TokenService* token_service)
+ DeviceOAuth2TokenService* token_service)
: token_service_(token_service) {
// TODO(blundell): Can |token_service_| ever actually be non-null?
if (token_service_) {
@@ -147,5 +145,3 @@
void DeviceIdentityProvider::OnRefreshTokenAvailable() {
ProcessRefreshTokenUpdateForAccount(GetActiveAccountId());
}
-
-} // namespace chromeos
diff --git a/chrome/browser/device_identity/device_identity_provider.h b/chrome/browser/device_identity/device_identity_provider.h
index b08fc9b..4660cbe 100644
--- a/chrome/browser/device_identity/device_identity_provider.h
+++ b/chrome/browser/device_identity/device_identity_provider.h
@@ -8,15 +8,12 @@
#include "base/macros.h"
#include "components/invalidation/public/identity_provider.h"
-namespace chromeos {
-
class DeviceOAuth2TokenService;
// Identity provider implementation backed by DeviceOAuth2TokenService.
class DeviceIdentityProvider : public invalidation::IdentityProvider {
public:
- explicit DeviceIdentityProvider(
- chromeos::DeviceOAuth2TokenService* token_service);
+ explicit DeviceIdentityProvider(DeviceOAuth2TokenService* token_service);
~DeviceIdentityProvider() override;
// IdentityProvider:
@@ -34,11 +31,9 @@
private:
void OnRefreshTokenAvailable();
- chromeos::DeviceOAuth2TokenService* token_service_;
+ DeviceOAuth2TokenService* token_service_;
DISALLOW_COPY_AND_ASSIGN(DeviceIdentityProvider);
};
-} // namespace chromeos
-
#endif // CHROME_BROWSER_DEVICE_IDENTITY_DEVICE_IDENTITY_PROVIDER_H_
diff --git a/chrome/browser/device_identity/device_oauth2_token_service.cc b/chrome/browser/device_identity/device_oauth2_token_service.cc
index b16712b..974dbe7 100644
--- a/chrome/browser/device_identity/device_oauth2_token_service.cc
+++ b/chrome/browser/device_identity/device_oauth2_token_service.cc
@@ -15,9 +15,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "chrome/browser/device_identity/device_oauth2_token_store.h"
-#include "chrome/common/pref_names.h"
#include "components/policy/proto/device_management_backend.pb.h"
-#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/gaia_urls.h"
@@ -27,8 +25,6 @@
#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
-namespace chromeos {
-
struct DeviceOAuth2TokenService::PendingRequest {
PendingRequest(
const base::WeakPtr<OAuth2AccessTokenManager::RequestImpl>& request,
@@ -65,12 +61,6 @@
FlushPendingRequests(false, GoogleServiceAuthError::REQUEST_CANCELED);
}
-// static
-void DeviceOAuth2TokenService::RegisterPrefs(PrefRegistrySimple* registry) {
- registry->RegisterStringPref(prefs::kDeviceRobotAnyApiRefreshToken,
- std::string());
-}
-
void DeviceOAuth2TokenService::SetAndSaveRefreshToken(
const std::string& refresh_token,
const StatusCallback& result_callback) {
@@ -137,6 +127,13 @@
return token_manager_.get();
}
+#if !defined(OS_CHROMEOS)
+void DeviceOAuth2TokenService::SetServiceAccountEmail(
+ const std::string& account_email) {
+ store_->SetAccountEmail(account_email);
+}
+#endif
+
void DeviceOAuth2TokenService::OnRefreshTokenResponse(
const std::string& access_token,
int expires_in_seconds) {
@@ -385,5 +382,3 @@
else
FlushPendingRequests(false, error);
}
-
-} // namespace chromeos
diff --git a/chrome/browser/device_identity/device_oauth2_token_service.h b/chrome/browser/device_identity/device_oauth2_token_service.h
index 15f1d19..60544ace 100644
--- a/chrome/browser/device_identity/device_oauth2_token_service.h
+++ b/chrome/browser/device_identity/device_oauth2_token_service.h
@@ -23,9 +23,6 @@
class OAuth2AccessTokenFetcher;
class OAuth2AccessTokenConsumer;
-class PrefRegistrySimple;
-
-namespace chromeos {
// DeviceOAuth2TokenService retrieves OAuth2 access tokens for a given
// set of scopes using the device-level OAuth2 any-api refresh token
@@ -45,8 +42,6 @@
void SetAndSaveRefreshToken(const std::string& refresh_token,
const StatusCallback& callback);
- static void RegisterPrefs(PrefRegistrySimple* registry);
-
// Pull the robot account ID from device policy.
CoreAccountId GetRobotAccountId() const;
@@ -79,6 +74,13 @@
OAuth2AccessTokenManager* GetAccessTokenManager();
+#if !defined(OS_CHROMEOS)
+ // Used on non-ChromeOS platforms to set the email associated with the
+ // current service account. On ChromeOS, this function isn't used because
+ // the service account identity comes from CrosSettings.
+ void SetServiceAccountEmail(const std::string& account_email);
+#endif
+
// Can be used to override the robot account ID for testing purposes. Most
// common use case is to easily inject a non-empty account ID to make the
// refresh token for the robot account visible via GetAccounts() and
@@ -194,6 +196,4 @@
DISALLOW_COPY_AND_ASSIGN(DeviceOAuth2TokenService);
};
-} // namespace chromeos
-
#endif // CHROME_BROWSER_DEVICE_IDENTITY_DEVICE_OAUTH2_TOKEN_SERVICE_H_
diff --git a/chrome/browser/device_identity/device_oauth2_token_service_factory.cc b/chrome/browser/device_identity/device_oauth2_token_service_factory.cc
index 1d4a6c83..a14ba71 100644
--- a/chrome/browser/device_identity/device_oauth2_token_service_factory.cc
+++ b/chrome/browser/device_identity/device_oauth2_token_service_factory.cc
@@ -6,19 +6,37 @@
#include <memory>
+#include "build/build_config.h"
#include "chrome/browser/chromeos/settings/token_encryptor.h"
+#if defined(OS_CHROMEOS)
#include "chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.h"
+#else
+#include "chrome/browser/device_identity/device_oauth2_token_store_desktop.h"
+#endif
#include "chrome/browser/device_identity/device_oauth2_token_service.h"
#include "chromeos/cryptohome/system_salt_getter.h"
+#include "components/policy/core/common/features.h"
#include "content/public/browser/browser_thread.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
-namespace chromeos {
-
namespace {
static DeviceOAuth2TokenService* g_device_oauth2_token_service_ = nullptr;
+std::unique_ptr<DeviceOAuth2TokenStore> CreatePlatformTokenStore(
+ PrefService* local_state) {
+#if defined(OS_CHROMEOS)
+ return std::make_unique<chromeos::DeviceOAuth2TokenStoreChromeOS>(
+ local_state);
+#elif defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
+ DCHECK(base::FeatureList::IsEnabled(policy::features::kCBCMServiceAccounts));
+ return std::make_unique<DeviceOAuth2TokenStoreDesktop>(local_state);
+#else
+ NOTREACHED();
+ return nullptr;
+#endif
+}
+
} // namespace
// static
@@ -34,8 +52,7 @@
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(!g_device_oauth2_token_service_);
g_device_oauth2_token_service_ = new DeviceOAuth2TokenService(
- url_loader_factory, std::unique_ptr<DeviceOAuth2TokenStore>(
- new DeviceOAuth2TokenStoreChromeOS(local_state)));
+ url_loader_factory, CreatePlatformTokenStore(local_state));
}
// static
@@ -46,5 +63,3 @@
g_device_oauth2_token_service_ = nullptr;
}
}
-
-} // namespace chromeos
diff --git a/chrome/browser/device_identity/device_oauth2_token_service_factory.h b/chrome/browser/device_identity/device_oauth2_token_service_factory.h
index 9dba99d..2b1c1731 100644
--- a/chrome/browser/device_identity/device_oauth2_token_service_factory.h
+++ b/chrome/browser/device_identity/device_oauth2_token_service_factory.h
@@ -17,8 +17,6 @@
class SharedURLLoaderFactory;
}
-namespace chromeos {
-
class DeviceOAuth2TokenService;
class DeviceOAuth2TokenServiceFactory {
@@ -51,6 +49,4 @@
DISALLOW_COPY_AND_ASSIGN(DeviceOAuth2TokenServiceFactory);
};
-} // namespace chromeos
-
#endif // CHROME_BROWSER_DEVICE_IDENTITY_DEVICE_OAUTH2_TOKEN_SERVICE_FACTORY_H_
diff --git a/chrome/browser/device_identity/device_oauth2_token_service_unittest.cc b/chrome/browser/device_identity/device_oauth2_token_service_unittest.cc
index 9087d92..90860b2 100644
--- a/chrome/browser/device_identity/device_oauth2_token_service_unittest.cc
+++ b/chrome/browser/device_identity/device_oauth2_token_service_unittest.cc
@@ -13,20 +13,9 @@
#include "base/run_loop.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/chromeos/policy/device_policy_builder.h"
-#include "chrome/browser/chromeos/settings/cros_settings.h"
-#include "chrome/browser/chromeos/settings/device_settings_service.h"
-#include "chrome/browser/chromeos/settings/scoped_testing_cros_settings.h"
-#include "chrome/browser/chromeos/settings/token_encryptor.h"
-#include "chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
-#include "chromeos/cryptohome/system_salt_getter.h"
-#include "chromeos/dbus/cryptohome/fake_cryptohome_client.h"
-#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
-#include "chromeos/tpm/stub_install_attributes.h"
-#include "components/ownership/mock_owner_key_util.h"
#include "components/prefs/testing_pref_service.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/browser_task_environment.h"
@@ -41,7 +30,64 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace chromeos {
+class MockDeviceOAuth2TokenStore : public DeviceOAuth2TokenStore {
+ public:
+ MockDeviceOAuth2TokenStore() = default;
+ ~MockDeviceOAuth2TokenStore() override = default;
+
+ // DeviceOAuth2TokenStore:
+ void Init(InitCallback callback) override {
+ pending_init_callback_ = std::move(callback);
+ }
+ CoreAccountId GetAccountId() const override { return account_id_; }
+ std::string GetRefreshToken() const override { return refresh_token_; }
+
+ void SetAndSaveRefreshToken(const std::string& refresh_token,
+ StatusCallback result_callback) override {
+ refresh_token_ = refresh_token;
+ pending_status_callback_ = std::move(result_callback);
+ }
+
+ void PrepareTrustedAccountId(TrustedAccountIdCallback callback) override {
+ pending_trusted_account_id_callback_ = std::move(callback);
+ TriggerTrustedAccountIdCallback(true);
+ }
+
+#if !defined(OS_CHROMEOS)
+ void SetAccountEmail(const std::string& account_email) override {
+ account_id_ = CoreAccountId::FromEmail(account_email);
+ }
+#endif
+
+ // Mock-specific functions:
+ void SetRefreshTokenForTesting(const std::string& token) {
+ refresh_token_ = token;
+ }
+
+ void SetAccountIdForTesting(CoreAccountId account_id) {
+ account_id_ = account_id;
+ }
+
+ void TriggerInitCallback(bool success, bool validation_required) {
+ std::move(pending_init_callback_).Run(success, validation_required);
+ }
+
+ void TriggerStatusCallback(bool success) {
+ std::move(pending_status_callback_).Run(success);
+ }
+
+ void TriggerTrustedAccountIdCallback(bool account_present) {
+ std::move(pending_trusted_account_id_callback_).Run(account_present);
+ }
+
+ private:
+ CoreAccountId account_id_;
+ std::string refresh_token_;
+
+ InitCallback pending_init_callback_;
+ StatusCallback pending_status_callback_;
+ TrustedAccountIdCallback pending_trusted_account_id_callback_;
+};
class DeviceOAuth2TokenServiceTest : public testing::Test {
public:
@@ -51,26 +97,16 @@
// Most tests just want a noop crypto impl with a dummy refresh token value in
// Local State (if the value is an empty string, it will be ignored).
void SetUpDefaultValues() {
- SetDeviceRefreshTokenInLocalState("device_refresh_token_4_test");
- SetRobotAccountId("[email protected]");
CreateService();
+ token_store_->SetRefreshTokenForTesting("device_refresh_token_4_test");
+ SetRobotAccountId("[email protected]");
AssertConsumerTokensAndErrors(0, 0);
- base::RunLoop().RunUntilIdle();
- }
-
- void SetUpWithPendingSalt() {
- FakeCryptohomeClient::Get()->set_system_salt(std::vector<uint8_t>());
- FakeCryptohomeClient::Get()->SetServiceIsAvailable(false);
- SetUpDefaultValues();
+ token_store_->TriggerInitCallback(true, true);
}
void SetRobotAccountId(const std::string& account_id) {
- device_policy_.policy_data().set_service_account_identity(account_id);
- device_policy_.Build();
- session_manager_client_.set_device_policy(device_policy_.GetBlob());
- DeviceSettingsService::Get()->Load();
- content::RunAllTasksUntilIdle();
+ token_store_->SetAccountIdForTesting(CoreAccountId::FromEmail(account_id));
}
std::unique_ptr<OAuth2AccessTokenManager::Request> StartTokenRequest() {
@@ -78,50 +114,27 @@
&consumer_);
}
- void SetUp() override {
- CryptohomeClient::InitializeFake();
- FakeCryptohomeClient::Get()->SetServiceIsAvailable(true);
- FakeCryptohomeClient::Get()->set_system_salt(
- FakeCryptohomeClient::GetStubSystemSalt());
-
- SystemSaltGetter::Initialize();
-
- scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util_(
- new ownership::MockOwnerKeyUtil());
- owner_key_util_->SetPublicKeyFromPrivateKey(
- *device_policy_.GetSigningKey());
- DeviceSettingsService::Get()->SetSessionManager(&session_manager_client_,
- owner_key_util_);
- }
+ void SetUp() override {}
void TearDown() override {
oauth2_service_.reset();
base::ThreadPoolInstance::Get()->FlushForTesting();
- DeviceSettingsService::Get()->UnsetSessionManager();
- SystemSaltGetter::Shutdown();
- CryptohomeClient::Shutdown();
base::RunLoop().RunUntilIdle();
}
+ MockDeviceOAuth2TokenStore* token_store() { return token_store_; }
+
void CreateService() {
+ auto store = std::make_unique<MockDeviceOAuth2TokenStore>();
+ token_store_ = store.get();
+
oauth2_service_.reset(new DeviceOAuth2TokenService(
- test_url_loader_factory_.GetSafeWeakWrapper(),
- std::unique_ptr<DeviceOAuth2TokenStore>(
- new DeviceOAuth2TokenStoreChromeOS(
- scoped_testing_local_state_.Get()))));
+ test_url_loader_factory_.GetSafeWeakWrapper(), std::move(store)));
oauth2_service_->max_refresh_token_validation_retries_ = 0;
oauth2_service_->GetAccessTokenManager()
->set_max_authorization_token_fetch_retries_for_testing(0);
}
- // Utility method to set a value in Local State for the device refresh token
- // (it must have a non-empty value or it won't be used).
- void SetDeviceRefreshTokenInLocalState(const std::string& refresh_token) {
- scoped_testing_local_state_.Get()->SetUserPref(
- prefs::kDeviceRobotAnyApiRefreshToken,
- std::make_unique<base::Value>(refresh_token));
- }
-
std::string GetValidTokenInfoResponse(const std::string& email) {
return "{ \"email\": \"" + email +
"\","
@@ -135,7 +148,6 @@
std::string GetRefreshToken() {
if (!RefreshTokenIsAvailable())
return std::string();
-
return oauth2_service_->GetRefreshToken();
}
@@ -175,17 +187,12 @@
};
content::BrowserTaskEnvironment task_environment_;
- ScopedStubInstallAttributes scoped_stub_install_attributes_;
ScopedTestingLocalState scoped_testing_local_state_;
- ScopedTestDeviceSettingsService scoped_device_settings_service_;
- ScopedTestCrosSettings scoped_test_cros_settings_{
- scoped_testing_local_state_.Get()};
network::TestURLLoaderFactory test_url_loader_factory_;
- FakeSessionManagerClient session_manager_client_;
- policy::DevicePolicyBuilder device_policy_;
std::unique_ptr<DeviceOAuth2TokenService, TokenServiceDeleter>
oauth2_service_;
TestingOAuth2AccessTokenManagerConsumer consumer_;
+ MockDeviceOAuth2TokenStore* token_store_;
};
void DeviceOAuth2TokenServiceTest::ReturnOAuthUrlFetchResults(
@@ -233,41 +240,6 @@
EXPECT_EQ(num_errors, consumer_.number_of_errors_);
}
-TEST_F(DeviceOAuth2TokenServiceTest, SaveEncryptedToken) {
- CreateService();
-
- // The token service won't report there being a token if the robot account ID
- // is not set, which would cause the expectation below to fail.
- SetRobotAccountId("[email protected]");
-
- oauth2_service_->SetAndSaveRefreshToken(
- "test-token", DeviceOAuth2TokenService::StatusCallback());
- EXPECT_EQ("test-token", GetRefreshToken());
-}
-
-TEST_F(DeviceOAuth2TokenServiceTest, SaveEncryptedTokenEarly) {
- // Set a new refresh token without the system salt available.
- SetUpWithPendingSalt();
-
- oauth2_service_->SetAndSaveRefreshToken(
- "test-token", DeviceOAuth2TokenService::StatusCallback());
- EXPECT_EQ("test-token", GetRefreshToken());
-
- // Make the system salt available.
- FakeCryptohomeClient::Get()->set_system_salt(
- FakeCryptohomeClient::GetStubSystemSalt());
- FakeCryptohomeClient::Get()->SetServiceIsAvailable(true);
- base::RunLoop().RunUntilIdle();
-
- // The original token should still be present.
- EXPECT_EQ("test-token", GetRefreshToken());
-
- // Reloading shouldn't change the token either.
- CreateService();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ("test-token", GetRefreshToken());
-}
-
TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_Success) {
SetUpDefaultValues();
std::unique_ptr<OAuth2AccessTokenManager::Request> request =
@@ -280,16 +252,16 @@
}
TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_SuccessAsyncLoad) {
- SetUpWithPendingSalt();
+ CreateService();
+ token_store()->SetRefreshTokenForTesting("device_refresh_token_4_test");
+ SetRobotAccountId("[email protected]");
std::unique_ptr<OAuth2AccessTokenManager::Request> request =
StartTokenRequest();
PerformURLFetches();
AssertConsumerTokensAndErrors(0, 0);
- FakeCryptohomeClient::Get()->set_system_salt(
- FakeCryptohomeClient::GetStubSystemSalt());
- FakeCryptohomeClient::Get()->SetServiceIsAvailable(true);
+ token_store()->TriggerInitCallback(true, true);
base::RunLoop().RunUntilIdle();
PerformURLFetches();
@@ -309,10 +281,11 @@
// Test succeeds if this line is reached without a crash.
}
-TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_NoSalt) {
- FakeCryptohomeClient::Get()->set_system_salt(std::vector<uint8_t>());
- FakeCryptohomeClient::Get()->SetServiceIsAvailable(true);
- SetUpDefaultValues();
+TEST_F(DeviceOAuth2TokenServiceTest, RefreshTokenValidation_InitFailure) {
+ CreateService();
+ token_store()->SetRefreshTokenForTesting("device_refresh_token_4_test");
+ SetRobotAccountId("[email protected]");
+ token_store()->TriggerInitCallback(false, true);
EXPECT_FALSE(RefreshTokenIsAvailable());
@@ -439,30 +412,3 @@
PerformURLFetches();
AssertConsumerTokensAndErrors(1, 1);
}
-
-TEST_F(DeviceOAuth2TokenServiceTest, DoNotAnnounceTokenWithoutAccountID) {
- CreateService();
-
- auto callback_that_should_not_be_called =
- base::BindRepeating([]() { FAIL(); });
- oauth2_service_->SetRefreshTokenAvailableCallback(
- std::move(callback_that_should_not_be_called));
-
- // Make a token available during enrollment. Verify that the token is not
- // announced yet.
- oauth2_service_->SetAndSaveRefreshToken(
- "test-token", DeviceOAuth2TokenService::StatusCallback());
-
- base::RunLoop run_loop;
- auto callback_that_should_be_called_once =
- base::BindRepeating([](base::RunLoop* loop) { loop->Quit(); }, &run_loop);
- oauth2_service_->SetRefreshTokenAvailableCallback(
- std::move(callback_that_should_be_called_once));
-
- // Also make the robot account ID available. Verify that the token is
- // announced now.
- SetRobotAccountId("[email protected]");
- run_loop.Run();
-}
-
-} // namespace chromeos
diff --git a/chrome/browser/device_identity/device_oauth2_token_store.h b/chrome/browser/device_identity/device_oauth2_token_store.h
index 20ea339e..54ee49e 100644
--- a/chrome/browser/device_identity/device_oauth2_token_store.h
+++ b/chrome/browser/device_identity/device_oauth2_token_store.h
@@ -73,6 +73,14 @@
// Invokes |callback| when the operation completes.
virtual void PrepareTrustedAccountId(TrustedAccountIdCallback callback) = 0;
+#if !defined(OS_CHROMEOS)
+ // Requests that this store persist the current service account's associated
+ // email.
+ // On ChromeOS, the account email comes from CrosSettings so this should never
+ // be called.
+ virtual void SetAccountEmail(const std::string& account_email) = 0;
+#endif
+
void SetObserver(Observer* observer) { observer_ = observer; }
Observer* observer() { return observer_; }
diff --git a/chrome/browser/device_identity/device_oauth2_token_store_desktop.cc b/chrome/browser/device_identity/device_oauth2_token_store_desktop.cc
new file mode 100644
index 0000000..471c77c
--- /dev/null
+++ b/chrome/browser/device_identity/device_oauth2_token_store_desktop.cc
@@ -0,0 +1,118 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/device_identity/device_oauth2_token_store_desktop.h"
+
+#include <string>
+
+#include "base/base64.h"
+#include "base/bind.h"
+#include "chrome/common/pref_names.h"
+#include "components/os_crypt/os_crypt.h"
+#include "components/policy/core/common/policy_pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+
+// This pref will hold the base64-encoded representation of the encrypted
+// refresh token for the browser's service account.
+const char kCBCMServiceAccountRefreshToken[] =
+ "cbcm.service_account_refresh_token";
+
+// The account email for the robot account used for policy invalidations on
+// Desktop platforms by Chrome Browser Cloud Management (CBCM). This is similar
+// to kDeviceRobotAnyApiRefreshToken on ChromeOS.
+const char kCBCMServiceAccountEmail[] = "cbcm.service_account_email";
+
+DeviceOAuth2TokenStoreDesktop::DeviceOAuth2TokenStoreDesktop(
+ PrefService* local_state)
+ : local_state_(local_state) {}
+DeviceOAuth2TokenStoreDesktop::~DeviceOAuth2TokenStoreDesktop() = default;
+
+// static
+void DeviceOAuth2TokenStoreDesktop::RegisterPrefs(
+ PrefRegistrySimple* registry) {
+ registry->RegisterStringPref(kCBCMServiceAccountRefreshToken, std::string());
+ registry->RegisterStringPref(kCBCMServiceAccountEmail, std::string());
+}
+
+void DeviceOAuth2TokenStoreDesktop::Init(InitCallback callback) {
+ std::string base64_encrypted_token =
+ local_state_->GetString(kCBCMServiceAccountRefreshToken);
+
+ if (base64_encrypted_token.empty()) {
+ // It's valid for the refresh token to not exist in the store, in
+ // which case init is successful and there shouldn't be a token
+ // validation step.
+ std::move(callback).Run(true, false);
+ return;
+ }
+
+ std::string decoded;
+ if (!base::Base64Decode(base64_encrypted_token, &decoded)) {
+ std::move(callback).Run(false, true);
+ return;
+ }
+
+ std::string decrypted_token;
+ bool success = OSCrypt::DecryptString(decoded, &decrypted_token);
+ if (success) {
+ refresh_token_ = decrypted_token;
+ // 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 (observer() && !GetAccountId().empty())
+ observer()->OnRefreshTokenAvailable();
+ }
+
+ std::move(callback).Run(success, true);
+}
+
+CoreAccountId DeviceOAuth2TokenStoreDesktop::GetAccountId() const {
+ return CoreAccountId::FromEmail(
+ local_state_->GetString(kCBCMServiceAccountEmail));
+}
+
+std::string DeviceOAuth2TokenStoreDesktop::GetRefreshToken() const {
+ return refresh_token_;
+}
+
+void DeviceOAuth2TokenStoreDesktop::SetAndSaveRefreshToken(
+ const std::string& refresh_token,
+ StatusCallback result_callback) {
+ std::string encrypted_token;
+ bool success = OSCrypt::EncryptString(refresh_token, &encrypted_token);
+
+ if (success) {
+ refresh_token_ = refresh_token;
+
+ // The string must be encoded as base64 for storage in local state.
+ std::string encoded;
+ base::Base64Encode(encrypted_token, &encoded);
+
+ local_state_->SetString(kCBCMServiceAccountRefreshToken, encoded);
+ }
+
+ std::move(result_callback).Run(success);
+}
+
+void DeviceOAuth2TokenStoreDesktop::PrepareTrustedAccountId(
+ TrustedAccountIdCallback callback) {
+ // There's no cryptohome or anything similar to initialize on non-chromeos
+ // platforms, so just run the callback as a success now.
+ callback.Run(true);
+}
+
+void DeviceOAuth2TokenStoreDesktop::SetAccountEmail(
+ const std::string& account_email) {
+ if (GetAccountId() == CoreAccountId::FromEmail(account_email))
+ return;
+
+ local_state_->SetString(kCBCMServiceAccountEmail, account_email);
+ OnServiceAccountIdentityChanged();
+}
+
+void DeviceOAuth2TokenStoreDesktop::OnServiceAccountIdentityChanged() {
+ if (observer() && !GetAccountId().empty() && !refresh_token_.empty())
+ observer()->OnRefreshTokenAvailable();
+}
diff --git a/chrome/browser/device_identity/device_oauth2_token_store_desktop.h b/chrome/browser/device_identity/device_oauth2_token_store_desktop.h
new file mode 100644
index 0000000..835a3dff
--- /dev/null
+++ b/chrome/browser/device_identity/device_oauth2_token_store_desktop.h
@@ -0,0 +1,56 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_DEVICE_IDENTITY_DEVICE_OAUTH2_TOKEN_STORE_DESKTOP_H_
+#define CHROME_BROWSER_DEVICE_IDENTITY_DEVICE_OAUTH2_TOKEN_STORE_DESKTOP_H_
+
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/device_identity/device_oauth2_token_store.h"
+#include "google_apis/gaia/core_account_id.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+// The pref name where this class stores the encrypted refresh token.
+extern const char kCBCMServiceAccountRefreshToken[];
+
+// The pref name where this class stores the service account's email.
+extern const char kCBCMServiceAccountEmail[];
+
+// The desktop (mac, win, linux) implementation of DeviceOAuth2TokenStore. This
+// is used by the DeviceOAuth2TokenService on those platforms to encrypt and
+// persist the refresh token of the service account to LocalState.
+class DeviceOAuth2TokenStoreDesktop : public DeviceOAuth2TokenStore {
+ public:
+ explicit DeviceOAuth2TokenStoreDesktop(PrefService* local_state);
+ ~DeviceOAuth2TokenStoreDesktop() override;
+
+ DeviceOAuth2TokenStoreDesktop(const DeviceOAuth2TokenStoreDesktop& other) =
+ delete;
+ DeviceOAuth2TokenStoreDesktop& operator=(
+ const DeviceOAuth2TokenStoreDesktop& other) = delete;
+
+ static void RegisterPrefs(PrefRegistrySimple* registry);
+
+ // DeviceOAuth2TokenStore:
+ void Init(InitCallback callback) override;
+ CoreAccountId GetAccountId() const override;
+ std::string GetRefreshToken() const override;
+ void SetAndSaveRefreshToken(const std::string& refresh_token,
+ StatusCallback result_callback) override;
+ void PrepareTrustedAccountId(TrustedAccountIdCallback callback) override;
+ void SetAccountEmail(const std::string& account_email) override;
+
+ private:
+ void OnServiceAccountIdentityChanged();
+
+ PrefService* const local_state_;
+ std::string refresh_token_;
+
+ base::WeakPtrFactory<DeviceOAuth2TokenStoreDesktop> weak_ptr_factory_{this};
+};
+
+#endif // CHROME_BROWSER_DEVICE_IDENTITY_DEVICE_OAUTH2_TOKEN_STORE_DESKTOP_H_
diff --git a/chrome/browser/device_identity/device_oauth2_token_store_desktop_unittest.cc b/chrome/browser/device_identity/device_oauth2_token_store_desktop_unittest.cc
new file mode 100644
index 0000000..a4643a9
--- /dev/null
+++ b/chrome/browser/device_identity/device_oauth2_token_store_desktop_unittest.cc
@@ -0,0 +1,158 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/device_identity/device_oauth2_token_store_desktop.h"
+
+#include "base/base64.h"
+#include "base/test/bind_test_util.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/scoped_testing_local_state.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "components/os_crypt/os_crypt.h"
+#include "components/os_crypt/os_crypt_mocker.h"
+#include "components/policy/core/common/policy_pref_names.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+class TestObserver : public DeviceOAuth2TokenStore::Observer {
+ public:
+ int called_count() const { return called_count_; }
+
+ private:
+ void OnRefreshTokenAvailable() override { ++called_count_; }
+
+ int called_count_ = 0;
+};
+} // namespace
+
+class DeviceOAuth2TokenStoreDesktopTest : public testing::Test {
+ public:
+ DeviceOAuth2TokenStoreDesktopTest()
+ : scoped_testing_local_state_(TestingBrowserProcess::GetGlobal()) {}
+ ~DeviceOAuth2TokenStoreDesktopTest() override = default;
+
+ ScopedTestingLocalState* scoped_testing_local_state() {
+ return &scoped_testing_local_state_;
+ }
+
+ void SetUp() override {
+ testing::Test::SetUp();
+ OSCryptMocker::SetUp();
+ }
+
+ void TearDown() override {
+ OSCryptMocker::TearDown();
+ testing::Test::TearDown();
+ }
+
+ private:
+ ScopedTestingLocalState scoped_testing_local_state_;
+};
+
+TEST_F(DeviceOAuth2TokenStoreDesktopTest, InitWithoutSavedToken) {
+ DeviceOAuth2TokenStoreDesktop store(scoped_testing_local_state()->Get());
+
+ EXPECT_TRUE(store.GetAccountId().empty());
+ EXPECT_TRUE(store.GetRefreshToken().empty());
+
+ store.Init(base::BindOnce([](bool, bool) {}));
+
+ TestObserver observer;
+ store.SetObserver(&observer);
+
+ // Observer shouldn't have been called because there's no account ID available
+ // yet.
+ EXPECT_EQ(0, observer.called_count());
+ EXPECT_TRUE(store.GetAccountId().empty());
+ EXPECT_TRUE(store.GetRefreshToken().empty());
+}
+
+TEST_F(DeviceOAuth2TokenStoreDesktopTest, InitWithSavedToken) {
+ scoped_testing_local_state()->Get()->SetString(kCBCMServiceAccountEmail,
+ "[email protected]");
+
+ std::string token = "test_token";
+ std::string encrypted_token;
+ OSCrypt::EncryptString(token, &encrypted_token);
+
+ std::string encoded;
+ base::Base64Encode(encrypted_token, &encoded);
+
+ scoped_testing_local_state()->Get()->SetString(
+ kCBCMServiceAccountRefreshToken, encoded);
+
+ DeviceOAuth2TokenStoreDesktop store(scoped_testing_local_state()->Get());
+
+ EXPECT_TRUE(store.GetRefreshToken().empty());
+
+ TestObserver observer;
+ store.SetObserver(&observer);
+
+ store.Init(base::BindOnce([](bool, bool) {}));
+
+ EXPECT_EQ(1, observer.called_count());
+ EXPECT_EQ(store.GetAccountId(), CoreAccountId::FromEmail("[email protected]"));
+ EXPECT_EQ(store.GetRefreshToken(), token);
+}
+
+TEST_F(DeviceOAuth2TokenStoreDesktopTest, ObserverNotifiedWhenAccountChanges) {
+ scoped_testing_local_state()->Get()->SetString(kCBCMServiceAccountEmail,
+ "[email protected]");
+
+ std::string token = "test_token";
+ std::string encrypted_token;
+ OSCrypt::EncryptString(token, &encrypted_token);
+
+ std::string encoded;
+ base::Base64Encode(encrypted_token, &encoded);
+
+ scoped_testing_local_state()->Get()->SetString(
+ kCBCMServiceAccountRefreshToken, encoded);
+
+ DeviceOAuth2TokenStoreDesktop store(scoped_testing_local_state()->Get());
+
+ TestObserver test_observer;
+ store.SetObserver(&test_observer);
+
+ EXPECT_TRUE(store.GetRefreshToken().empty());
+
+ store.Init(base::BindOnce([](bool, bool) {}));
+
+ EXPECT_EQ(1, test_observer.called_count());
+
+ EXPECT_EQ(store.GetAccountId(), CoreAccountId::FromEmail("[email protected]"));
+ EXPECT_EQ(store.GetRefreshToken(), token);
+
+ store.SetAccountEmail("[email protected]");
+
+ EXPECT_EQ(2, test_observer.called_count());
+}
+
+TEST_F(DeviceOAuth2TokenStoreDesktopTest, SaveToken) {
+ std::string token = "test_token";
+
+ DeviceOAuth2TokenStoreDesktop store(scoped_testing_local_state()->Get());
+ store.Init(base::BindOnce([](bool, bool) {}));
+
+ EXPECT_TRUE(store.GetRefreshToken().empty());
+
+ bool callback_success = false;
+ store.SetAndSaveRefreshToken(
+ token, base::BindLambdaForTesting([&callback_success](bool success) {
+ callback_success = success;
+ }));
+
+ EXPECT_TRUE(callback_success);
+
+ std::string persisted_token = scoped_testing_local_state()->Get()->GetString(
+ kCBCMServiceAccountRefreshToken);
+
+ std::string decoded;
+ base::Base64Decode(persisted_token, &decoded);
+ std::string decrypted;
+ OSCrypt::DecryptString(decoded, &decrypted);
+
+ EXPECT_EQ(token, store.GetRefreshToken());
+ EXPECT_EQ(token, decrypted);
+}
diff --git a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
index d93c41b..4aa815f 100644
--- a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
+++ b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
@@ -100,9 +100,8 @@
std::unique_ptr<api::identity::GetAuthToken::Params> params(
api::identity::GetAuthToken::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
- interactive_ = params->details.get() &&
- params->details->interactive.get() &&
- *params->details->interactive;
+ interactive_ = params->details.get() && params->details->interactive.get() &&
+ *params->details->interactive;
should_prompt_for_scopes_ = interactive_;
should_prompt_for_signin_ =
@@ -414,8 +413,7 @@
const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension());
IdentityAPI* id_api = IdentityAPI::GetFactoryInstance()->Get(GetProfile());
IdentityTokenCacheValue cache_entry = id_api->GetCachedToken(token_key_);
- IdentityTokenCacheValue::CacheValueStatus cache_status =
- cache_entry.status();
+ IdentityTokenCacheValue::CacheValueStatus cache_status = cache_entry.status();
if (type == IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE) {
switch (cache_status) {
@@ -545,8 +543,8 @@
break;
}
- CompleteFunctionWithError(
- std::string(identity_constants::kAuthFailure) + error.ToString());
+ CompleteFunctionWithError(std::string(identity_constants::kAuthFailure) +
+ error.ToString());
}
void IdentityGetAuthTokenFunction::OnIssueAdviceSuccess(
@@ -659,7 +657,7 @@
}
}
error = std::string(identity_constants::kAuthFailure) +
- service_error.ToString();
+ service_error.ToString();
break;
case GaiaWebAuthFlow::OAUTH_ERROR:
@@ -824,9 +822,12 @@
}
#if defined(OS_CHROMEOS)
+// Even though the DeviceOAuth2TokenService may be available on non-ChromeOS
+// platforms, its robot account is not made available because it should only be
+// used for very specific policy-related things. In fact, the device account on
+// desktop isn't scoped for anything other than policy invalidations.
void IdentityGetAuthTokenFunction::StartDeviceAccessTokenRequest() {
- chromeos::DeviceOAuth2TokenService* service =
- chromeos::DeviceOAuth2TokenServiceFactory::Get();
+ DeviceOAuth2TokenService* service = DeviceOAuth2TokenServiceFactory::Get();
// Since robot account refresh tokens are scoped down to [any-api] only,
// request access token for [any-api] instead of login.
OAuth2AccessTokenManager::ScopeSet scopes;
@@ -856,9 +857,9 @@
if (chrome::IsRunningInForcedAppMode()) {
std::string app_client_id;
std::string app_client_secret;
- if (chromeos::UserSessionManager::GetInstance()->
- GetAppModeChromeClientOAuthInfo(&app_client_id,
- &app_client_secret)) {
+ if (chromeos::UserSessionManager::GetInstance()
+ ->GetAppModeChromeClientOAuthInfo(&app_client_id,
+ &app_client_secret)) {
token_key_account_access_token_fetcher_ =
identity_manager->CreateAccessTokenFetcherForClient(
token_key_.account_id, app_client_id, app_client_secret,
diff --git a/chrome/browser/invalidation/profile_invalidation_provider_factory.cc b/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
index be1fd42..d4d8440 100644
--- a/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
+++ b/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
@@ -125,8 +125,8 @@
if (user_manager::UserManager::IsInitialized() &&
user_manager::UserManager::Get()->IsLoggedInAsKioskApp() &&
connector->IsEnterpriseManaged()) {
- identity_provider.reset(new chromeos::DeviceIdentityProvider(
- chromeos::DeviceOAuth2TokenServiceFactory::Get()));
+ identity_provider = std::make_unique<DeviceIdentityProvider>(
+ DeviceOAuth2TokenServiceFactory::Get());
}
#endif // defined(OS_CHROMEOS)
diff --git a/chrome/browser/policy/chrome_browser_cloud_management_controller.cc b/chrome/browser/policy/chrome_browser_cloud_management_controller.cc
index 8bebe43..b5e25fd 100644
--- a/chrome/browser/policy/chrome_browser_cloud_management_controller.cc
+++ b/chrome/browser/policy/chrome_browser_cloud_management_controller.cc
@@ -18,6 +18,8 @@
#include "build/branding_buildflags.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/device_identity/device_oauth2_token_service.h"
+#include "chrome/browser/device_identity/device_oauth2_token_service_factory.h"
#include "chrome/browser/enterprise_reporting/report_generator.h"
#include "chrome/browser/enterprise_reporting/report_scheduler.h"
#include "chrome/browser/lifetime/application_lifetime.h"
@@ -342,6 +344,12 @@
UnenrollBrowser();
}
+void ChromeBrowserCloudManagementController::OnServiceAccountChanged(
+ CloudPolicyClient* client) {
+ DeviceOAuth2TokenServiceFactory::Get()->SetServiceAccountEmail(
+ client->service_account_email());
+}
+
void ChromeBrowserCloudManagementController::ShutDown() {
if (report_scheduler_)
report_scheduler_.reset();
diff --git a/chrome/browser/policy/chrome_browser_cloud_management_controller.h b/chrome/browser/policy/chrome_browser_cloud_management_controller.h
index eb73a9b..556264c 100644
--- a/chrome/browser/policy/chrome_browser_cloud_management_controller.h
+++ b/chrome/browser/policy/chrome_browser_cloud_management_controller.h
@@ -102,6 +102,7 @@
void OnPolicyFetched(CloudPolicyClient* client) override;
void OnRegistrationStateChanged(CloudPolicyClient* client) override;
void OnClientError(CloudPolicyClient* client) override;
+ void OnServiceAccountChanged(CloudPolicyClient* client) override;
// Early cleanup during browser shutdown process
void ShutDown();
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 1d661bc..39e4dbc 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -315,7 +315,7 @@
#include "chrome/browser/chromeos/settings/device_settings_cache.h"
#include "chrome/browser/chromeos/system/automatic_reboot_manager.h"
#include "chrome/browser/chromeos/system/input_device_settings.h"
-#include "chrome/browser/device_identity/device_oauth2_token_service.h"
+#include "chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.h"
#include "chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h"
#include "chrome/browser/extensions/extension_assets_manager_chromeos.h"
#include "chrome/browser/media/protected_media_identifier_permission_context.h"
@@ -377,8 +377,10 @@
#endif
#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+#include "chrome/browser/device_identity//device_oauth2_token_store_desktop.h"
#include "chrome/browser/downgrade/downgrade_prefs.h"
#include "chrome/browser/ui/startup/default_browser_prompt.h"
+
#endif
#if defined(TOOLKIT_VIEWS)
@@ -719,7 +721,7 @@
chromeos::DemoModeResourcesRemover::RegisterLocalStatePrefs(registry);
chromeos::DemoSession::RegisterLocalStatePrefs(registry);
chromeos::DemoSetupController::RegisterLocalStatePrefs(registry);
- chromeos::DeviceOAuth2TokenService::RegisterPrefs(registry);
+ chromeos::DeviceOAuth2TokenStoreChromeOS::RegisterPrefs(registry);
chromeos::device_settings_cache::RegisterPrefs(registry);
chromeos::EasyUnlockService::RegisterPrefs(registry);
chromeos::echo_offer::RegisterPrefs(registry);
@@ -806,6 +808,7 @@
#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
RegisterDefaultBrowserPromptPrefs(registry);
downgrade::RegisterPrefs(registry);
+ DeviceOAuth2TokenStoreDesktop::RegisterPrefs(registry);
#endif
// Obsolete. See MigrateObsoleteBrowserPrefs().
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index c0823ff..113d342 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -490,8 +490,8 @@
const signin::ScopeSet scopes{cloud_devices::kCloudPrintAuthScope};
DCHECK(!device_request_callback_);
- chromeos::DeviceOAuth2TokenService* token_service =
- chromeos::DeviceOAuth2TokenServiceFactory::Get();
+ DeviceOAuth2TokenService* token_service =
+ DeviceOAuth2TokenServiceFactory::Get();
device_request_ = token_service->StartAccessTokenRequest(scopes, this);
device_request_callback_ = std::move(callback);
}